Generic method vs wildcard - compilation error - java

I had a issue where (to simplify):
public void method(List<List<?>> list){...}
gave me a compilation error when called with:
method(new ArrayList<List<String>>()); // This line gives the error
After reading a similar thread, I understood that it would work if I were to rewrite the method signature as:
public void method(List<? extends List<?>> list){...}
Now, my question is, why does the following work then?
public <T> void method(List<List<T>> list){...}

Confusions do come when you deal with multi-level wildcard syntax. Let's understand what those types exactly mean in there:
List<List<?>> is a concrete parameterized type. It is a heterogenous collection of different types of List<E>. Since List<?> represent a family of all the instantiation of List, you can't really pass an ArrayList<List<String>> to List<List<?>>. Because, nothing stops you from adding a List<Integer> to it inside the method, and that will crash at runtime, had compiler allowed it.
List<? extends List<?>> is a wildcard parameterized type. It represents a family of different types of List<E>. Basically, it might be a List<ArrayList<String>>, List<LinkedList<Date>>, so on. It can be a list of any type that extend from a List<?>. So, it will be safe to pass a ArrayList<List<String>> to it, the reason being, you won't be allowed to add anything, but null to the list. Adding anything to the list will be a compile time error.
As for List<List<T>>, it is again a concrete parameterized type. And since you're dealing with a generic method now, the type parameter will be inferred to be the type that is passed for it. So, for an ArrayList<List<String>>, type T will be inferred as T. A generic method deals with the types that are declared with it. So, there is only a single type T here. All the lists you get out of List<List<T>> will certainly be a List<T> for any type T. So, it's a homogenous collection of that type of List. Inside the method, you can not add any arbitrary List<E> to the List<List<T>>, because the compiler doesn't know whether that type E is compatible with T or not. So, it is safe invocation.
Related:
Multiple wildcards on a generic methods makes Java compiler (and me!) very confused
Java HashMap nested generics with wildcards
What are multi-level wild cards? Confusion in syntax
When to use generic methods and when to use wild-card?

I think I found the answer in Angelika Langer's generics FAQ, "Case Study #3":
If a method signature uses multi-level wildcard types then there is always a difference between the generic method signature and the wildcard version of it. Here is an example. Assume there is a generic type Box and we need to declare a method that takes a list of boxes.
Example (of a method with a type parameter):
public static <T> void print1( List <Box<T>> list) {
for (Box<T> box : list) {
System.out.println(box);
}
}
Example (of method with wildcards):
public static void print2( List <Box<?>> list) {
for (Box<?> box : list) {
System.out.println(box);
}
}
Both methods are perfectly well behaved methods, but they are not equivalent. The generic version requires a homogenous list of boxes of the same type. The wildcard version accepts a heterogenous list of boxes of different type. This becomes visible when the two print methods are invoked.

The basic reason is that List<List<?>> is not a superclass of List<List<String>>.
A List<List<?>> could contain a List<Integer> and a List<String> for example.
The generic types must match exactly, otherwise you could get erroneous assignments made.

Related

False positive Sonar S1452 on return type containing generic of wildcard generic in java [duplicate]

Is it feasible to say that generic wildcard types should not be used in return parameters of a method?
In other words, does make sense to declare an interface like the following:
interface Foo<T> {
Collection<? extends T> next();
}
Additionally, is it ok to say that generic wildcard types does make sense only at method's parameter declaration?
The main benefit of using wildcard types, say in method formal parameter, is to provide flexibility to the user to pass, say any type of Collection, or List or anything that implements Collection (assuming that the collection is declared like Collection<?>). You would often find yourself using wildcard types in formal parameters.
But ideally you should avoid using them as return type of your method. Because that way, you would force the user of that method to use wildcard types at the caller end, even if they didn't want to. By using wildcard types, you're saying that, hey! this method can return any type of Collection, so it's your job to take care of that. You shouldn't do that. Better to use bounded type parameter. With bounded type parameter, the type will be inferred based on the type you pass, or the target type of the method invocation.
And here's a quote from Effective Java Item 28:
Do not use wildcard types as return types. Rather than providing
additional flexibility for your users, it would force them to use
wildcard types in client code.
Properly used, wildcard types are
nearly invisible to users of a class. They cause methods to accept the
parameters they should accept and reject those they should reject. If
the user of a class has to think about wildcard types, there is
probably something wrong with the class’s API.
No, it is not feasible to say this.
Or to put it that way: It does make sense to have such an interface.
Imagine the following
interface Foo<T>
{
Collection<? extends T> next();
}
class FooInteger implements Foo<Number>
{
private final List<Integer> integers = new ArrayList<Integer>();
void useInternally()
{
integers.add(123);
Integer i = integers.get(0);
}
#Override
public Collection<? extends Number> next()
{
return integers;
}
}
// Using it:
Foo<Number> foo = new FooInteger();
Collection<? extends Number> next = foo.next();
Number n = next.iterator().next();
If you wrote the return type as Collection<T>, you could not return a collection containing a subtype of T.
Whether or not it is desirable to have such a return type depends on the application case. In some cases, it may simply be necessary. But if it is easy to avoid, then you can do this.
EDIT: Edited the code to point out the difference, namely that you might not always be able to choose the type internally. However, in most cases returning something that involves a wildcard can be avoided - and as I said, if possible, it should be avoided.
The example sketched above should still be considered as an example to emphasize the key point. Although, of course, such an implementation would be a bad practice, because it is exposing an internal state.
In this and similar cases, one can often return something like a
return Collections.<Number>unmodifiableList(integers);
and by this, declare the return type as Colletion<Number>: The unmodifiableList method solves the problem of the exposed internal state, and has the neat property that it allows changing the type parameter to a supertype, because the list is then... well, unmodifiable anyhow.
https://rules.sonarsource.com/java/RSPEC-1452
It is highly recommended not to use wildcard types as return types.
Because the type inference rules are fairly complex it is unlikely the
user of that API will know how to use it correctly. Let's take the
example of method returning a "List<? extends Animal>". Is it possible
on this list to add a Dog, a Cat, ... we simply don't know. And
neither does the compiler, which is why it will not allow such a
direct use. The use of wildcard types should be limited to method
parameters.
This rule raises an issue when a method returns a wildcard type.
Noncompliant Code Example
 List<? extends Animal> getAnimals(){...}  
Compliant Solution
 List<Animal> getAnimals(){...}   or
 List<Dog> getAnimals(){...}

Java name clash error, a method has the same erasure as another method

I have two classes as follows
class QueryResult:
public class QueryResult
{
...
public static List sortResults(boolean ascending, List<QueryResult> toSort)
{ ...
}
}
and class CaseResult:
public class CaseResult extends QueryResult
{
...
public static List sortResults(boolean ascending, List<CaseResult> toSort)
{ ...
}
}
I am getting the following error:
Name clash: The method sortResults(boolean, List) of type
CaseResult has the same erasure as sortResults(boolean,
List) of type QueryResult but does not hide
it CaseResult.java
I tried answers under the similar question Java generics name clash , has the same erasure but got more errors. I think I may misunderstand something or those answers do not fit my case.
Could someone please provide any solutions or explain more to help me understand? Thank you all.
The reason for the error is covered in Darshit Chokshi's answer.
However, since a solution/alternative has not been posted yet, try the following:
You are trying to override the sortResults() method in such a way so that you can sort lists with different elements. However, when overriding you need to have the same type signature. The signature looks similar in your case, but since the elements in the List differ - the compiler realises List< QueryResult> and List< CaseResult> is different, but due to type erasure in Java, it would be uncertain which method it should be calling - i.e. should it call the super class method or the subclass method.
Instead of overriding, rather change the original method in the super class (in your case, QueryResult) so that it can handle anytype of List element. You can use wildcard capturing to accomplish this:
public class QueryResult {
...
public <T> static List<T> sortResults(boolean ascending, List<T> toSort) {
...
}
}
This method receives a list and will infer the element type, assigning the element type to the generic type parameter T. Whenever you then want to refer to the element type in the body of the method, instead of using the element type name (previously either QueryResult or CaseResult), now you would use the generic type variable T instead.
You can also put further bounds on this variable if required (i.e. if the list element needs to be a subtype of QueryResult you can say < T extends QueryResult>), this will force Java to do a type check on the List and what type of elements it may have.
A further comment on your original code. Be very careful of using raw types in new generic code - you are returning a list as a raw type: List, without specifying what the element type of the list is i.e. a parameterised type: List< SomeActualType>. This can cause many problems and is not advised. The Java creators kept this form of coding in Java for backward compatibility of code that existed before generics, but it is strongly advised not to code in this manner for new written code.
You can read up more about the raw type vs parameterised type and the pitfalls of using raw types, as well as more information on wildcard capturing and bounds, in the textbook:
Effective Java, by Joshua Bloch
Section: Generics
Item 23: Don't use raw types in new code
Item 28: Use bounded wildcards to increase API flexibility
As per Java Documentation,
If a subclass defines a static method with the same signature as a static method in the superclass, then the method in the subclass hides the one in the superclass.
The distinction between hiding a static method and overriding an instance method has important implications:
The version of the overridden instance method that gets invoked is the one in the subclass.
The version of the hidden static method that gets invoked depends on whether it is invoked from the superclass or the subclass

All Possible ways Of Generics Identifier to Methods when Method Argument are <T> Or <?> or any?

Not new to java but You may consider Me as new to Generics and having through various Confusion such that
A) Is It necessary to add generics identifier to Method IF Method contains any argument like myMethod(List <T> prm_ObjT, List<? extends Object>) Or Any Such type of Arguments .
I Have tried this example to learn this Concept. And write multiple Variety of this Method
public static void test(List<T> set)
Error : cannot find symbol T :- public static void test(List<T> set)
public static <T extends Object> void test(List<T> list) // Works Fine to me
public static <T> void test(List<T> list) // Works Again fine to me
public static <? extends Object>void test(List<?> set)
Error : error: <identifier> expected
public static <? extends Object>void test(List<?> set)
class Ideone
{
private static List<String> obj_larr= new ArrayList<String>();
static {
obj_larr.add("Vikrant");
obj_larr.add("Nakul");
obj_larr.add("Vishwas");
obj_larr.add("Neeraj");
obj_larr.add("Wahid");
}
public static <T extends Object> void test(List<T> list){ //Works Fine To me.
System.out.println(list);
}
public static void main (String[] args) throws java.lang.Exception
{
test(obj_larr);
}
}
Question :- Please explain each Situation and Provide all possible Combination of Identifier that can attach with a Method() If Method Generic Argument is passed in different ways ..?
Java Generics are confusing and somewhat illusive. There is also some terminology that one needs to use precisely. Usually, applying first principles works, but there are some hairy cases where the line noise in the Java source code becomes rather too much. Fortunately, your confusion is in understandable parts of Java Generics.
First of all, all your questions are with respect to generic methods. In Java, you have both generic classes and generic methods. The thing of (generic) essence here is the so called type parameter. The weird looking things enclosed inside <> are called type parameters.
The usefulness of generic methods is evident when you have a particular case at hand. My favorite example of this is from the JDK library itself, in the java.util.Arrays class:
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
Here, the generic method is taking a variable list of arguments of any type and returning an ArrayList containing those elements. An invocation of this method is:
List<Integer> intList = Arrays.asList(1, 2, 3);
or
List<String> myFriends = Arrays.asList("Larry", "Moe", "Curly");
See how generic definition of Arrays.asList helps here, the compiler is able to assign Integer to the type parameter T in the first case, whereas String in another case!
Understanding generics using concrete examples (rather than contrived examples you cite) like the above helps.
There's a lot going on here, but one way to explain this is to look at it from a compiler's standpoint. Here's an attempt to explain why compilation succeeds or fails in the cases you have cited:
When it tries to compile a method like public static void test(List<T> set), it gathers that it is a static method that takes a List of some type parameter T. But what is T? Compiler wants you to specify that it is a generic type parameter (let's say it's just the "syntax" of generic method declaration). That's what you do when you say public static <T> void test(List<T> set) and compiler is happy.
In the second declaration, you do specify that and compiler is happy. It's important to note that like any other Object in Java, the type parameter itself also needs to be an Object and like (when your class is just a java.lang.Object) you don't have to specify public class MyClass extends Object, you don't have to specify that T extends Object if that's the only restriction you have. So, public static <T extends Object> void test(List<T> list) is equivalent to public static <T> void test(List<T> list). You might argue why <T> is needed in the generic method declaration, but you may read the language specification for details, since the devil is in the details here.
As we said above in 2), 2) and 3) are equivalent.
The type parameter, if specified, must have a name. In this declaration you are considering the so-called wild-card and that complicates things further. But leaving that aside, like the compiler is complaining, it does not find the generic type declaration in your method declaration valid because it wants to know the name (or, identifier) for the type parameter.
I am not good at generic either. Here is my way to remember the syntax:
When using the generic type T in a method, it can be a parameter or a return type. So you will have to declare it before the return type.
The wildcard ? means we don't care about the type, so you use it directly.
You'll find a complete treatment of type calculus (why the type system is mathematically sound) in Benjamin Pierce's excellent book Types and Programming Languages (TAPL).
An important first thing to understand is that type variables name types, which in Java are always represented as classes.
Before Generics
Using your method signature, let's consider what it looked like before generics in Java: public static void test(List list). That shouldn't be confusing at all.
However, note that the "naked" List can hold any objects at all. A more precise way to say that: it can hold any subclass of Object and we have no way of constraining types added to the list, e.g., a list containing both an Integer and a String.
List list = new ArrayList();
list.add("hello world!");
list.add(new Integer(1));
test(list);
That's perfectly legal Java syntax, even today (with compiler warnings). But notice that the test method must handle any possible type provided inside the list.
What's needed is a way to constrain the types that can be placed into the list and have the compiler enforce that to the best of its ability.
Generically
We can use the syntax public static void test(List<Object> list) to represent the same thing, but we still haven't constrained the values of the list.
Type Constants and Type Variables
Notice above where we specified List<Object>, that Object is a type constant. The only thing it describes is instances of the exact type Object and that's really all we can know about items the list contains.
What we need is a way to specify an unknown type when the List class is being compiled. There's no way that the JDK, which implements the List class, can know at its compile time what you might want to put in it.
Furthermore, we need more flexibility than that. We'd like to be able to specify type constraints in 3 different flavors:
some type that we'll name T, exactly (a.k.a. invariant), with syntax <T>;
some type that we'll name T and all of its subtypes (a.k.a. covariant), with syntax <? extends T>;
some type that we'll name T and all of its supertypes (a.k.a. contravariant), with syntax <? super T>.
That's where type variables come from. They represent unknown types at compile time, just as normal variables represent unknown values at compile time.
In order to get all 3 constraint flavors, the compiler treats type variables for Java methods using the syntax above. You cannot use the second or third syntax for generic variable declarations (a List<Number> can hold values of type Number or any of its subclasses without extra syntax).
Note that in the type calculus presented in TAPL, T is both the first subtype of itself, and also the first supertype of itself. So saying ? extends T or ? super T implicitly includes T itself.
More on type variance at https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)
Back to Your Examples
public static void test(List<T> set) fails because the compiler is looking for a type (class named T), which isn't defined anywhere.
public static <T extends Object> void test(List<T> list) is correct syntax but more verbose than it needs to be. Idiomatically, it's the same as
public static <T> void test(List<T> list)
Here, the test method still receives values of type Object, because there's no further constraint on T.
public static <? extends Object> void test(List<?> set) fails because ? is not a valid type variable name (same restrictions as for Java class names).
public static void test(List<?> set) works just fine.
Notes
In Java, generics are only a feature of the compiler. There were no JVM changes. Therefore the bytecode method signatures still use Object, and the compiler emits cast instructions where needed.
Because of (1), you have to consider type erasure, but that's another question for another day.

Why use a wild card capture helper method?

Referring to : Wildcard Capture Helper Methods
It says to create a helper method to capture the wild card.
public void foo(List<?> i) {
fooHelper(i);
}
private <T> void fooHelper(List<T> l) {
l.set(0, l.get(0));
}
Just using this function below alone doesn't produce any compilation errors, and seems to work the same way. What I don't understand is: why wouldn't you just use this and avoid using a helper?
public <T> void foo(List<T> l) {
l.set(0, l.get(0));
}
I thought that this question would really boil down to: what's the difference between wildcard and generics? So, I went to this: difference between wildcard and generics.
It says to use type parameters:
1) If you want to enforce some relationship on the different types of method arguments, you can't do that with wildcards, you have to use type parameters.
But, isn't that exactly what the wildcard with helper function is actually doing? Is it not enforcing a relationship on different types of method arguments with its setting and getting of unknown values?
My question is: If you have to define something that requires a relationship on different types of method args, then why use wildcards in the first place and then use a helper function for it?
It seems like a hacky way to incorporate wildcards.
In this particular case it's because the List.set(int, E) method requires the type to be the same as the type in the list.
If you don't have the helper method, the compiler doesn't know if ? is the same for List<?> and the return from get(int) so you get a compiler error:
The method set(int, capture#1-of ?) in the type List<capture#1-of ?> is not applicable for the arguments (int, capture#2-of ?)
With the helper method, you are telling the compiler, the type is the same, I just don't know what the type is.
So why have the non-helper method?
Generics weren't introduced until Java 5 so there is a lot of code out there that predates generics. A pre-Java 5 List is now a List<?> so if you were trying to compile old code in a generic aware compiler, you would have to add these helper methods if you couldn't change the method signatures.
I agree: Delete the helper method and type the public API. There's no reason not to, and every reason to.
Just to summarise the need for the helper with the wildcard version: Although it's obvious to us as humans, the compiler doesn't know that the unknown type returned from l.get(0) is the same unknown type of the list itself. ie it doesn't factor in that the parameter of the set() call comes from the same list object as the target, so it must be a safe operation. It only notices that the type returned from get() is unknown and the type of the target list is unknown, and two unknowns are not guaranteed to be the same type.
You are correct that we don't have to use the wildcard version.
It comes down to which API looks/feels "better", which is subjective
void foo(List<?> i)
<T> void foo(List<T> i)
I'll say the 1st version is better.
If there are bounds
void foo(List<? extends Number> i)
<T extends Number> void foo(List<T> i)
The 1st version looks even more compact; the type information are all in one place.
At this point of time, the wildcard version is the idiomatic way, and it's more familiar to programmers.
There are a lot of wildcards in JDK method definitions, particularly after java8's introduction of lambda/Stream. They are very ugly, admittedly, because we don't have variance types. But think how much uglier it'll be if we expand all wildcards to type vars.
The Java 14 Language Specification, Section 5.1.10 (PDF) devotes some paragraphs to why one would prefer providing the wildcard method publicly, while using the generic method privately. Specifically, they say (of the public generic method):
This is undesirable, as it exposes implementation information to the caller.
What do they mean by this? What exactly is getting exposed in one and not the other?
Did you know you can pass type parameters directly to a method? If you have a static method <T> Foo<T> create() on a Foo class -- yes, this has been most useful to me for static factory methods -- then you can invoke it as Foo.<String>create(). You normally don't need -- or want -- to do this, since Java can sometimes infer those types from any provided arguments. But the fact remains that you can provide those types explicitly.
So the generic <T> void foo(List<T> i) really takes two parameters at the language level: the element type of the list, and the list itself. We've modified the method contract just to save ourselves some time on the implementation side!
It's easy to think that <?> is just shorthand for the more explicit generic syntax, but I think Java's notation actually obscures what's really going on here. Let's translate into the language of type theory for a moment:
/* Java *//* Type theory */
List<?> ~~ ∃T. List<T>
void foo(List<?> l) ~~ (∃T. List<T>) -> ()
<T> void foo(List<T> l) ~~ ∀T.(List<T> -> ()
A type like List<?> is called an existential type. The ? means that there is some type that goes there, but we don't know what it is. On the type theory side, ∃T. means "there exists some T", which is essentially what I said in the previous sentence -- we've just given that type a name, even though we still don't know what it is.
In type theory, functions have type A -> B, where A is the input type and B is the return type. (We write void as () for silly reasons.) Notice that on the second line, our input type is the same existential list we've been discussing.
Something strange happens on the third line! On the Java side, it looks like we've simply named the wildcard (which isn't a bad intuition for it). On the type theory side we've said something _superficially very similar to the previous line: for any type of the caller's choice, we will accept a list of that type. (∀T. is, indeed, read as "for all T".) But the scope of T is now totally different -- the brackets have moved to include the output type! That's critical: we couldn't write something like <T> List<T> reverse(List<T> l) without that wider scope.
But if we don't need that wider scope to describe the function's contract, then reducing the scope of our variables (yes, even type-level variables) makes it easier to reason about those variables. The existential form of the method makes it abundantly clear to the caller that the relevance of the list's element type extends no further than the list itself.

Generics (List) typing question

I am trying to use a common technique to create objects from Xml. (Xml is legacy, so although there are already libraries to do this, it seemed faster to write this myself.)
I don't understand the compiler's complaint about the generic usage. Code sample:
public void createObjects() {
List<Object1> objectOnes = new ArrayList<Object1>();
List<Object2> objectTwos = new ArrayList<Object2>();
parseObjectsToList("XmlElement1", objectOnes);
parseObjectsToList("XmlElement2", objectTwos);
}
private void parseObjectsToList(String xmlTag, List<? extends Object> targetList) {
// read Xml and create object using reflection
Object newObj = createObjectFromXml(xmlTag);
targetList.add(newObj)
/* compiler complains: "The method add(capture#2-of ? extends Object) in the type List<capture#2-of ? extends Object> is not applicable for the arguments (Object)"
*/
/* If I change method signature to parseObjectsToList(String xmlTag, List targetList)
it works fine, but generates compiler warning about raw type */
}
Thanks for any enlightenment on the subject!
The problem you are running into is that, with the bounded wildcard that you have defined, you will be unable to add any element to the collection. From this tutorial:
List<? extends Shape > is an example of a bounded wildcard. The ? stands for an unknown type, just like the wildcards we saw earlier. 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.
There is, as usual, a price to be paid for the flexibility of using wildcards. That price is that it is now illegal to write into shapes in the body of the method
All a wildcard type means is that the actual type parameter T of the List that you pass as the second argument to parseObjectsToList is going to be a subtype of Object. It does NOT mean that the same List will be parameterized with different types.
So now you have a List<T> (called targetList) and you are trying to call targetList.add(Object). This is illegal because Object is not necessarily a subtype of T.
Because you are adding to the List rather than extracting elements from it, use List<Object> and make sure that's exactly what you pass in.
Using a List<Object> will work, but you might want keep your more precisely typed List<Object1> and List<Object2> for type-safety elsewhere. In that case, you'll need to check the type of each object before adding it to the List.
private void parseObjectsToList(String tag, List<T> list, Class<? extends T> c) {
// read Xml and create object using reflection
Object newObj = createObjectFromXml(tag);
list.add(c.cast(newObj)) ;
}
The cast() operation is a reflective equivalent to the static cast operator: (T) newObj
Using the altered method would look something like this:
parseObjectsToList("XmlElement1", objectOnes, Object1.class);
Think about what you are asking the compiler to do:
Given a list of "something that is a subtype of Object
Let me insert an Object into it
This doesn't make sense. Suppose your list is a list of Integer. Suppose that createObjectFromXml returns a String. It wouldn't make sense to allow inserting a String into a list typed for Integers.
So, your options are either to make your List a List<Object> or to find some way to make createObjectFromXml return a specific type, that you can then tie to the type of your list.

Categories