What are the use cases of generic non-static methods? - java

What is a valid use case for having a non-static method generic without having the class itself generic already?
Example:
public class A {
<T> T someMethod(T param) {
//use case?
}
}
As shown above, the class is not parameterized, but the method is. When such structure can be used?
Please note that the above code is just an example. I am okay with all return types or parameters. I am just interested in a valid use case for a generic non-static method.

One use case is to infer compile-time type, but that would require your method to have actual return type, not just void.
Here is an example from GSON
public <T> T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException {
if (json == null) {
return null;
}
return (T) fromJson(new JsonTreeReader(json), typeOfT);
}

What are the use cases of generic non-static methods (if class itself
is not generic)?
One important use of this method signature is illustrated by the type safe heterogenous container pattern. This pattern is useful in situations for which the container can represent many types (not just one single type, as is the case for List<E>). In this pattern, the value's key is made generic instead of the container.
Here is the API for a type safe heterogenous container, taken from Essential Java, 2nd Ed. J. Bloch:
// Typesafe heterogeneous container pattern - API
public class Favorites {
public <T> void putFavorite(Class<T> type, T instance);
public <T> T getFavorite(Class<T> type);
}
This container maps keys, which are generic, to values whose type is represented by its corresponding key. This pattern exploits the fact that the Java Class class was made generic in Java 5. The generic Class<T> objects are used as run time type tokens which provide both compile-time and run-time type information for the corresponding values.
To store "favorite" String and Integer objects in the map, a client would write:
myFavs = new Favorites();
myFavs.putFavorite(String.class, "My Favorite String");
myFavs.putFavorite(Integer.class, Integer.valueOf(12345));
Note how the class literals are used as run-time type tokens which can then be used to restore the correct type to each value when it is retrieved from the map:
String myFavString = myFavs.getFavorite(String.class);
int myFavInt = myFavs.getFavorite(Integer.class);
The type safe heterogenous container pattern, which is extendible to other kinds of data structures (eg. a row from a database, each column of which may have a different type), allows designers to implement data structures with an arbitrary number of unrelated types in a type safe way.
This is made possible by the fact that instance methods can be made generic.

public class A {
<T> T someMethod(T param) {
//use case?
}
}
Here if class it self is not generic, so you will be creating object of A as A a = new A();, but if there a requirement such that the someMethod in A should have generic parameter, in that case you will be using generics.
Example of such class can be, it I have Calc class which as add method.
class Calc {
<T> T add(<T extends Number> param1, <T extends Number> param2) {
return param1 + param2;
}
}
Here the above method can accept parameter which extends Number class only and it will return type that you have provided as parameter. Hence code will be more type safe.
Calc c = new Calc();
int a = 1;
int b = 2;
calc.add(1, 2) // returns int 3

Related

What is the purpose of additional diamond parameters in a method signature (that look like an additional return type(s))? [duplicate]

This question already has answers here:
What does the type parameter <T> in the method definition mean? [duplicate]
(1 answer)
What are Generics in Java? [closed]
(3 answers)
Java Generics: Generic type defined as return type only
(6 answers)
Understanding generic parameters with void return types
(5 answers)
Closed 10 months ago.
I have the following class which builds:
public class Test<T> {
public T DoSomething(T value) {
return value;
}
}
I can also define it like this class like this (notice the extra in the DoSomething signature (which also builds):
public class Test<T> {
public <T> T DoSomething(T value) {
return value;
}
}
What is its purpose and when do I need to include it? I am asking about the additional <T> in the return type, not what generics are.
Maybe this will clear it up. The notation <T> declares a type variable.
So we have one variable T at the class level, and a redeclaration of that same symbol for a particular method.
class Test<T> {
<T> T doSomething(T value) {
// <T> declares a new type variable for this one method
System.out.println("Type of value: " + value.getClass().getSimpleName());
return value;
}
T doSomethingElse(T value) {
// T is not redeclared here, thus is the type from the class declaration
System.out.println("Type of value: " + value.getClass().getSimpleName());
return value;
}
public static void main(String... a) {
Test<String> t = new Test<>();
t.doSomething(42);
t.doSomething("foo"); // also works
t.doSomething(t); // contrived, but still works
t.doSomethingElse("hi");
t.doSomethingElse(42); // errors because the type `T` is bound to `String` by the declaration `Test<String> t`
}
}
In main, I create a Test<String> so the class-level T is String. This applies to my method doSomethingElse.
But for doSomething, T is redeclared. If I call the method with an Integer arg, then T for that case is Integer.
Really, it would have been better to call the second type variable anything else at all, on the declaration of doSomething. U, for example.
(In most cases, I actually favour giving useful names to type variables, not just single letters).
The concept is known as a generic method (docs.oracle.com).
In the code presented, we have an especially tricky case of generics since we have two generic parameters with the same name:
the <T> on the class-level: public class Test<T>, and
the <T> on the method-level: public <T> T DoSomething(T value)
The latter hides the former within the scope of the method DoSomething(...), just like a local variable would hide an instance field with the same name. In general, I would advice against this type of "hiding" since it makes the code harder to read and understand. Thus, for the rest of the discussion we will work with this (slightly modified) version of the code:
public class Test<T> {
public T doSomethingWithT(T t) {
return t;
}
public <U> U doSomethingWithU(U u) {
return u;
}
}
The scope of the class-level generic parameter T is for the whole class, while the scope of the method-level generic parameter U is only for the one method it is delared on. This will lead to the following observation:
// T is bound to type String for the instance testString:
final Test<String> testString = new Test<>();
final String tString = testString.doSomethingWithT("Hello");
System.out.println(tString); // prints "Hello"
// will not compile since 1 is not a String:
// int tInt = testString.doSomethingWithT(1);
// For this one invocation of doSomethingWithU(...), U is bound to
// type String:
final String uString = testString.doSomethingWithU("World!");
System.out.println(uString); // prints "World!"
// for this one invocation of doSomethingWithU(...), U is bound to
// type Integer:
final int uInt = testString.doSomethingWithU(1);
System.out.println(uInt); // prints "1"
Ideone demo
Notice that, although doSomethingWithU(...) is a generic method, we did not have to specify the generic parameter, the compiler inferred the type for us. While seldom used, we can also explicitly specify the generic parameter for thie method:
final Test<String> testString = new Test<>();
final Number number = testString.<Number>doSomethingWithU(1);
System.out.println(number);
Ideone demo
(In this example, the explicit generic parameter is not necessary, the code works without it aswell, but there are rare cases where this may be useful or even necessary.)
The following is not strictly necessary to understand generic methods, but more of a curiosity one might find in code and is meant to prime the reader that it is bad practice, should not be used and removed when seen.
It should also be mentioned that the JLS allows us to add generic method parameters on method invocations that do not have any generic parameter. Those parameter do not have any effect:
Object o = new Object();
// Method "hashCode()" on "Object" has not generic parameters, one
// can "add" one to the method invocation, it has no effect on the
// semantics, however
int hash = o.<String>hashCode();
Ideone demo
A remark on the code: In Java, methods should be written in camelCase instead of CamelCase (DoSomething(...) -> doSomething(...))

How to return the same generic Collection-type with different element-type?

I have a method, that maps elements of a collection to other object and returns a collection containing the mapped elements. I want the returned Collection to be of the same Collection-type as the input Collection, but with a different element type.
My method would look something like this:
<E extends OriginalElement, T extends TargetElement,
C extends Collection<E>, R extends C<T>> R map(C elementsToMap) {
// snip
}
Obviously the part R extends C<T> doesn't work.
How can I specify that return type to be the same subclass of Collection as Type C, but with element type T instead of E?
You can't, I don't think, because e.g. ArrayList<String> and ArrayList<Integer> are essentially unrelated types.
Plus, when you say "same generic Collection-type", do you mean:
"if I give you some subclass of ArrayList, you'll give me back an instance of java.util.ArrayList"; or
"if I give you a specific subclass of ArrayList, you'll give me back an instance of the same specific subclass of ArrayList"?
Not only is that hard, because in general you don't know how to instantiate arbitrary subclasses, you might not be able to create such an instance, for example if the input is an IntegerArrayList (extends ArrayList<Integer>), and you want to map the elements to Strings. So, whilst you could return a java.util.ArrayList<String> in that case, you can't have a generic solution because you need some knowledge of "which type to instantiate in this specific case".
I am going to make an unquantified assertion that a small handful of collection types can handle most cases. So, provide overloads for these specific types:
</* type variables */> ArrayList<T> map(ArrayList<E> input) { ... }
</* type variables */> HashSet<T> map(HashSet<E> input) { ... }
</* type variables */> ImmutableList<T> map(ImmutableList<E> input) { ... }
// etc.
and then provide a general method for the other cases, and leave it up to callers to specify the collection type they want:
</* type variables */> Stream<T> map(Collection<E> input) { ... }
and then call the general method from the specific methods:
</* type variables */> ArrayList<T> map(ArrayList<E> input) {
return map((Collection<E>) input).collect(toCollection(ArrayList::new));
}
// etc.

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.

How to get return type from any Method with Guava?

What I understand from the official Guava's TypeToken wiki is we can get the return type of a method even if it is defined by a type argument. But I cannot manage to retrieve the returned type of a Method.
If I have an instanced List<String>, how can I do to get String.class from the get() method instead of E?
I know Java does type erasure during compile-time (i.e. the type argument is not available during runtime). Maybe I'm wrong, and Guava cannot retrieve the expected type of a method from a instanced class...
If you can get a TypeToken<List<String>>, you can get the return type of its get method (as shown in the example). But if you have some arbitrary List<?> instance, you won't be able to get a TypeToken representing the actual type of that list (e.g. List<String>) because that information doesn't exist at runtime.
As ColinD and Louis Wasserman have mentioned, generic type erasure does not erase generic type information about the super class. Here is also an interesting blog post about it.
The trick is to extend a class that declares generic type. This allows to use getGenericSuperclass() to retrieve generic type information.
private static class AnyClassWithGenerics<A, B, C> {
}
private static class SomeObject extends AnyClassWithGenerics<String, Number, ArrayList<Integer>> {
}
public static void main(String[] args) throws Exception {
Type genericSuperclass = SomeObject.class.getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedTypeImpl) {
for (Type type : ((ParameterizedTypeImpl) genericSuperclass).getActualTypeArguments()) {
System.out.println(type);
}
}
}
Above code produces this result:
class java.lang.String
class java.lang.Number
java.util.ArrayList<java.lang.Integer>
The only ugly thing is that cast and I did not investigate under what conditions getGenericSuperclass() returns object of ParameterizedTypeImpl type.

I'm studying Head First Java, but I can't understand Page 544

"When you declare a type parameter for the class, you can simply use that type any place that you'd use a real class or interface type. The type declared in the method argument is essentially replaced with the type you use when you instantiate the class.
If the class itself doesn't use a type parameter, you can still specify one for a method, by declaring it in a really unusual (but available) space-before the return type, This method says that T can be "any type of Animal"."
Can you explain?
What it means is that in a generic class, you can write methods like so:
public T doSomething () {
}
Note that the return type is 'T'.
At compile-time, the return type of that method will be whatever you have passed to the generic class when you instantiated it.
class Zoo<T> {
static void putAnimal(T animal) {
// do stuff
}
}
Zoo<Ape> apeZoo = new Zoo<Ape>(); // you can now put apes (and chimps) here
Zoo<Reptile> monkeyZoo = new Zoo<Reptile>(); // this zoo takes reptiles
apeZoo.putAnimal(new Chimp());
monkeyZoo.putAnimal(new Tortoise());
For the first paragraph, this is just how generics work for classes. For instance, for list, you can create a list of a generic type, such as integer, e.g.:
ArrayList<Integer> list = new ArrayList<Integer>();
(in real code you'd use List<Integer> of course)
Now ArrayList will be defined as:
public class Arraylist<T> { // implements....
// ...
public T get(int index) {
// ...
}
}
Which is what makes it possible to use the get method on list and get an Integer (because we made a class of type ArrayList<Integer> so T = Integer). Otherwise the compiler would have no idea what types of objects the list was storing and you'd have to get the method to return an Object, which is how it used to be.
What the second paragraph means is that you can add type parameters to methods just as you can to classes. e.g.:
public <T> void noOp(T element) {
// code here
}
This would allow you, for instance, to create a static utility method that returns something of type T. To return the first element of a List of T's:
public static <T> T getFirst (List<T> list) {
return list.get(0);
}
And you could use this method in a strongly typed fashion. Suggestions for better examples welcome. :-)
edit: I just realised I once wrote something that uses this functionality. I was using the JPA API and getting really annoyed at all the times you have to return something (a list, or a single item) from a query, and running into unchecked type warnings because there's no way to infer the type here. If you're like me and trying to avoid warnings in your code, you'd have to suppress the warnings every single time. So I wrote this method to suppress the warnings for me:
#SuppressWarnings("unchecked")
public static <T> List<T> returnResultList(Query query) {
return (List<T>)query.getResultList();
}
Which through the magic of type inference works on:
List<Integer> list = returnResultList(query);

Categories