When to use <T> in generic method's declaration - java

What is the difference between this:
T getById(Integer id);
And this:
<T> T getById(Integer id);
Are they not both returning a class with type T?

Yes, but you will have to declare T somewhere. What changes is where you do.
In the first case, T is defined at class level, so your method is part of a generic class and you will have to specialize the class when you declare/instantiate. T will be the same for all methods and attributes in the class.
In the second, T is defined at method level, so it's a generic method. Value for T can (often) be deduced.
In the first case, the scope of T is the whole class, while in the second is the method only.
The second form is used commonly with static methods. Also, the latter has the advantage that the type variable T can be deduced (you don't have to specify it in most cases), while you have to specify it for the former.
Specifically, you will have to use a generic class if some attributes of it depend on T (are of type T, List<T>, etc.).

In the first snippet, T is referring to the type variable declared in the class' type parameter list.
In the second snippet, you are creating a new type variable T (which may shadow the class one), declared in the method parameter list.

The first one returns the type T of the enclosing generic type. For example,
T get(int index);
declared in class List<T> returns the element of type T at the given index of the List<T>.
The second one declares that the method itself is a generic method, whose returned type depends on the way it's invoked. If you invoke it as
String s = theObject.<String>getById(id);
it will return a String. If you invoke it as
Foo f = theObject.<Foo>getById(id);
it will return a Foo. Most of the time, the generic type is inferred automatically by the compiler, so you can simply write
Foo f = theObject.getById(id);
For a concrete example, see
static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp)
which returns the maximum element, of type T, in a collection of T. The type returned by the method depends on the type of the collection passed to the method.

The other answers explain well when its used, I am providing an example
For point 1
class ArrayList<E> {//implementing and extending
public E get(int index) {
}
}
For point 2 : Static utility method
public static <T> List<T> asList(T... a) {
return new ArrayList<T>(a);
}

Related

In java, what is the exact meaning of each type parameter of a generic method in a type introduction?

When we define a generic class, in the type introduction, each type parameter acts as a placeholder for each unique type that will be passed to either the class initializer or a class method. This means I must pass at least two different data types to the BoxA class, defined below.
class BoxA<T, S> {
private T t;
private S s;
public void add(T t, S s) {
this.t = t;
this.s = s;
}
public T getFirst() {
return t;
}
public S getSecond() {
return s;
}
}
I have a very difficult time understanding exactly what type parameters mean for generic methods, because they act differently from generic class type parameters for type introduction. For instance:
class Util {
public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public void setKey(K key) { this.key = key; }
public void setValue(V value) { this.value = value; }
public K getKey() { return key; }
public V getValue() { return value; }
}
I have no idea why the code above works, because if type parameters assume the same role as placeholders as they do for generic class definitions, then the compare method should receive two arguments of differing data types. Instead, each of them receives an argument of type Pair<K, V> which is also a generic class. What I find difficult to understand is the specific role of K and V within public static <K, V> boolean compare(){}. Are they placeholders for individual types of arguments passed into the method? Are they placeholders for type parameters passed to the actual object-type arguments, which is then passed into the method (i.e. Pair<K, V>: I view this as one unique type: class Pair<K, V> that receives two unique type parameters, K and V)? Or do generic methods require a unique type parameter for every variable they access whether they are passed as arguments to the method or arguments to an object, which is then passed into the method?
It's hard to understand what exactly you're asking and what exactly you are confused about; I'll try answering your questions anyway.
Type parameters are placeholders for actual types, no matter whether you use them on a class or on a method. Note that this is exactly the same idea as with regular value parameters: they are placeholders for actual values that you supply when you call a method.
public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2)
This is a method with two type parameters, K and V, and two value parameters, p1 and p2.
When you call this method, you'll have to specify actual types for the type parameters, and actual values for the value parameters. In other words: you'll have to specify what types K and V are and you'll have to pass two instances of class Pair for p1 and p2.
The type parameters are "passed" to the type Pair in this example. So, the declaration of method compare means: I have a method named compare which takes two Pair objects with type parameters K and V. Instead of specifying actual, concrete types, I leave those as parameters. By doing this, you can call compare with any Pair with specific types for K and V.
For example, you can call compare with two Pair<Integer, String> objects. Or two Pair<BigDecimal, Long> objects, etc.
Are they placeholders for individual arguments passed into the method?
They are placeholders for types, just like regular parameters are placeholders for values.
Are they placeholders for type parameters passed to the actual object-type arguments passed into the method(i.e. Pair<K, V> //I view this as one unique type: class Pair<K, V> that receives two unique type parameters, K and V)?
Yes... (if I understand your question correctly). The method signature means that the method takes two Pair<K, V> objects, where you leave specifying the actual types to use for K and V to the caller of the method.
Or do generic methods require a unique type parameter for every variable they access whether they are passed as arguments to the method or arguments to an object, which is then passed into the method?
I don't understand what you mean by this question.
I works, because compiler does something called type erasure. Basically, during compilation compiler translates generics into non-generic code.
Here are docs explaining it in details: https://docs.oracle.com/javase/tutorial/java/generics/erasure.html
First of all, when you say,
When we define a generic class, in the type introduction, each type
parameter acts as a placeholder for each unique type that will be
passed to either the class initializer or a class method.
That is not true. The type variables do not have to be in types that are passed to a constructor or method. It's perfectly valid for the type variables to not be used in the declaration of any constructor or method at all (though they would be pretty useless in that case), or used only in a return type (rare), or the type could be embedded in a more complicated type that is used in a constructor or method. For example, it's perfectly reasonable for your generic class BoxA<T, S> to have a constructor
public BoxA(Pair<T, S> p1, Pair<T, S> p2) {
// ...
}
A generic class promises that (and the compiler checks that) the class works correctly no matter what types are substituted for the type variables, and in fact the class instance doesn't need to know what the type argument is; it is guaranteed that the same code works for all types in the bounds. Similarly, a generic method is a method which has some type variables that are specific to that method itself, and not associated with the type variables of the class instance. It promises that (and the compiler checks that) the method works correctly no matter what types are substituted for the type variables, and the method doesn't need to know what the type argument is.
When you create an instance of a generic class, you do new BoxA<Something, SomethingElse>(), or you use a diamond operator (new BoxA<>()), and the context must be such that the compiler can infer the type arguments. When you call a generic method, you can also explicitly specify the type arguments: Util.<String, Integer>compare(pair1, pair2). However, 99% of the time, you would just write Util.compare(pair1, pair2), and the compiler infers it for you (i.e. it verifies that there exists some choice of type arguments that makes the code valid). That is one of the cool things about generic methods. In rare cases, the inference will produce something that does not compile, and you have to explicitly specify the type arguments.

Instantiating generic type ArrayList<T>

I am new to generics and read in a article "A parameterized type, such as ArrayList<T>, is not instantiable — we cannot create instances of them".
Full quote, from Java in a Nutshell:
A parameterized type, such as ArrayList<T>, is not instantiable - we
cannot create instances of them. This is because <T> is just a type
parameter - merely a place-holder for a genuine type. It is only when
we provide a concrete value for the type parameter, (e.g.,
ArrayList<String>), that the type becomes fully formed and we can
create objects of that type.
This poses a problem if the type that we want to work with is unknown
at compile time. Fortunately, the Java type system is able to
accommodate this concept. It does so by having an explicit concept of
the unknown type which is represented as <?>.
I understand that it should not be instantiable since the concrete (actual) type is not known. If so, why does the below code compiles without an error?
public class SampleTest {
public static <T> List<T> getList(T... elements) {
List<T> lst = new ArrayList<>(); // shouldn't this line return an error?
return lst;
}
}
I know there is a gap in my understanding of generics here. Can someone point out what am i missing here?
Because T is given as another generic type argument.
It's the whole purpose of generics to make the type parameterizeable. So the caller can specify the type. This can be done in multiple layers: the caller may also be generic and let its caller specify the type.
public static void main(String[] args)
{
foo(7);
}
public static <T> void foo(T value)
{
bar(value);
}
public static <U> void bar(U value)
{
baz(value);
}
public static <V> void baz(V value)
{
System.out.println(value.getClass().getSimpleName());
}
It prints out
Integer
A parameterized type, such as ArrayList<T>, is not instantiable
Means: You cannot create ArrayList of an unknown T. It must be specified at compile time. But it can be done indirectly, by another generic. In your case, it's another T, which will be specified again by the caller of your generic getList.
The wildcard <?> is something different. It is used to specify compatibility. <?> is the syntax to avoid specification of the type. You can use extends to require a basetype or interface. However, you cannot create instances with wildcards.
List<?> list = new ArrayList<String>();
list = new ArrayList<Integer>();
This wouldn't be possible otherwise. It makes most sense when using it in parameter specifications, for instance:
public static int foo(List<? extends Comparable> list)
{
return list.get(1).compareTo(list.get(2));
}
It's very confusing of this book. It assumes that <?> somehow solves the problem that a List with unknown T cannot be instantiated. IMHO, this is rubbish. T must be specified to create an instance.
The code that you mention can compile because the Object "lst" is not actually initialized until the method is called. Since the method knows that it will be getting a var-args argument of type T, it can compile in this scenario. Take the example Wrapper class below for example:
public class Wrapper<T> {
public static <T> List<T> getList(T... elements){
List<T> lst = new ArrayList<>();
for(T element: elements) {
lst.add(element);
}
return lst;
}
}
This code can compile because the method hasn't been called. When the method is called, Type T will be the type that we pass as the var-args argument and the code will have no issue compiling. Lets test this in our main method:
public static void main( String[] args ){
System.out.println(Wrapper.getList("Hi", "Hello", "Yo"));
}
And the output is:
[Hi, Hello, Yo]
However, lets generate a compile-time error to see what the article is talking about within our main method:
Wrapper<T> myWrap = new Wrapper<>();
We are actually trying initialize a generic Object of the Wrapper class in the code above, but is unknown. Since the value for the placeholder will be unknown even when we call the method, it results in a compile-time error, whereas creating a List of type T within the getList method does not cause a compile-time error because it will be initialized with a type when the method is called.
once you call the method -> you are using a concrete value.
the method defines T and later you use it in the return type and the parameter list.
public static <T> List<T> getList(T... elements)
once you will send the first parameter from specific type -> the contract will force you for the next parameters.
List<? extends Object> list = getList("", 1); -> in this case java doesnt find common between string and integer so it uses the most basic connection "Object"
List<String> list2 = getList("test", "test2"); -> here you can see that because all of the parameters are Strings - java find that in common and use it as the T.
The specific passage from the book doesn't make any sense and is wrong. new ArrayList<T>() is perfectly fine provided that we are in the scope of a type parameter named T (either a type parameter of a generic class that we are in, or a type parameter of the generic method we are in).
new ArrayList<T>() can no less be instantiated than new ArrayList<String>() -- both compile to the same bytecode and both just instantiate an ArrayList object at runtime. The object doesn't know anything about its type parameter at runtime, and therefore no knowledge of T at runtime is needed to instantiate it. The type parameter in an instantiation expression of a parameterized type (new ArrayList<T>) is just used by the compiler to type-check the parameters passed to the constructor (there are none in this case) and to figure out the type returned by the expression; it is not used in any other way.
And by the way the method does not need to receive any parameters of type T, or of any type containing T, in order for this to work. A method that receives no arguments can still instantiate and return an ArrayList<T> perfectly fine:
public static <T> List<T> emptyList() {
List<T> lst = new ArrayList<T>();
return lst;
}
Also, the section in the book where this statement appears in doesn't really have anything to do with instantiation -- the section is about wildcards, and wildcards don't really have anything to do with object instantiation at all. So I am not really sure why they are mentioning it (incorrectly) there.

When is ti appropriate to use declare generic argumens for the methods instead of simply usinf super class? [duplicate]

As far as I know, using an upper bounded generic and using a superclass as a method parameter both accept the same possible arguments. Which is preferred, and what's the difference between the two, if any?
Upper bounded generic as parameter:
public <T extends Foo> void doSomething(T foo) {}
Superclass as parameter:
public void doSomething(Foo foo) {}
That's an upper bounded type parameter. Lower bounds are created using super, which you can't really do for a type parameter. You can't have a lower bounded type parameter.
And that would make a difference, if you, for example want to pass a List<T>. So, for the below two methods:
public <T extends Foo> void doSomething(List<T> foos) {}
public void doSomething(List<Foo> foo) {}
And for the given class:
class Bar extends Foo { }
The following method invocation:
List<Bar> list = new ArrayList<Bar>();
doSomething(list);
is valid for 1st method, but not for 2nd method. 2nd method fails because a List<Foo> is not a super type of List<Bar>, although Foo is super type of Bar. However, 1st method passes, because there the type parameter T will be inferred as Bar.
Generally, you only need a type variable when it's used in more than one place in class/method/field declarations. When you declare one on a method (rather than a class), the only places to use it are on the parameters and return value of that method.
For example, you can use it on multiple parameters to ensure their types match:
public static <T> void addToList(List<T> list, T element) {
list.add(element);
}
This is a trivial example, but you can see that it prevents you from giving it an element that doesn't match the list's generic type:
List<Integer> list = new ArrayList<>();
addToList(list, 7);
//addToList(list, 0.7); // doesn't compile
//addToList(list, "a"); // doesn't compile
You can also declare a parameter and the return type to be the same type:
public static <T> T nullCheck(T value, T defValue) {
return value != null ? value : defValue;
}
Since this method is returning one of the two T objects it's given, we can safely say that the returned object is also of type T.
Integer iN = null;
Integer i = nullCheck(iN, 7);
System.out.println(i); // "7"
Double dN = null;
Double d = nullCheck(dN, 0.7);
System.out.println(d); // "0.7"
Number n = nullCheck(i, d); // T = superclass of Integer and Double
System.out.println(n); // "7"
As for the example in the question, the type variable is only being used once, so it's equivalent to using the superclass. In this case you should avoid declaring a type variable, it's just unnecessary clutter.
Also I should note that the other answer changes the example to use List<T> and List<Foo>, but as mentioned in the comments, the superclass is really List<? extends Foo>, so no type variable is needed there, either.

Declaring generic methods, clarification needed

Consider the following 2 method declarations:
1. public abstract <T extends MetaData> List<T> execute();
2. public abstract List<? extends MetaData> execute();
Both seem to return back a list of objects that extend MetaData.
What is the difference between them please?
In the first case you will allow Java to use type inference and infer the type of T at each call site.
In the second case you will always get a List<? extends MetaData> and so won't be able to assign it to a variable of any narrower type like List<IntegerMetaData>.
If there are any subtypes of MetaData then the first version can only return an empty list or null. The second version may return a list containing instances of MetaData and its subtypes.
Example: Say A and B are subtypes of MetaData and execute returns a list containing an instance of A. The caller might have called execute like so:
List<B> list = execute(); // the second version does not allow this
The caller said he wanted a list of Bs, but got a list containing an A. Due to type erasure the implementation of execute has no way of knowing what the caller asked for. Thus the first version can't be implemented (except to return null or an empty list).
In example 1, you cannot must return a List whose generic type is T, e.g.:
#Override
public <T extends MetaData> List<T> execute() {
List<T> l = new ArrayList<T>();
return l;
}
In example 2, you can return a List whose generic type is just MetaData, e.g.:
#Override
public List<? extends MetaData> execute2() {
List<MetaData> l = new ArrayList<MetaData>();
return l;
}
What is the difference? In the first case, the method has a generic type, T and you must return something that relates to that type. In the second case, you just return a generic type, but the method itself does not have a generic type.

Java weird generic return type

Browsing through Guava libraries I saw this weird signature on a readLines method from Files class:
public static <T> T readLines(File file,
Charset charset,
LineProcessor<T> callback)
I know a little bit about generics in java, but this baffled me.
What does the double T mean here? And why is the first one in angled brackets?
UPDATE: Thanks for the answers. I am still not clear as to why I should use a T inside the brackets. Why for example can't it just be:
public static <> T readLines()
or
pulibc static <K> T readLines()
Or does the java syntax dictate that the SAME letter must be used?
Now this is even wierder:
static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
how can a method have a generic-return type and be void?
It's a generic method -- the T is called a type parameter, and can represent any type. So if I have a method with this signature:
public <T> T foo(T[] bar)
I can call it on any array, and it will return a single object of the same type. If I pass it a String array, I'll get back a String, and so on. More information in the Sun tutorials for "generic methods".
Edit: In answer to your updated question, bear in mind that the first <T> isn't part of the return type: it's just an indicator that T is a type parameter. So look at the example you quoted:
static <T> void fromArrayToCollection(T[] a, Collection<T> c)
That just means that fromArrayToCollection will accept any array and any collection, but that they must be an array and collection of the same type. So you can pass in a String[] and a Collection<String>, or an Integer[] and a Collection<Integer>, but not a String[] and a Collection<Integer>. No matter what type you put in for T, the method returns nothing.
The first T inside the angle brackets mean that the method itself is generic. The second T is the return type. T can be any type within its bounds. In this case, T has no bounds.
T will be determined at the call site, and in this case, inferred from the LineProcessor<T> parameter.
I am still not clear as to why I should use a T inside the brackets. Why for example can't it just be:
public static <> T readLines()
or
public static <K> T readLines()
Or does the java syntax dictate that the SAME letter must be used?
The <T> or <K> is the type parameter. If you write <K> T, then the T isn't a type parameter - rather, you're using the specific class T. This won't work if you don't have a class that's literally named T in scope.
Now this is even wierder:
static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
how can a method have a generic-return type and be void?
It doesn't; the <T> is not a "generic return type", it's just the type parameter to the method. You're saying that the method is generic, and T is the type parameter. The return type of the method is void.
Instead of being generic at class level only the method readLines uses generics.
The first <T> declares the generic types used by the method
The following T is the return type.
The first one uses the same syntax as a generic class to declare the generic types. Instead you could write
class Generic <T>
{
public static T readLines(File file,
Charset charset,
LineProcessor<T> callback)
}
This however would make all instances of the class generic.
Extended Example:
public static <ElementType,ListType extends List<ElementType>> ListType add(ListType list,ElementType elem)
{
list.add(elem);
return list;
}
ArrayList<String> = add(add(new ArrayList<String>(),"Hello"),"World");
The method adds a given Element to a List and returns the List.
The method uses two generic Types one for the elements of the list and one for the list itself.
The names used are nothing special, using a T for a generic type is like using i for an integer.
ElementType is the name used for the generic Type of the elements (any valid variable name / identifier could be used)
ListType is the name for the generic list Type, the classes used have to extend/implement List for the ElementType.
The example calls the method with:
ElementType = String
ListType = ArrayList
which would result in
public static ArrayList<String> add(ArrayList<String> list, String elem)
Bloat end :-)
This is a generic method.
Actually there are three Ts, the third on LineProcessor<T> specifies T when you use the method.

Categories