Java generic list methods

Java generic list return type

Why does the thisDoesntWork() method not work, and is there any other way around it (other than doing it the thisWorks() way which isn’t always practical)?

When it is not practical it means you should not be doing it. Even your thisWorks method is unsafe, because you are assuming your genericList will hold String (which you cannot tell for sure from your code).

getGenericList() returns a List, but you need to call addAll() with a List. List is not the same as List, hence the error. So why is myList declared to be List rather than List?

@SJuan76: There’s no way around it. The original data source contains objects, but we need to be able to treat the contents as strings. This could in theory lead to ClassCastExceptions yes, but hopefully we will be able to keep track of what kind of list is contained.

That’s a good point, but String was just an example. I need to be able to handle other types too. In any case, if the elements are not actually Strings, adding the results of toString() to the lists will likely lead to even more confusion than a ClassCastException would. I edited the question to reflect that it’s not actually String related.

4 Answers 4

The compiler cannot infer what type to choose for the type parameter of the generic method getGenericList() in thisDoesntWork() .

In this case you need to explicitly state the Type for the type argument by calling getGenericList()

Alternatively you can change the signature of getGenericList() to accept a Class argument. Then you would invoke getGenericList(MyListElement.class) in both thisWorks() and thisDoesntWork() . Admittedly that’s a bit more verbose, but definitly more intuitive to clients of your method.

I would say as a general rule, try to make the type arguments of your generic methods be inferrable from that method’s arguments.

Would it be acceptable to have both a getGenericList() AND a getGenericList(Class) version? That would let the caller pick which one he wants to use.

Thanks for poitning that out, my answer still reflected the question’s original type, which was String. I’ve edited my answer to match the current form of the question.

You can change thisDoesntWork() like so:

 public void thisDoesntWork()< // well, it works now myList.addAll(this.getGenericList()); > 

You need to tell the compiler what type getGenericList() is dealing with.

Since myList is expecting a String , we know we’re dealing with String s. If it were some other type, the code would have to change accordingly.

getGenericList() is just an example method to simplify the code as much as possible. In the real application it will return a real list and in theory the objects inside could be some other type. I would assume the result is a ClassCastException.

@jahroy: it doesn’t contain anything, but that’s irrelevant. We are trying to tell the compiler what type to infer for E

@jahroy: We are not talking about the runtime (at runtime there is no difference between lists of different types). We are talking about the compile time. At compile-time, each expression has a definite type, that is inferred by the compiler.

The type argument to the generic method getGenericsList() can be passed at call time:

otherwise the compiler does its best to deduce it from the context. When you assign the returned object to a List reference, the compiler hence infers that you passed String as the type argument.

the compiler doesn’t seem to be able to infer the correct type, and to be honest I don’t know if this is because it is not smart enough, or because it doesn’t want to carry the responsibility by design.

Читайте также:  Php перевод с английского

I even made a test to see if the problem is the wildcard, or if addAll() cannot infer the type arguments from the parameterized type, but nothing seems to work:

public class GenericsList < public static void main(String[] args) < // same signature as Java API Listbase = new List(); base.addAll(GenericsList.getList()); // ERROR! // addAll() doesn't use a wildcard List2 base2 = new List2(); base2.addAll(getList2()); // ERROR! // what about a generic method? addAll(base, getList()); // ERROR! > static List getList() < return new List(); > static void addAll(List src, List other) <> static List2 getList2() < return new List2(); > static class List  < void addAll(List magicalListGetter(Class clazz) < Listlist = doMagicalVooDooHere(); return list; > 

9 Answers 9

private Object actuallyT; public List magicalListGetter(Class klazz) < Listlist = new ArrayList<>(); list.add(klazz.cast(actuallyT)); try < list.add(klazz.getConstructor().newInstance()); // If default constructor >. return list; > 

One can give a generic type parameter to a method too. You have correctly deduced that one needs the correct class instance, to create things ( klazz.getConstructor().newInstance() ).

No need to even pass the class:

public List magicalListGetter() < return new ArrayList(); > 

This is the best solution if you want to manipulate the list and simply return the same type. (For instance, reversing the order, reducing the number of items, etc.) Passing a class would only be needed if you need to instantiate a new object of type T.

Another option is doing the following:

public class UserList extends List < >public T magicalListGetter(Class clazz) < Listlist = doMagicalVooDooHere(); return (T)list; > List users = magicalListGetter(UserList.class); 

Let us have List objectList which we want to cast to List

public List list(Class c, List objectList) < Listlist = new ArrayList<>(); for (Object o : objectList) < T t = c.cast(o); list.add(t); >return list; > 
public List magicalListGetter()

or you can use Object and the parent class of everything:

public List magicalListGetter() < Listlist = doMagicalVooDooHere(); return list; > 

Note Perhaps there is a better parent class for all the objects you will put in the list. For example, Number would allow you to put Double and Integer in there.

publiс List magicalListGetter(Class clazz)

You can simply cast to List and then check if every element can be casted to T.

public List asList(final Class clazz) < Listvalues = (List) this.value; values.forEach(clazz::cast); return values; > 

Given some legacy code that returns an untyped List

List list = database.GetCustomers(); //legacy code returns untyped list 

we will use a helper function:

public static @NotNull List castList(final @NotNull Iterable sourceList) < Listresult = new ArrayList<>(); for (Object o : sourceList) result.add((T)o); return result; > 

to convert the returned list to a generic typed List :

List = castList(database.GetCustomers()); //cast the list the appropriate type 

Why Java doesn’t have extension methods is quite beyond me.

I’m pretty sure you can completely delete the , which will generate a warning and you can use an, @ suppress warnings. If you really want it to be generic, but to use any of its elements you will have to do type casting. For instance, I made a simple bubble sort function and it uses a generic type when sorting the list, which is actually an array of Comparable in this case. If you wish to use an item, do something like: System.out.println((Double)arrayOfDoubles[0] + (Double)arrayOfDoubles[1]); because I stuffed Double(s) into Comparable(s) which is polymorphism since all Double(s) inherit from Comparable to allow easy sorting through Collections.sort()

 //INDENT TO DISPLAY CODE ON STACK-OVERFLOW @SuppressWarnings("unchecked") public static void simpleBubbleSort_ascending(@SuppressWarnings("rawtypes") Comparable[] arrayOfDoubles) < //VARS //looping int end = arrayOfDoubles.length - 1;//the last index in our loops int iterationsMax = arrayOfDoubles.length - 1; //swapping @SuppressWarnings("rawtypes") Comparable tempSwap = 0.0;//a temporary double used in the swap process int elementP1 = 1;//element + 1, an index for comparing and swapping //CODE //do up to 'iterationsMax' many iterations for (int iteration = 0; iteration < iterationsMax; iteration++) < //go through each element and compare it to the next element for (int element = 0; element < end; element++) < elementP1 = element + 1; //if the elements need to be swapped, swap them if (arrayOfDoubles[element].compareTo(arrayOfDoubles[elementP1])==1) < //swap tempSwap = arrayOfDoubles[element]; arrayOfDoubles[element] = arrayOfDoubles[elementP1]; arrayOfDoubles[elementP1] = tempSwap; >> > >//END public static void simpleBubbleSort_ascending(double[] arrayOfDoubles) 

Highly active question. Earn 10 reputation (not counting the association bonus) in order to answer this question. The reputation requirement helps protect this question from spam and non-answer activity.

Linked

Hot Network Questions

Subscribe to RSS

To subscribe to this RSS feed, copy and paste this URL into your RSS reader.

Site design / logo © 2023 Stack Exchange Inc; user contributions licensed under CC BY-SA . rev 2023.7.21.43541

By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy.

Источник

What does List mean in java generics?

As Tom said, the ? , or unbounded wildcard, means that the type of the object is not specified. It could be unknown, could be meant for multiple possible values or might be just plain irrelevant. Your example, List , is pronounced «List of unknown.» It’s convenient because it’s flexible, but there are also some pitfalls because you can’t shove random objects in and pull them out of groups of unknown with total impunity.

  • Wildcards are discussed here in the Java tutorial.
  • There’s a good — if verbose — tutorial on generics in general by Angelika Langer available here.
  • And there’s another good overview here (PDF) by Gilad Bracha; check out pages 5-7.
  • Finally, if you can get your hands on Effective Java by Josh Bloch, it’s got a great section on generics and the cases in which you can, can’t, should and shouldn’t use wildcards (chapter 5, pages 109-146 in the second edition).

Incidentally, your Google search failed because Google doesn’t truck with special characters:

With some exceptions, punctuation is ignored (that is, you can’t search for @#$%^&*()=+[]\ and other special characters).

(EDIT: I must have been really tired when I wrote this last night. Cleaned up formatting/added a little info.)

The keyword you need to get more information is Wildcards

To answer this question I need to explain Unbounded Wildcards and Bounded Wildcards.
The content of this post has been assembled from java documentation.

1. Unbounded Wildcards

  • If you are writing a method that can be implemented using functionality provided in the Object class.
  • When the code is using methods in the generic class that don’t depend on the type parameter. For example, List.size or List.clear . In fact, Class is so often used because most of the methods in Class do not depend on T .

2. Bounded Wildcards

Consider a simple drawing application that can draw shapes such as rectangles and circles. To represent these shapes within the program, you could define a class hierarchy such as this:

public abstract class Shape < public abstract void draw(Canvas c); >public class Circle extends Shape < private int x, y, radius; public void draw(Canvas c) < . >> public class Rectangle extends Shape < private int x, y, width, height; public void draw(Canvas c) < . >> 

These classes can be drawn on a canvas:

Any drawing will typically contain a number of shapes. Assuming that they are represented as a list, it would be convenient to have a method in Canvas that draws them all:

public void drawAll(List shapes) < for (Shape s: shapes) < s.draw(this); >> 

Now, the type rules say that drawAll() can only be called on lists of exactly Shape: it cannot, for instance, be called on a List . That is unfortunate, since all the method does is read shapes from the list, so it could just as well be called on a List . What we really want is for the method to accept a list of any kind of shape: public void drawAll(List shapes) < . >There is a small but very important difference here: we have replaced the type List with List . Now drawAll() will accept lists of any subclass of Shape , so we can now call it on a List if we want.

List is an example of a bounded wildcard. The ? stands for an unknown type, however, in this case, we know that this unknown type is in fact a subtype of Shape. (Note: It could be Shape itself, or some subclass; it need not literally extend Shape.) We say that Shape is the upper bound of the wildcard.

Similarly, the syntax ? super T , which is a bounded wildcard, denotes an unknown type that is a supertype of T. A ArrayedHeap280 , for example, includes ArrayedHeap280 , ArrayedHeap280 , and ArrayedHeap280 . As you can see in the java documentation for Integer class, Integer is a subclass of Number that in turn is a subclass of Object.

Источник

Оцените статью