I started reading some article about generics in Java and one thing confused me:
public static <t> T getFirst(List<T> list)
"This method will accept a reference to a List and will return an object of type T."
cool, but what does <t> do (the lower case one, after static)? I tried and failed to understand it...
It should rather be :
public static <T> T getFirst(List<T> list)
So, what does the <T> mean ?
It means that there is a type called <T> for the scope of this method. And the method will return an instance of that type T, also.
How to use it ?
If you pass a List<String> the method should return the first String in the list.
If you pass a List<Integer> the method should return the first Integer in the list.
What's the point of supporting such methods ?
You don't have to overload methods with different signatures, according to the type of the objects in the List and
You don't have to worry that the method will return other type than the type of the objects in the list, which will relief you from the burden of possible casting, for example.
Maybe it is more understandable like this:
public static <T> T getFirst(T something)
In short means that the type T will be a parameter given later when you call the method:
String text = "text";
getfirst(text);
Now the compiler will know that all the T means String here.
Related
I have learned that in compile time generics we use changes to most specific type. so what is the benefit of generics?
for example in this code:
int a=1;
double b = 2.1;
printArray(a,b);
public static <E> void printArray(E first , E second);
in compile time E changes to Number (because the specific parent of int and double is Number)
so what is the benefit of generics when we can write Number instead of E in here?
The purpose of generics is not related to the fact that the generic parameter will be inferred to be the most specific type. The purpose of generic methods is to allow you to write a method that can work with any type and at the same time, maintain type safety.
Your printArray method can not only take Number as arguments, but also String, SomeClass, Object and all sorts of reference types.
At this point you might ask "can't we just write Object as the parameter types?" Sure with the type being Object, the parameter will not only accept all reference types, but the primitives will also be accepted and boxed! So in this specific case, you don't necessarily have to use a generic method.
However, there are times when generic methods shine.
One of these occasions is when the methods work with generic types. For example, this is Optional.ofNullable:
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
It creates a Nullable<T> depending on whether the parameter is null. If this were not generic, it would have to return Optional<Object>. Every time you want to call get or orElse, you need to cast the result to the type you want. If you made a mistake in one of the casts, a ClassCastException might be thrown at runtime. But with generics, the compiler checks the types for you!
Here's another example:
public static <T> T first(List<T> list) { return list.get(0); }
Without generics, you would have to use the raw type List and return an Object. This again creates the problems of casting and reduced type safety.
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.
I came across the following snippet of code that uses generics.
public class Generics<T> {
public static <T> T replaceIfNull(T objectToCheck, T defaultValue) {
return objectToCheck == null ? defaultValue : objectToCheck;
}
public static <T> boolean CheckIfNull(T objectToCheck) {
return objectToCheck == null ? true : false;
}
}
I am having a difficult time truly understanding how generics work, formed and used. I have a high level understanding, meaning that I know the definition of generics. And by the definition my interpretation of this code snippet is that replaceIfNull method checks for null values of any object and then returns a default value (whatever that is). And that CheckIfNull method is similar, in that it checks null value for any object.
But how does this work? Why is the method formed with <T>, which seems to be a type and then there is T following. I do not understand this syntax, <T> T means? And how does T become a type in the parameters? How come this method, for example, could not be written as
public static Object replaceIfNull(Object objectToCheck, Object defaultValue) {
return objectToCheck == null ? defaultValue : objectToCheck;
}
Thank you in advance for your clarification.
Let's start with answering your last question. The method rewrite with Object instead of generics has two drawbacks. First, it will not work with primitives (which might not be a real drawback in this case, since you are checking against null, and primitives cannot take null values, but still...). Second, it will require casting. If , for example, you use this method on two strings, like replaceIfNull(myString, "Default Value"), then you would expect to get a String as an output, right? But instead the method declared to be returning Object; so there is no way for compiler to know that it will return a String, and you will have to do casting every time you use it: `String result = (String) replaceIfNull(myString, "Default Value");' Generics were introduced specifically to fix this situation.
You can think of generics as templates; whatever type you put in the angle braces will be used later in the code whenever you use type parameter. So, <T> means: "Here will go some type; replace T with it everywhere in the code".
And the last question is about the method signature. I think here you mixed up two different methods of using generics - on a class level, and on a method level. Since you've already introduced the type parameter on the class level, there is no need to do it again on a method level, so I think you can safely remove <T> from method declaration.
I suggest you read a more detailed explanation on generics here: http://docs.oracle.com/javase/tutorial/java/generics/
The subject of Generics is very broad and you can read about it extensively on Oracle's website or on Stack Overflow.
Why is the method formed with <T>, which seems to be a type and then there is T following.
This is a generic method. The <T> declares a new type variable with no bounds.
// v return type
public static <T> T replaceIfNull(T objectToCheck, T defaultValue) {
// ^ new type variable ^ type variable used as a type
Within the method body, since the type variable has no bounds, T can, at most, be interpreted as Object. You're only going to have access to method declared in Object on expressions of type T.
Outside the method, ie. in invocation contexts, the type variable T will receive a concrete type value. That is, it will either infer it from its invocation context or it will be provided explicitly.
For example, in
replaceIfNull(someStringVar, otherStringVar);
the type variable T will be bound to String, so all usages of T will be interpreted as String. You could therefore do
String notNull = replaceIfNull(someStringVar, " not null ");
You could also provide the type argument explicitly
Generics.<String>replaceIfNull(nullVar, " not null ");
and now again the type variable will be bound to String.
Note that the type variable T declared at the type level
public class Generics<T>
is completely different from the type variable T declared in the method.
I am refreshing my knowledge on Java generics. So I turned to the excellent tutorial from Oracle ... and started to put together a presentation for my coworkers. I came across the section on wildcards in the tutorial that says:
Consider the following method, printList:
public static void printList(List<Object> list) {
...
The goal of printList is to print a list of any type, but it fails to achieve that goal — it prints only a list of Object instances; it cannot print List<Integer>, List<String>, List<Double>, and so on, because they are not subtypes of List<Object>. To write a generic printList method, use List<?>:
public static void printList(List<?> list) {
I understand that List<Object> will not work; but I changed the code to
static <E> void printObjects(List<E> list) {
for (E e : list) {
System.out.println(e.toString());
}
}
...
List<Object> objects = Arrays.<Object>asList("1", "two");
printObjects(objects);
List<Integer> integers = Arrays.asList(3, 4);
printObjects(integers);
And guess what; using List<E> I can print different types of Lists without any problem.
Long story short: at least the tutorial indicates that one needs the wildcard to solve this problem; but as shown, it can be solved this way too. So, what am I missing?!
(side note: tested with Java7; so maybe this was a problem with Java5, Java6; but on the other hand, Oracle seems to do a good job regarding updates of their tutorials)
Your approach of using a generic method is strictly more powerful than a version with wildcards, so yes, your approach is possible, too. However, the tutorial does not state that using a wildcard is the only possible solution, so the tutorial is also correct.
What you gain with the wildcard in comparison to the generic method: You have to write less and the interface is "cleaner" since a non generic method is easier to grasp.
Why the generic method is more powerful than the wildcard method: You give the parameter a name which you can reference. For example, consider a method that removes the first element of a list and adds it to the back of the list. With generic parameters, we can do the following:
static <T> boolean rotateOneElement(List<T> l){
return l.add(l.remove(0));
}
with a wildcard, this is not possible since l.remove(0) would return capture-1-of-?, but l.add would require capture-2-of-?. I.e., the compiler is not able to deduce that the result of remove is the same type that add expects. This is contrary to the first example where the compiler can deduce that both is the same type T. This code would not compile:
static boolean rotateOneElement(List<?> l){
return l.add(l.remove(0)); //ERROR!
}
So, what can you do if you want to have a rotateOneElement method with a wildcard, since it is easier to use than the generic solution? The answer is simple: Let the wildcard method call the generic one, then it works:
// Private implementation
private static <T> boolean rotateOneElementImpl(List<T> l){
return l.add(l.remove(0));
}
//Public interface
static void rotateOneElement(List<?> l){
rotateOneElementImpl(l);
}
The standard library uses this trick in a number of places. One of them is, IIRC, Collections.java
Technically, there is no difference between
<E> void printObjects(List<E> list) {
and
void printList(List<?> list) {
When you are declaring a type parameter, and using it only once, it essentially becomes a wildcard parameter.
On the other hand, if you use it more than once, the difference becomes significant. e.g.
<E> void printObjectsExceptOne(List<E> list, E object) {
is completely different than
void printObjects(List<?> list, Object object) {
You might see that first case enforces both types to be same. While there is no restriction in second case.
As a result, if you are going to use a type parameter only once, it does not even make sense to name it. That is why java architects invented so called wildcard arguments (most probably).
Wildcard parameters avoid unnecessary code bloat and make code more readable. If you need two, you have to fall back to regular syntax for type parameters.
Hope this helps.
Both solutions are effectively the same, it's just that in the second one you are naming the wildcard. This can come handy when you want to use the wildcard several times in the signature, but want to make sure that both refer to the same type:
static <E> void printObjects(List<E> list, PrintFormat<E> format) {
I just learned about this fine looking syntax
Collections.<String>emptyList()
to get an empty List with elements which are supposedly of type String. Java's source looks like this:
public static final List EMPTY_LIST = new EmptyList<Object>();
:
public static final <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
Now if I code a method in that way where the generic type does not appear in the parameter list, is there any way how I can access the actual class that becomes T?
I'm saying, up to now my approach to code the same thing would have been
private <T> T get(String key, Class<T> clazz) {
// here I can do whatever I want with clazz, e.g.:
return clazz.cast(value);
}
If I removed the clazz-parameter I wouldn't be able to do the cast(). Obviously I could do
return (T) value;
but that gives me the usual warning Type safety: Unchecked cast from Object to T. Ok, #SuppressWarnings("unchecked") helps here, but actually I want to do something with the intended return type of the method. If I add a local variable
T retValue;
I'd have to initialise it with something, null doesn't help. After I assign it like
#SuppressWarnings("unchecked")
T retValue = (T) value;
I could do, e.g.
retValue.getClass().getName()
but if the cast fails I end up with no information about T again.
Since Java (or at least my Java 6) does not have the generic info any more during runtime, I currently can't think of a way to do this. Is there a way? Or do I have to stick with my "old" approach here?
Please note that the example I lined out is very simple and doesn't make much sense. I want to do more complicated stuff here, but that's out of the scope.
If you want the generic type at runtime you need to either have it as a field or create a sub-class of a type for a specific combination of types.
e.g.
List<String> list = new ArrayList<String>() {}; // creates a generic sub-type
final Class type = (Class) ((ParameterizedType) list.getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
System.out.println(type);
prints
class java.lang.String
You can't, unfortunately. All generics and type parameters are erased in runtime. So in runtime the type of your T is simply Object
retValue.getClass().getName() will always return the runtime type of the object and not the class name of the parameter type.
If you want to grab the parameter class, there's no other way than to use your first solution. (That is, pass the class object explicitly.)
As you mentioned, Java generics are build time only. They are not used at run time.
Because of this, the old approach you were using will be your only way to accomplish this.
I find out that there is one solution for getting Class<?> from T:
public class Action<T>{
}
public Class<?> getGenericType(Object action) throws ClassNotFoundException{
Type type =
((ParameterizedType)action.getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
String sType[] = type.toString().split(" ");
if(sType.length != 2)
throw new ClassNotFoundException();
return Class.forName(sType[1]);
}
The usage of code above:
Action<String> myAction = new Action<String>();
getGenericType(myAction);
I did not tested this with primitive types (int, byte, boolean).
I think that it is not very fast, but you do not have to pass Class<?> to constructor.
EDIT:
The usage above is not right, because generic superclass is not available for Action<String>. Generic super class will be available only for inherited class like class ActionWithParam extends Action<String>{}. This is reason why I changed my mind and now I suggest to pass class parameter to constructor, too. Thanks to newacct for correction.