What is the best way to define Generic Method in Java? - java

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

Java Mapping Class and List to Generic Types

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;
}

Java - From a String Type name how to initialize an ArrayList of that Type

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).

Reverse a generic list?

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.

Using generics to add an object of generic type to a map

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

How to create a method that retrieves a sublist containing elements of a specific class T?

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;
}

Categories

Resources