pawinder gupta
pawinder gupta

Reputation: 1265

Java Generics - difference in method declaration

What is the difference between the following two method declarations:

 1. <R> Stream<R> myFunc(Function<? super T, ? extends R> mapper);    
 2. Stream<R> myFunc(Function<? super T, ? extends R> mapper);

For the 2nd declaration to compile, I need to add type parameter to class like this.

public class MyGenericsTest<T, R>

In this case compiler is ensuring that the return type of myFunc is determined at the compile time. The compiler could have known that from the method signature as well. I am confused on why these 2 declarations are treated differently by compiler.

Upvotes: 8

Views: 3655

Answers (2)

ajb
ajb

Reputation: 31699

The second form:

Stream<R> myFunc(Function<? super T, ? extends R> mapper);

really isn't any different from this:

Stream<String> myFunc(Function<? super T, ? extends String> mapper);

to the compiler, except that it uses a different type. The second one returns a stream of String. The first one returns a stream of R, whatever R is. The compiler already knows what String is. For the first one, the compiler has to know what R is, which means it has to be defined somewhere. It can be a generic parameter on an outer class, but it could also be a non-generic class that you import from somewhere else (written by someone who is very bad at coming up with meaningful names).

Keep in mind that although we often use single upper-case letters as generic parameters, that's just a human convention. The compiler just treats it like any other identifier.

But that's why your two examples are so different. The first one is a syntax that defines the method as a generic method with a type parameter that you're calling R. The second one is the exact same syntax as a method that returns Stream<String> or List<Integer> or something.

Upvotes: 1

ortis
ortis

Reputation: 2223

By writing <R> Stream<R> myFunc(Function<? super T, ? extends R> mapper) you are telling the compiler that:

  • R is any class and is local to the method (by starting with<R> at the beginning)
  • The return type is a Stream of R
  • T is a class specified in the type parameter of MyGenericsTest<T> (if you dont specify it, it wont work as the compiler will not know T)

If you change to Stream<R> myFunc(Function<? super T, ? extends R> mapper), R and T are not local (no <R, T> at the beginning of the method) and the compiler expects them to be defined at a class level as MyGenericsTest<T, R>

Upvotes: 11

Related Questions