i want to cast List<HashMap<String, Object>> into Set<StudentInfo>
i have method
public List<HashMap<String,Object>> getStudentData(studentId);
i want to convert the result into Set so i used
Set<StudentInfo> studentFilteredInfo = new HashSet<>();
List<Map<String, Object>> studentCompleteRecord = getStudentData(1005);
studentFilteredInfo.addAll((Collection<? extends StudentInfo>studentCompleteRecord ));
initially when i executed on localhost it with java 8, eclipse and tomcat 8 it is working fine.
when i tried to build it with maven
mvn clean package
it will through an Error:
incompatible types: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
cannot be converted to java.util.Collection<? extends com.school.model.StudentInfo>
You are mistaken: there is no casting from List<Map<String, Object>> into some Set<Whatever>!
Casting basically means: you know that some "Object" has a more specific type; thus you tell the compiler: "you can safely assume that this thingy here is something else in reality".
But that means: in reality (at runtime), that "thingy" really is "something else"! And alone the generic types that you provide in your question make it very clear: you can't be doing a cast here!
In other words: you have to write code that iterates your List of Maps; to extract that information that is required to create new StudentInfo objects. Then you collect those newly created objects; and put them into a new Set; which you then can return from your method!
And finally: always avoid "concrete" implementation types; you used List<HashMap<... - instead, you should go for List<Map<... !
You need to write code to explicitly convert a Map<String,Object> to a StudentInfo instance. Suppose StudentInfo has a method like this:
static StudentInfo create(Map<String, Object> info) {
String name = info.get("name");
Transcript transcript = info.get("grades");
return new StudentInfo(name, transcript);
}
Then you would need to iterate over each element in the list and use your method to convert the Map instances to StudentInfo objects.
With lambdas:
Set<StudentInfo> studentFilteredInfo = studentCompleteRecord.stream()
.map(StudentInfo::create)
.collect(Collectors.toSet());
Without lambdas:
Set<StudentInfo> studentFilteredInfo = new HashSet<>();
for (Map<String,Object> e : studentCompleteRecord)
studentFilteredInfo.add(StudentInfo.create(e);
Related
Java 11 here. I have the following POJO:
#Data // Lombok; adds getters, setters, all-args constructor and equals and hashCode
public class Fliflam {
private String merf;
private String tarf;
private Boolean isFlerf;
}
I have a method that validates a Flimflam and returns a List<String> of any errors encountered while validating the Flimflam. I can change this to return Optional<List<String>> if anyone thinks thats helpful for some reason, especially when dealing with the Stream API:
public List<String> validateFlimflam(Flimflam flimflam) {
List<String> errors = new ArrayList<>();
// ... validation code omitted for brevity
// 'errors' list is populated with any errors; otherwise it returns empty
return errors;
}
I want to stream (Stream API) through a List<Flimflam> and populate a Map<Flimflam,List<String>> errors map, where the key of the map is a Flimflam that failed validation, and its corresponding value is the list of validation error strings.
I can achieve this the "old fashioned" way like so:
List<Flimflam> flimflams = getSomehow();
Map<Flimflam,List<String>> errorsMap = new HashMap<>();
for (Flimflam ff : flimflams) {
List<String> errors = validateFlimflam(ff);
if (!errors.isEmpty() {
errorsMap.put(ff, errors);
}
}
How can I accomplish this via the Stream API?
Like this
Map<Flimflam,List<String>> errorsMap = flimflams.stream().collect(Collectors.toMap(f -> f, f-> f::validateFlimflam));
toMap takes 2 parameters (keyMapper,valueMapper)
In your case key mapper is object from stream itself, and value is calling validateFlimflam on that object
It is hard to tell where exactly your validateFlimflam method is defined. I suspect it is not in the Flimflam class itself since there would be no need to pass an instance of itself to the method. So I presume it is an external method to that class. Assuming that I would proceed as follows:
thisClass = instance containing validateFlimflam. Could be set to this
Map<Flimflam, List<String>> errorsMap =
flimflams.stream().collect(Collectors.toMap(f -> f,
thisClass::validateFlimflam));
If by chance, Flimflam does contain validateFlimflam you could do it like this. Note that this presumes the method takes no arguments as they wouldn't be necessary
Map<Flimflam, List<String>> errorsMap =
flimflams.stream().collect(Collectors.toMap(f -> f,
Flimflam::validateFlimflam));
Finally, if the containing class is some other class and the validateFlimflam method is declared static, then you could do it like this by using the containing class name, not instance. Also, in this case, the method would take an argument as defined.
Map<Flimflam, List<String>> errorsMap =
flimflams.stream().collect(Collectors.toMap(f -> f,
SomeClass::validateFlimflam));
A a = new A(); //classA { }
HashMap<String, Object> hm = new Hashmap<String,Object>();
hm.put("A", a);
My question is, How can i put the Object itself instead of "A" in same declaration?
hm.put(`a??`, a);
You simply cannot do that, the language prohibits it. It would only be possible if your class A is a subclass of String which is not possible, since String is declared as final in Java.
With respect to you interview question: It's not possible due to the generic type parameter that was chosen for the declaration. You can read more about that in Bounded Type Parameters.
A a = new A(); //classA { }
Map<A, A> hm = new Hashmap<A, A>();
hm.put(a, a);
But I do not see any point of putting a->a
If the class held a non-changing decent String field, you could use that.
// the id property must be a String, immutable and unique for each instance!
myMap.put(a.getId(), a);
If you want to make any object as a key in your HashMap, then that object has to be immutable.. Because, you don't want anyone to change your key, after you add them to your HashMap..
Just imagine, if your keys are changed after insertion, you won't ever be able to find your inserted value..
But if your key is immutable, then if anyone tries to change your keys, he will actually create a new one for himself, but you will still have yours..
That is what happens in case you use String as your key in HashMap(They can't be changed).. So, if you want your object to be a key, either you make your class a subclass of String (that you can't do), or, just make your class immutable..
This is actually possible using a raw type, like this:
Object key = ...;
Object value = ...;
Map<String, Integer> map = new HashMap<>();//a normal map
Map rawMap = map; // here is the raw type
rawMap.put(key, value); // it works!
This runs fine, but problems arise when you try to use the generic map later:
Integer value = map.get(key);// ClassCastException (unless value actually is an Integer)
That's why you were told that it's a "dirty trick". You shouldn't use it.
I am using a class where I am taking input as the file name and the file location. I have a pre defined file names, so I will match the predefined file names with the file name that I received and then store the values accordingly. Please look at the code below
//Set of storage maps and tables
public class storage
{
//Storage set
public static Set<Integer> tiger = new HashSet<Integer>();
//Storage set
public static Set<Integer> lion = new HashSet<Integer>();
//This is the table used for storing the browser customer count
public static Table<String,String,Integer> elephant = HashBasedTable.create();
//Storage map
public static Map<String, String> monkey = new HashMap<String, String>();
public static void storeDataDirector(String fileLocation,String fileName) throws Exception
{
if (fileName = monkey)
**update the "monkey map"**
}
This is my problem, also I have lot of maps and tables to be used so I wouldn't be able to use multiple if conditions and then check and update the same.
What I would like to know is the below
As I have said earlier, The file name that I am sending to the program which is "String filename" has the same name of the "Map monkey" but the former is a String and the latter is the map. I would like to know if I will be able to use the string variable as a reference to the map instance as both of them have the same name . This will highly avoid the if conditions that I am using in the program and thus I would like to possible solution for this ... Anything related to type caseting ort
You need to have another Map - whose key is a String and value is a Map. Something like Map<String,Map> allMaps = new HashMap<String,Map>()
Once you have this map , populate it with all your filenames and the corresponding maps monkey.
allMaps .put("monkey", monkey)
If a string filename corresponds to not a map but to a set , then you need to declare something more general Map<String,Object> allMaps = new HashMap<String,Object>(). Ofcourse this means you need to cast the value to its particular type before you can do any meaningful thing with it.
Then , to use this map , use your filename argument
Map monkeyAgain = allMaps.get(filename)
You can use reflection:
Storage.class.getField(fileName).get(null)
You will still have to cast the returned object. I do not think this the right approach.
The idea is to relate them in a Map, and use the file name as a key for example
Map<String, Map<String, String>>
// file store structure
If you need a generic solution, you could solve this by implementing an abstraction of your store structure, by implementing an interface similar to this one:
// T is the store type and U is the original type (String from file for instance...)
public interface StoreUnit<T, U> {
void update(U record);
List<T> list();
}
so you will have an implementation for each case (Set, Map, Table ...) and will relate it in a map using the file name as key.
monkeyFileName => MapStoreUnit<Entry<String,String>,String>
tigerFileName => SetStoreUnit<Integer, String>
elephantFileName => TableStoreUnit<Entry<Entry<String,String>,String>,String> // not sure if for Table there is something better than Entry ;)
When you wanna update some store you perform a get over the map using the file name as key, and invoking update method implemented with the record (that could be an String, complex Object) and so on. When you need to read something from there you could use the list method.
I'm tring to create an arraylist of different class instances. How can I create a list without defining a class type? (<Employee>)
List<Employee> employees = new ArrayList<Employee>();
employees.add(new Employee());
Employee employee = employees.get(0);
You could create a list of Object like List<Object> list = new ArrayList<Object>(). As all classes implementation extends implicit or explicit from java.lang.Object class, this list can hold any object, including instances of Employee, Integer, String etc.
When you retrieve an element from this list, you will be retrieving an Object and no longer an Employee, meaning you need to perform a explicit cast in this case as follows:
List<Object> list = new ArrayList<Object>();
list.add("String");
list.add(Integer.valueOf(1));
list.add(new Employee());
Object retrievedObject = list.get(2);
Employee employee = (Employee)list.get(2); // explicit cast
List<Object> objects = new ArrayList<Object>();
objects list will accept any of the Object
You could design like as follows
public class BaseEmployee{/* stuffs */}
public class RegularEmployee extends BaseEmployee{/* stuffs */}
public class Contractors extends BaseEmployee{/* stuffs */}
and in list
List<? extends BaseEmployee> employeeList = new ArrayList<? extends BaseEmployee>();
List anyObject = new ArrayList();
or
List<Object> anyObject = new ArrayList<Object>();
now anyObject can hold objects of any type.
use instanceof to know what kind of object it is.
I believe your best shot is to declare the list as a list of objects:
List<Object> anything = new ArrayList<Object>();
Then you can put whatever you want in it, like:
anything.add(new Employee(..))
Evidently, you will not be able to read anything out of the list without a proper casting:
Employee mike = (Employee) anything.get(0);
I would discourage the use of raw types like:
List anything = new ArrayList()
Since the whole purpose of generics is precisely to avoid them, in the future Java may no longer suport raw types, the raw types are considered legacy and once you use a raw type you are not allowed to use generics at all in a given reference. For instance, take a look a this another question: Combining Raw Types and Generic Methods
How can I create a list without defining a class type? (<Employee>)
If I'm reading this correctly, you just want to avoid having to specify the type, correct?
In Java 7, you can do
List<Employee> list = new ArrayList<>();
but any of the other alternatives being discussed are just going to sacrifice type safety.
If you can't be more specific than Object with your instances, then use:
List<Object> employees = new ArrayList<Object>();
Otherwise be as specific as you can:
List<? extends SpecificType> employees = new ArrayList<? extends SpecificType>();
I see that all of the answers suggest using a list filled with Object classes and then explicitly casting the desired class, and I personally don't like that kind of approach.
What works better for me is to create an interface which contains methods for retrieving or storing data from/to certain classes I want to put in a list. Have those classes implement that new interface, add the methods from the interface into them and then you can fill the list with interface objects - List<NewInterface> newInterfaceList = new ArrayList<>() thus being able to extract the desired data from the objects in a list without having the need to explicitly cast anything.
You can also put a comparator in the interface if you need to sort the list.
I know this is an old question, but there's a nice and easy way to do this (it works with the mostly recent versions of ElasticSearch Rest API).
The search object goes like:
SearchResponse<JsonData> search = client.search(s -> s
.index(index)
.query(query),
JsonData.class);
And then I iterate over the response like this:
for (Hit<JsonData> hit: search.hits().hits()) {
String stringSource = hit.source().toString();
MySavedRegister mySavedRegister = mapper.readValue(stringSource, mySavedRegister .class);
mylist.add(esGenericEvent);
}
Where mySavedRegister stands for the class that has the hits' sources parameters.
I have the following code using generics:
Set membersKeySet = membersList.keySet();
Iterator<DoubleKey> membersItr = membersKeySet.iterator();
while(membersItr.hasNext()){
DoubleKey<Integer, Integer> dk = membersItr.next();
}
Eclipse tells me that "Set is a raw type. References to generic type <E> should be parametrized". DoubleKey is also a Generic class. What I understand is that the .iterator() method doesn't assure that the DoubleKey Class has been passed with the same parameter types. I tried typecasting but it doesn't work. How can I pull this off? Thanks!
P.S. I'm still n00b inusing Generics.
If the objects stored in the set are instances of DoubleKey<Integer, Integer>, then the code should look like this :
Set<DoubleKey<Integer, Integer>> membersKeySet = membersList.keySet();
Iterator<DoubleKey<Integer, Integer>> membersItr = membersKeySet.iterator();
while(membersItr.hasNext()){
DoubleKey<Integer, Integer> dk = membersItr.next();
}
You should define type of the keyset.
Set<DoubleKey> membersKeySet = membersList.keySet();
Could you please provide memberList definition to provide the full picture?
Well depending on what membersList is, I'd expect this to be the solution:
Set<DoubleKey> membersKeySet = membersList.keySet();
If membersList is also declared using a raw type, it becomes trickier... but we'll cross that bridge when you've checked whether that's all you need :)
From the code you give, it looks like membersList is actually a map of some sort. So, in order to get the compile time type safety of generics, membersList should be defined appropriately, something like
Map<DoubleKey, Object> membersList = new HashMap<DoubleKey, Object>();
Set<DoubleKey> membersKeySet = membersList.keySet();
With that, your iterator should work as you have it.
Normally you'd use the compact for-loop notation:
while(DoubleKey<Integer, Integer> dk: membersList.keySet()) {
}
And if you are using DoubleKey<Integer, Integer> all over the place, consider making it a class all on its own:
class IIKey extends DoubleKey<Integer, Integer> {}