This question already has answers here:
What is the difference between 'E', 'T', and '?' for Java generics?
(6 answers)
Generic type parameter naming convention for Java (with multiple chars)?
(5 answers)
Where does the T, U, V convention for generic type params come from? [closed]
(1 answer)
Understanding Java generics. Type parameter conventions
(5 answers)
Closed 7 months ago.
I use javap often.
So when I see JDK classes across, I understood that probably:
T means Type;
E means Enumertion;
Meaning of V is unclear for me.
Please shed some light on this question?
Maybe I am wrong. But I see several JDK classes belongs to package java.util.function.* , java.util.concurrent.* has this V, T, E in place of class type, return type.
In Java 5 Generic types were introduced in the language. In a nutshell generics - is a mechanism of type safety, they are meant to make the code more robust. Generics allow writing clean and highly reusable code without performing instanceof checks and type-casting (to be precise type-casts are still there, they would be added by the compiler under the hood, and they are safe).
V, T, E, etc. are so-called type variables. These are only placeholders, not the actual types, i.e. it's a way to tell the compiler that you expect a particular type at runtime and you can refer to this type using type variable.
In your code, you can call type variables with any name you like. The common convention is to use single uppercase letters like T, R, but compiler be happy with Cat as a type variable, and even with a name of existing JDK classes and interfaces like Integer (which is highly discouraged, but your code would compile).
public class MyClass<T> {} // OK
public class MyClass<CAT> {} // OK
public class MyClass<Integer> {} // OK, note `Integer` is just a placeholder and has the the same meaning as `T` or `A`
public class MyClass<super> {} // will NOT compile, keywords and restricted identifiers (like `record` which isn't a keyword) can't be used as generic type parameters
Regarding type variables that you can encounter in the JDK, there's no common policy that has been listed anywhere. Sometimes there's some informal intuition behind these names, sometimes probably not (e.g. when you see T, U, V defined together as generic variables you can clearly observe that it's an order of letters in the English alphabet, T - stands for type, and U, V are simply some other types distinct from T and each other).
Speaking of cases when probably there's some meaning:
E - in Collection<E> most likely means element, and in Enum<E> - stands for enum.
R in Function<T,R> stands for result, or return type of the function.
K and V in Map<K,V> and Map.Entry<K,V> stand for key and value.
A in the Collector<T,A,R> interface is meant to represent accumulation type (type of the mutable container which collector uses internally).
Java has a feature called generics which is used to develop classes such that its functionality can be used with any type of objects. The letter you see like T, E or V are just place holders. For example List<E>. This is substituted with actual class when start using the list like below.
List<Integer> numbers = new ArrayList<Integer>();
Java uses this approach to check type safety so that a String object cannot be added to an Integer list.
numbers.add(1); //Good
numbers.add("Harry"); //Compilation error
Here are some useful resources.
https://docs.oracle.com/javase/tutorial/java/generics/index.html
https://www.baeldung.com/java-generics
Related
I just saw this kind of code ImmutableList<String> list= ImmutableList.<String>builder().build();
which really confused me. How to understand the diamond after ImmutableList.?
Most parameterized types in java show up on a type. This looks like so:
interface List<T> {
void add(T elem);
}
So, any List type is parameterized, and as generics is really just a mechanism to link things, what it links is that a List<String> has an add method that takes String objects, and a get(int) method that returns a String, etc.
But, methods themselves may also want this linking behaviour. For example, let's say I want to make a method that takes 2 arguments of the same type, and returns the first non-null one. Here too I want to link things: The types of the 2 argument, and the return type? All the same thing, caller's choice as to what it might be.
Java supports this: Methods can ALSO have generics:
public <T> T firstNonNull(T a, T b) {
return a == null ? b : a;
}
is valid java, and you can call it:
String a = firstNonNull("hello", "world!");
Compiles without requiring a cast.
Java will infer generics if it can; it does that in my previous example (the two arguments are both strings; java infers you meant T to be String there). But you can, if you want, be explicit about it. This is where this funky syntax comes in:
Number a = ClassContainingFNN.<Number>firstNonNull(null, null);
You need the dot to use this syntax, hence why I had to make the call a little longer. With the ImmutableList builder method, java can't (easily) infer what type you wanted, as the call to builder() itself doesn't let the compiler know that you're attempting to build a list of, say, strings. That's why forcing it by explicitly telling java what you want the type param to be is useful, thus, why the usual way to call this builder is:
ImmutableList.<String>builder().add(aString).add(anotherString).build();
Java will always try to infer something if you don't explicitly pick something, but it would just infer Object here. Unless you wanted a list of objects, you need the 'forcibly pick a type' option.
See java support jls-15.12 for supporting TypeArguments after entering Type.
MethodInvocation:
MethodName ( [ArgumentList] )
TypeName . [TypeArguments] Identifier ( [ArgumentList] )
The builder is generic method
public static <E> Builder<E> builder()
And because it's static you entered before method name the type using diamond operator
In case of new instance it'll be as you expected:
new ImmutableList.Builder<Color>()
I was reading and reviewing the following site and had a question.
https://www.geeksforgeeks.org/angle-bracket-in-java-with-examples/
In the explanations below they show class definitions followed by <T> and then when actually implementing these classes they use different types such as or as the parameters. My question is: is the '' notation actually a defined syntax in Java? In particular, is the T a necessary thing in order to define a "Generic"? And then does it basically mean that the parameters can be of multiple different types? Also, if anyone can reword or explain in simpler terms what the meaning of a generic is that would be very helpful. Thanks.
The <T> is indeed a syntax defined by Java, but you can use whatever name you want to name a type, you don't need to use T, for example this is valid:
public class Box<MyType> {
private MyType t;
public void set(MyType t) { this.t = t; }
public MyType get() { return t; }
}
But, stick with T or other common type names, as other people are already used to seeing those as the "generic types" so it makes reading your code simpler.
I recommend you read Java's Trail about Generics, where you can find the most commonly used type parameter names:
E - Element
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types
As for "what the meaning of generics is", check this other page.
It’s defined syntax since Java 5. You need a type parameter (one or more) for defining a generic. The type parameter needs not be called T, any Java identifier will do. A single uppercase letter is conventional, and T for type is what we often pick if we haven’t got a specific reason for some other letter.
The actual type parameter has to be a reference type. Values still always go into actual parameters in round brackets, not into type parameters (unlike in C++, for example). You can make a new ArrayList<Integer>(50), a list of Integer objects with an initial capacity for 50 of them.
That the actual type parameter has to be a reference type means that you can have a List<String>, a List<LocalDate> or a list of an interface type that you have declared yourself, even a List<int[]>. In the Java versions I have used (up to Java 10) the type parameter cannot be a primitive type (like int), but it can be an array type (like int[] or String[][], though often impractical). Allowing primitive types may come in a future Java version.
Link: Similar question: What does < T > (angle brackets) mean in Java?
I was reading about Set interface from here which the code sipped below which is a generic method that removes duplicates from a collection.
My question is what is that **< E>** placed after static before Set<E> ?
I mean wouldn't that Set<E> be enough ? why <E> was there twice?
public static <E> Set<E> removeDups(Collection<E> c) {
return new LinkedHashSet<E>(c);
}
Here **<E>** is a generic type. Generic type is defined as
A generic type is a generic class or interface that is parameterized
over types. The following Box class will be modified to demonstrate
the concept. LINK
And regarding you question related to <E>. A good description for it can be found on the same tutorial
Type Parameter Naming Conventions
By convention, type parameter names are single, uppercase letters.
This stands in sharp contrast to the variable naming conventions that
you already know about, and with good reason: Without this convention,
it would be difficult to tell the difference between a type variable
and an ordinary class or interface name.
The most commonly used type parameter names are:
E - Element (used extensively by the Java Collections Framework)
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types
You'll see these names used throughout the Java SE API and the rest of
this lesson.
This means that this method declares a generic parameter type which the class does not define; in this case, you MUST declare the parameter type before the return type (even if this "return type" is void).
Think about it this way. Remove the initial <E>. Your declaration would then become:
public static Set<E> removeDups(Collection<E> c)
What is E here? Unless it is a generic parameter type defined by the class itself, it can only be an existing class.
Hence this syntax. It allows you to define a generic parameter for use in the method signature.
It's just the generic type used within the method. Static methods that use generic types must specify that type before the return type.
Java lesson on generics are leading me to variance concept. This causes me some headaches as I cannot find a very simple demonstration of what it is.
I have read several similar questions on stackoverflow, but I found them too difficult to understand for a Java learner. Actually the problem is that the explanation of generics requires variance to be understood, and the concept of variance is demonstrated relying heavily on generics understanding.
I had some hope reading this, but in the end I shared C. R.'s feeling:
The title reminds me of the days learning general relativity. – C.R.
Dec 22 '13 at 7:34
Four theory questions are very confusing to me, and I cannot find good and simple explanations. Here they are, with my current partial understanding (I fear experts will have a great fun reading this).
Your help to correct and clarify is welcome (remember this is for beginners, not for experts).
Is there something wrong with this understanding?
What is invariance / covariance / contravariance related to in the context of programing? My best guess is that:
This is something encountered in object-oriented programing.
This has to do when looking at method arguments and result type in the class and an ancestor.
This is used in the context of method overriding and overloading.
This is used to establish a connection between the type of a method argument, or the method return type, and the inheritance of the classes themselves, e.g. if class D is a descendant of class A, what can we say about the types of arguments and the method method return type?
How variance relates to Java methods? My best guess is that, given two classes A and D, with A being an ancestor of D, and a overhiden/overloaded method f(arg):
If the relation between the argument type in the two methods IS THE SAME than the relation between the two classes, the argument type in the method is said COVARIANT with the class type, said otherwise: the inheritance between arg types in A and D is covariant with the inheritance of classes A and D.
If the relation between the arguments REVERSES the relation between classes, the arg type is said CONTRAVARIANT to the class type, said otherwise: the inheritance between arg types in A and D is contravariant with the inheritance of classes A and D..
Why is variance understanding so important for Java programmers? My guess is that:
Java language creators have implemented rules for variance in the language, and this has implications on what a programmer can do.
A rule states that the return type of an overriding/overloading method must be contravariant to the inheritance.
Another rule states that the type of an argument of an overriding/overloading must be is covariant to the inheritance.
The Java compiler checks the variance rules are valid, and provides errors or warnings accordingly. Deciphering the messages is easier with variance knowledge.
What is the difference between overrhiding and overloading? Best guess:
A method overrides another method when argument and return types are both invariant. All other cases are understood by the compiler as overloading.
This is not specific to OO, but has to do with the properties of certain types.
For example, with the function type
A -> B // functional notation
public B meth(A arg) // how this looks in Java
we have the following:
Let C be a subtype of A, and D be a subtype of B. Then the following is valid:
B b = meth(new C()); // B >= B, C < A
Object o = meth(new C()); // Object > B, C < A
but the follwoing are invalid:
D d = meth(new A()); // because D < B
B b = meth(new Object()); // because Object > A
hence, to check whether a call of meth is valid, we must check
The expected return type is a supertype of the declared return type.
The actual argument type is a subtype of the declared argument type.
This is all well known and intuitive. By convention we say that the return type of a function is covariant, and the argument type of a method is contravariant.
With parameterized types, like List, we have it that the argument type is invariant in languages like Java, where we have mutability. We can't say that a list of C's is a list of A's, because, if it were so, we could store an A in a list of Cs, much to the surprise of the caller, who assumes only Cs in the list. However, in languages where values are immutable, like Haskell, this is not a problem. Because the data we pass to functions cannot be mutated, a list of C actually is a list of A if C is a subtype of A. (Note that Haskell has no real subtyping, but has instead the related notion of "more/less polymorphic" types.)
Reading the Java online tutorial I haven't understood anything about wildcard capture.
For example:
import java.util.List;
public class WildcardError {
void foo(List<?> i) {
i.set(0, i.get(0));
}
}
Why can't the compiler retain the assignment safely?
It knows that, by executing for instance, the method with an Integer List, it gets from i.get an Integer value. So it tries to set an Integer value at index 0 to the same Integer list (i).
So, what's wrong? Why write Wildcard helper?
why the compiler can't retain the assignment safe? It knows that,by executing for instance, the method with an Integer List, it gets from i.get an Integer value. So it try to set an Integer value at index 0 to the same Integer list (i).
Put differently, why does the compiler not know that the two usages of the wildcard type List<?> in
i.set(0, i.get(0));
refer to the same actual type?
Well, that would require the compiler to know that i contains the same instance for both evaluations of the expression. Since i isn't even final, the compiler would have to check whether i could possibly have been assigned in between evaluating the two expressions. Such an analysis is only simple for local variables (for who knows whether an invoked method will update a particular field of a particular object?). This is quite a bit of additional complexity in the compiler for rarely manifesting benefits. I suppose that's why the designers of the Java programming language kept things simple by specifying that different uses of the same wildcard type have different captures.
why the compiler can't retain the assignment safe?
The compiler doesn't know anything about the type of elements in List<?> i, by definition of ?. Wildcard does not mean "any type;" it means "some unknown type."
It knows that,by executing for instance, the method with an Integer List, it gets from i.get an Integer value.
That's true, but as I said above: the compiler can only know – at compile time, remember – that i.get(0) returns an Object, which is the upper bound of ?. But there's no guarantee that ? is at runtime Object, so there is no way for the compiler to know that i.set(0, i.get(0)) is a safe call. It's like writing this:
List<Foo> fooz = /* init */;
Object foo = fooz.get(0);
fooz.set(0, foo); // won't compile because foo is an object, not a Foo
More reading:
Can't add value to the Java collection with wildcard generic type
Java Collections using wildcard
Generic collection & wildcard in java
Generics - Cannot add to a List with unbounded wildcard
What is the difference betwen Collection<?> and Collection<T>
According to Get-Put principle:
If you have extends wildcard as in List<? extends Something>, then:
1A. You can get from the structure using Something or its superclass reference.
void foo(List<? extends Number> nums) {
Number number = nums.get(0);
Object number = nums.get(0); // superclass reference also works.
}
1B. You cannot add anything to the structure (except null).
void foo(List<? extends Number> nums) {
nums.add(1); Compile error
nums.add(1L); Compile error
nums.add(null); // only null is allowed.
}
Similarly, if you have super wildcard as in List<? super Something>, then:
2A. You can add to the structure which is Something or its subclass.
For eg:
void foo(List<? super Number> nums) {
nums.add(1); // Integer is a subclass of Number
nums.add(1L); // Long is a subclass of Number
nums.add("str"); // Compile error: String is not subclass of Number
}
2A. You cannot get from the structure (except via Object reference).
For eg:
void foo(List<? super Integer> nums) {
Integer num = nums.get(0); // Compile error
Number num = nums.get(0); // Compile error
Object num = nums.get(0); // Only get via Object reference is allowed.
}
Coming back to OP's question, List<?> i is just the short representation for List<? extends Object> i. And since it's a extends wildcard, the set operation fails.
The final piece remaining is WHY the operation fails ? Or why the Get-Put principle in the first place? - This has to do with type safety as answered by Jon Skeet here.
I also find this question hard to understand; splitting the single command into two commands helped me.
Below code is what actually happens in the background when the original method is inspected&compiled, the compiler makes its own local variable: the result of the i.get(0) call is placed in the register on the local variable stack.
And that is - for the understanding of this issue - the same as making a local variable which for convenience I have given the name element.
import java.util.List;
public class WildcardError {
void foo(List<?> i) {
Object element = i.get(0); // command 1
i.set(0, element); // command 2
}
}
When command 1 is inspected, it can only set the type of element to Object (--> upperbound concept, see Matt's answer), as it can not use ? as a variable type; the ? is only used for indicating that the generic type is unknown.
Variable types can only be real types or generic types, but since you don't use a generic type in this method like <T> for example, it is forced to use a real type. This forcing is done because of the following lines in the java specification (jls8, 18.2.1):
A constraint formula of the form ‹Expression → T› is reduced as follows:
[...]
– If the expression is a class instance creation expression or a method invocation expression, the constraint reduces to the bound set B3 which would be used to determine the expression's invocation type when targeting T, as defined in §18.5.2. (For a class instance creation expression, the corresponding "method" used for inference is defined in §15.9.3).
Solution Will Be,
import java.util.List;
public class WildcardError {
private void fooHelper(List<T> i){
i.set(0, i.get(0));
}
public void foo(List<?> i){
fooHelper(i);
}
}
here fooHelper will capture type T of wildcard ? (so as the name wildcard capture).
I think you misunderstand the ? in Generics. It isn't "wildcard capture" at runtime. It is "wildcard capture" at compile time. Since that capture is gone after compilation, the List<?> often becomes List<Object> or a list of some interface or common base class that is the lowest subclass that is shared amongst the instances according to the Generics type.
Because Java had to make the Generics system compatible with non-Generics supporting JVMs, there are no Generics types at runtime. This means that all checks / captures don't exist at runtime. Either the compiler permits a very narrow range of compatible Generics type assignments when it compiles, or it throws an error.
Now if you want to hold a Generics type at runtime, there are approaches. Most of them involve passing the Class object as a parameter into a constructor, which holds it in a field. Then you can refer to the field for the exact passed type. You can entangle this type with your Generics parameters; and by doing so, you can then have the actual type in places in the runtime code where the "Generics type parameters" have been replaced by their most permissive type supported in the real Java type system. I don't recommend doing this for many situations, as it is a lot of work (and not likely to give you much more security); but, occasionally you really do need the type.
I guess your misunderstanding of the restriction comes from substitution of ? for any type, Object or something like that in your mind. But that assumption is not correct, ? in fact means unknown type. So in the following line
fooz.set(0, foo);
you're trying to assign the variable of some type to the variable of unknown type (since the function signature is like void set(int, ?)), which can never be possible, whatever the type of foo would be. In your case the type of foo is Object and you cannot assign it to a variable of some unknown type, which in fact may be Foo, Bar or any other.