8

Why are generics declared as part of a method? For instance, when creating a method that uses generics, the generics must be included after the method modifiers:

public static <T, K> void delete(AbstractDao<T, K> dao)

The generics portion of a method is not shown as part of a method declaration. According to java documentation, methods contain the following items:

Modifiers—such as public, private, and others you will learn about later.

The return type—the data type of the value returned by the method, or void if the method does not return a value.

The method name—the rules for field names apply to method names as well, but the convention is a little different.

The parameter list in parenthesis—a comma-delimited list of input parameters, preceded by their data types, enclosed by parentheses, (). If there are no parameters, you must use empty parentheses.

Reference: https://docs.oracle.com/javase/tutorial/java/javaOO/methods.html

Community
  • 1
  • 1
mattfred
  • 2,583
  • 1
  • 20
  • 36
  • 1
    It is not stated on that docs but the generics is implied on `return type` of a method. Not sure where to find this on the docs though – Jorge Campos Jul 31 '15 at 17:35
  • 1
    Generics also can be defined at class level. What exactly you want to know? You want us to explain the rationale of making generics part of method declaration or find the place in documentation about generics? – Aivean Jul 31 '15 at 17:38
  • 2
    Notice that https://docs.oracle.com/javase/tutorial/java/javaOO/methods.html is a tutorial that might well be pre-Java5. Should not take that definitions as set in stone. – Javier Jul 31 '15 at 17:47

4 Answers4

10

This is because you have to consider separately generic type parameters declaration and usage.

In a method declaration without the first <T,K>, like this:

public static void delete(AbstractDao<T, K> dao)

the compiler wouldn't know that T and K are supposed to be method type parameters (inferred from the method call). It would expect T and K to be already declared (e.g. imported), because these are usages of generics, not declarations.

That's why you need the declaration <T, K> after the modifiers for the compiler, telling it that T and K are type parameters inferred from the method call.

The problem does not occur when you declare a generic class like this:

public class MyClass<T> {
}

because there is no other meaning T could have here, that can only be a type parameter declaration.


Note: you can also tell the difference between declarations and usages, because you can constrain a type parameter during its declaration, but not during its usage. This is valid:

public static <T extends Pony, K> void delete(AbstractDao<T, K> dao)

While this is not:

public static <T, K> void delete(AbstractDao<T extends Pony, K> dao)

Why isn't the compiler smarter?

You could tell me that the compiler could be smart and it could see that the type is not declared, and deduce it is supposed to be generic. But it would really be a mess if it were so.

In most cases your method won't be generic. In most cases, a parameter like List<Something> would be used where Something is actually defined already. Imagine if you simply forget to import the Something class...

The compiler would assume a generic type parameter, erased by object, and you would not understand why you're not able to use your class's methods etc. It would take some time to realize what's wrong, because the compiler would accept such a declaration.

Joffrey
  • 13,071
  • 1
  • 42
  • 68
2

For a more authoritative and complete source of documentation, you should refer to the Java Language Specification. Specifically in this case section 8.4 on method declarations where they explicitly mention type parameters:

A method declares executable code that can be invoked, passing a fixed number of values as arguments.

MethodDeclaration:

{MethodModifier} MethodHeader MethodBody

MethodHeader:

Result MethodDeclarator [Throws]

TypeParameters {Annotation} Result MethodDeclarator [Throws]

MethodDeclarator:

Identifier ( [FormalParameterList] ) [Dims]

M A
  • 65,721
  • 13
  • 123
  • 159
  • Thanks for the exact reference, but I think this does not really answer the *why* part of the question. – Joffrey Jul 31 '15 at 17:53
  • @Joffrey The JLS answers the OP's question. The type parameters are part of the [method signature](https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.2). – M A Jul 31 '15 at 18:01
  • The JLS says that type parameters are declared in the method signature. It does not say *why*. And the OP's question really is *"Why are generics declared as part of a method?"*. But maybe I just misunderstood the OP's question. – Joffrey Jul 31 '15 at 18:06
1

From http://math.hws.edu/javanotes/c10/s5.html "We need to replace the specific type String in the definition of the method with the name of a type parameter, such as T. However, if that's the only change we make, the compiler will think that "T" is the name of an actual type, and it will mark it as an undeclared identifier. We need some way of telling the compiler that "T" is a type parameter. That's what the < T > does in the definition of the generic class "class Queue< T > { ...". For a generic method, the < T > goes just before the name of the return type of the method" So, the < T > before the method name tells the compiler that the T in the method signature is not an actual type, but a generic.

Lee
  • 41
  • 4
0

Generics is just an abbreviation for “generic types”, that can be expressed for return types or for parameter types (like in your case: AbstractDao<T, K>). And the syntax of the language requires that the type variables specified in the generic types should be declared before the return type of the method, so that they can encompass both return as well as parameter types.

Renzo
  • 24,048
  • 4
  • 43
  • 54