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.
Related
I'm quite new in Java, although I have much experience in C++ and other languages. So templates/generics are not something I don't know.
There's something that bothers me though, it is this <?> that I was told I should use everytime I use a generic instance of something when I don't know in advance of which specific type it will be:
Like:
List< MyGeneric > foo; // bad
List< MyGeneric<?> > bar; // good
IntelliJ doesn't barf on me when using the first expression, and I don't understand why it should. My coworkers have expressed that the 2nd expression was much better, but couldn't tell me exactly why.
I mean, what exactly is the difference between these two, apart from the second being explicit about the fact that it is a generic that we manipulate ?
The compiler certainly knows that it is a generic at compile time, so my guess is that the second expression is only better because it tells the programmer that he is manipulating a generic.
Am I right?
Edit: for clarification, I ovbiously use the most restrictive type, like List<MyGeneric<Double>>, whenever I know in advance what I am going to store in there. My question is for when I store unknown types of generics.
Every time? It's not applicable always, and it doesn't always make sense.
Let's describe what that actually is: <?> is an unbound wildcard, which immediately implies two things:
MyGeneric is a generic class, but
You do not know what type it's holding (and it likely doesn't matter).
It is preferable to the first expression in that the first expression always guarantees that you'll be working with a raw type, and you really don't want to use raw types. However, it is a gross overgeneralization to assume that using an unbound wildcard every time would be ideal.
If you actually know or care the type, or know or care about its bounds, use that instead.
Let's give an example of why it's bad to use the first. Assuming MyGeneric is defined like this:
class MyGeneric<T> {
private final T instance;
MyGeneric(T instance) { this.instance = instance; }
T get() { return instance; }
}
The following code would compile and run, but fail at runtime with a ClassCastException:
List<MyGeneric> list = new ArrayList<>();
list.add(new MyGeneric<>("Hello"));
for (MyGeneric instance : list) {
Integer value = (Integer) instance.get(); // Compiles, but fails at runtime.
}
This compiles because you're using raw types: the compiler doesn't know that instance.get() can't return an Integer; it would merely warn you that it might be unsafe.
On the other hand, the following code would not even compile:
List<MyGeneric<String>> list = new ArrayList<>();
list.add(new MyGeneric<>("Hello"));
for (MyGeneric<String> instance : list) {
Integer value = (Integer) instance.get(); // Won't compile, incompatible types.
}
The difference is that a raw type ignores the fact that the class is a generic, while the wildcard <?> specifies that the class is a generic but the type argument is unknown.
Raw means that you lose all compiler type-checking. Wildcard keeps type-checking intact.
Example:
public class MyGeneric<T> {
private T val;
public T get() {
return this.val;
}
public void set(T val) {
this.val = val;
}
}
MyGeneric a = new MyGeneric<Integer>();
a.set("Foo"); // accepted
Setting the value for a to a String when it was declared to be an Integer is accepted by the compiler, because a was defined raw, which means that the compiler is ignoring the fact that the class is a generic. When val is later used as an Integer, the program will crash. It's a bomb waiting to go off.
MyGeneric<?> b = new MyGeneric<Integer>();
b.set("Bar"); // compile error
Trying to set the value for b will not compile:
The method set(capture#1-of ?) in the type MyGeneric<capture#1-of ?> is not applicable for the arguments (String)
Here the compiler knows that the class is a generic and will not allow setting the value to anything (even an Integer), because it doesn't know what type would be allowed (wildcard = unknown, remember?). The compiler safeguards here, as it should.
List<?> means a list typed to an unknown type. This could be a List<A>, a List<B>, a List<String> etc.
Since the you do not know what type the List is typed to, you can only read from the collection, and you can only treat the objects read as being Object instances. Here is an example:
public void processElements(List<?> elements) {
for(Object o : elements){
System.out.println(o);
}
}
The processElements() method can now be called with any generic List as parameter. For instance a List<A>, a List<B>, List<C>, a List<String> etc. Here is a valid example:
List<A> listA = new ArrayList<A>();
processElements(listA);
Following tutorials will further help you to understand it:
https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
http://tutorials.jenkov.com/java-generics/wildcards.html
I have a generic method T foo(T) which, depending on the actual type of the argument, performs different operations. Following is an example that illustrates the same problem. (See below for a description of what I'm actually doing in my code.)
<T extends Number> T foo(T a) {
if (a instanceof Integer) {
return ((Integer) a) + 1;
} else if (a instanceof Double) {
return ((Double) a) + 1;
} else {
throw new IllegalArgumentException();
}
}
This does not violate the requirement of the return type but it is not accepted by javac. The problem is that e.g. the return ((Integer) a) + 1; will only ever be executed when T is Integer but the compiler can't (according to the JLS) infer this and thus expects that a T is passed to return. The expression there is typed as int, which can't be converted to T.
Is there a way to deal with this situation without resorting to an unchecked cast?
What I'm actually doing in my code: In the application, there's a generic interface which is used to encapsulate some value. There are different specialized implementations of that interface for different value types and the method I'm trying to write should dynamically chose the right implementation.
If you are type-checking a at runtime, then you are defeating the point of generics. But generics don't work with mathematical operators anyway, because those operators work with primitives and type parameters work with reference types. Your workaround doesn't work with the compiler because T could be any Number type at compile time, so the compiler can't allow you to return an Integer when it thinks it could be any Number type.
Instead, I would overload two non-generic foo methods -- one with int and one with double. Neither of these methods would be generic, and each would just perform its own operation.
This isn't proper use of generics. You should use method overloading instead
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 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.
I would like to be able to detirmine the return type of my method call at runtime, but I can not seem to be able to get the Type of T.
public <T> T getT()
{
Object t = null;
Class<?> c = t.getClass();
System.out.println(c.getName());
return (T) t;
}
Is there any way to determine the Type of T at runtime in Java?
Your function will throw a NullPointerException, because you call "getClass" on a null pointer (since t is initialized with null). Additionally, generics are used for giving added compile-time type-checking. They do not give you anything special at runtime; generics simply use type Object, but cause the code which uses the generic object to perform implicit casts and also causes the compiler to be aware of how you will use it.
Java generics are a static type checking feature. Attempting to retrieve reflection artifacts from generic parameters is typical of poorly thought out design.
In the question example, there is no guarantee that T is a class or even interface. For example
List<? extends Frogs> list = thing.getT();
If you really want to go down this path (and I strongly suggest you don't, not that I expect you to take any notice), then you can supply a reflection object that is statically related to the generic parameter as an argument:
public <T> T getT(Class<T> clazz) {
Object value = map.get(clazz);
return clazz.cast(value);
}
If you have a generic Class you can write a constructor that takes the type and saves it into a member of your class. This way you can check the Type during runtime. All information that are only in the generics are gone after compiling.