I want to define generic static method in my one of project.
Requirement is to method return type to be one of method parameter.
The below is my solution.
public static <T> List<T> convertMapToAttribute(Class<T> attrClass, T attr) {
List<T> list = null;
if (attrClass.equals(String.class)) {
list = (List<T>) new ArrayList<String>();
list.add(attr);
} else if (attrClass.equals(Integer.class)) {
list = (List<T>)new ArrayList<Integer>();
list.add(attr);
}
return list;
}
I have two questions.
Can we avoid this waring "warning: [unchecked] unchecked cast"
without adding #SuppressWarnings("unchecked")?
Is there any other elegant way to solve this above problem
The following should work fine:
List<T> list = new ArrayList<T>();
List<T> list = new ArrayList<>(); // Java 7
Couldn't you just do something like...
public static <T> List<T> convertMapToAttribute(Class<T> attrClass, T attr) {
List<T> list = new ArrayList<T>(1);
list.add(attr);
return list;
}
instead?
UPDATE based on feedback
public static <T> List<T> convertMapToAttribute(T attr) {
List<T> list = new ArrayList<T>(1);
list.add(attr);
return list;
}
By having Class<T> as a parameter, the way to do a checked cast (and skip the annoying warning) is to invoke attrClass.cast() which will throw ClassCastException if the casting fails. In this case, T should be either String or Integer.
The problem here is that you're doing an unchecked cast from a list of T to a list of either String or Integer when you should define the list directly and add the element using a cast:
if (attrClass.equals(String.class)) {
List<String> list = new ArrayList<String>();
list.add(attrClass.cast(attr));
}
And the same goes for Integer.
There's something weird with your method tough (I don't understand the intention, actually), you're creating a list of elements from a type that you're also passing a parameter... Shouldn't this work as well? (since you create a list of T types and add an element of T type).
public static <T> List<T> convertMapToAttribute(T attr) {
List<T> list = new ArrayList<T>();
list.add(attr);
return list;
}
Not to my knowledge
Skip the attrClass parameter, since it actually makes the method non-generic.
Related
I am trying to create a method which accepts a class as parameter and do some operation and return a list of same class.
I am trying to use Generics and have the below code.
Question:
What should I do to map the provided class to the BeanListProcessor type and List ?
NOTE: This code is not correct and will produce syntax errors. This is a kind of template to explain my requirement.
public static List<?> process(Class<?> bean) {
List<?> rows = new ArrayList<>();
BeanListProcessor<bean> processor = new BeanListProcessor<bean>(bean.getClass());
....
return rows;
}
You may want to define a generic type at method level - if you want to return instances of the type provided as argument in the returned list.
public static <T> List<T> process(Class<T> beanClass) {
List<T> rows = new ArrayList<>();
BeanListProcessor<T> processor = new BeanListProcessor<T>(beanClass);
...
return rows;
}
May be many of you have several times wanted to do this. Right now I am trying to do it but stuck.
Say, I have a method like this:
private Object getList(String nameofType) {
return new ArrayList<Type>();
/**e.g. It returns ArrayList<java.lang.Double> if nameofType is "java.lang.Double",
/*ArrayList<java.io.File> if nameofType is "java.io.File"**/
}
How can I init an ArrayList like this?
(This doesn't really answer the question; it is just pointing out that a Class<T> parameter is unnecessary simply to create a generic list, as suggested in other answers)
Guava's Lists.newArrayList method looks something like this:
public static <T> ArrayList<T> newArrayList() {
return new ArrayList<>();
}
No type parameter is needed.
List<String> stringList = Lists.newArrayList();
List<Integer> integerList = Lists.newArrayList();
If you need to invoke for a specific type, you can invoke like:
Lists.<MySpecificType>newArrayList();
The closest thing to what you want to do, might be this:
private List getList(String nameofType) {
List list = null;
try {
Class clazz = Class.forName(nameofType); //must be fully qualified, example: "java.lang.Integer"
list = Collections.checkedList(new ArrayList(), clazz);
} catch (ClassNotFoundException e) {
// log exception, etc.
}
return list;
}
This will return an effectively type-checked list, that will throw an exception if you try to insert an object of different type than specified.
You can check it four yourself:
List list = getList("java.lang.Integer");
System.out.println("Inserting Integer");
list.add(new Integer(1));
System.out.println("List: "+ list);
System.out.println("Inserting Long");
list.add(new Long(1));
System.out.println("List: "+ list);
Output:
Inserting Integer
List: [1]
Inserting Long
Exception in thread "main" java.lang.ClassCastException: Attempt to insert class java.lang.Long element into collection with element type class java.lang.Integer
Do you have to use a String-Parameter?
If not, you can use Generics:
private <T> Object getList(Class<T> listType) {
return new ArrayList<T>();
}
Not sure what you are trying to accomplish, but this code satisfies your needs i believe
public <T> List<T> getList(Class<T> clazz) {
return new ArrayList<T>();
}
It returns a properly List<T> based on the class you pass to its parameter.
Using a string as a parameter does not really help the compiler. Keep in mind that the type information for parameterised types (using generics) are erased at run-time (https://docs.oracle.com/javase/tutorial/java/generics/erasure.html).
public static <T> List<T> arrayListReverse(List<T> lst) {
ArrayList reversed= new ArrayList();
for (int i=lst.size()-1;i>=0;i--){
<T> t= lst.get(i);
reversed.add(t);
}
return reversed;
}
I want to be be able to return a list that is a reversed version of the original list. It should be able to work for any type. I keep getting errors when it comes to the t=input.get(i);
Edit: I would like to only use the List interface
public static <T> List<T> arrayListReverse(List<T> lst) {
Collections.reverse(lst);
return lst;
}
<T> should be T:
public static <T> List<T> arrayListReverse(List<T> lst) {
ArrayList reversed= new ArrayList();
for (int i=lst.size()-1;i>=0;i--){
T t = lst.get(i);
reversed.add(t);
}
return reversed;
}
In your code <T> t = should just be T t =, but you could also use a for-each loop and add to the front of your reversed as you iterate forward. And, you shouldn't use raw types (you didn't specify a generic for reversed) and you could use the diamond operator <>. And you could initialize your output list with the same initial size as your input. Something like
public static <T> List<T> arrayListReverse(final List<T> lst) {
List<T> reversed = new ArrayList<>(lst.size());
for (T t : lst) {
reversed.add(0, t);
}
return reversed;
}
You can also use this:
ArrayList reversed = new ArrayList();
reversed=Collections.reverse(startArray);
Documentation:
public static void reverse(List list)
Reverses the order of the elements in the specified list.
This method runs in linear time.
Parameters:
list - the list whose elements are to be reversed.
Throws:
UnsupportedOperationException - if the specified list or its list-iterator does not support the set operation.
If you really want the method to return the same type of list, as is given as parameter, use the following:
public static <T,L extends List<T>> L reverse(L list){
Collections.reverse(list);
return list;
}
This will return a Vector<String>, if you pass a Vector of Strings.
It will return an ArrayList<Something>, if you pass an ArrayList of Somethings.
It will return a LinkedList<Doom>, when you pass a LinkedList of Doom.
I think, you get the idea.
Btw., Madushan Perera`s answer will also return the same Type as passed, but in that case you would have to cast, if assigning to the original variable.
I have three Maps:
Map<Integer,ArrayList<ItemType1>> map1;
Map<Integer,ArrayList<ItemType2>> map2;
Map<Integer,ArrayList<ItemType3>> map3;
I frequently want to look up a key into a map and add an item to it's ArrayList value. I want to make a method that will take as a parameter a map Map<Integer,ArrayList<T>> (with an ArrayList value of a generic type T), a key to add to, and an item of type T to add to that map.
In theory something like this (I know this is not working Java code):
private void addToListInMap(Map<Integer,ArrayList<T>> map,Integer keyValue, T itemToAdd){
ArrayList<T> listOfItems= map.get(keyValue);
if(listOfItems == null){
listOfItems= new ArrayList<T>();
map.put(keyValue, listOfItems);
}
listOfItems.add(itemToAdd);
}
How can I achieve something like this using generics?
This isn't too terribly difficult: provide the generic type as a type argument to your method.
All your code is missing is the type parameter to it. Then, it should "just work".
private <T> void addToListInMap(Map<Integer, ArrayList<T>> map,
Integer keyValue, T itemToAdd) {
ArrayList<T> listOfItems = map.get(keyValue);
if (listOfItems == null) {
listOfItems = new ArrayList<T>();
map.put(keyValue, listOfItems);
}
listOfItems.add(itemToAdd);
}
You need to type the method, so code in the method has access to it (to create the new list).
private static <T> void addToListInMap(Map<Integer,ArrayList<T>> map, Integer keyValue, T itemToAdd {
ArrayList<T> listOfItems = map.get(keyValue);
if (listOfItems == null) {
listOfItems = new ArrayList<T>();
map.put(keyValue, listOfItems);
}
listOfItems.add(itemToAdd);
}
I made the method static too, since it doesn't need access to any fields to work.
You should also consider making the type of the value List<T> instead of ArrayList<T> - see Liskov substitution principle
I have the following function
public <T> T getItemsByType(){
T[] retarr = null;
for(int i = 0; i<items.size(); i++){
if(items.get(i).get instanceof T){
}
}
return null;
}
I need my function to search in a list of items for instances of type T and then return an array of T.
Of course, this would've been great if worked but the problem is that:
Cannot perform instanceof check against type parameter T. Use its erasure Object instead since further generic type information will be erased at runtime
What should I do to obtain the same effect?
You need to pass Class<T> clazz as argument to your method, then use it to check if the element can be assignable to that class by using Class#isInstance.
public <T> T getItemsByType(Class<T> clazz) {
T[] retarr = null;
for(int i = 0; i<items.size(); i++){
if(clazz.isInstance(items.get(i))){
//do your logic here...
}
}
return null;
}
Some recomendations:
It would be better returning a List<T> or Collection<T> instead of returning a single T element.
Avoid returning null, so you don't have to do null-defensive programming.
Use an iterator or an enhanced for loop to traverse through all the elements in your list.
So, a better implementation would be:
public <T> List<T> getItemsByType(Class<T> clazz) {
List<T> theList = new ArrayList<T>();
//using Object since you never specified which type of elements holds this list
for (Object o : items) {
if(clazz.isInstance(o)) {
//do your logic here...
theList.add(clazz.cast(o));
}
}
return theList;
}