Java Type Annotations #5: var and void

In the Java Programming language, type annotations are those which can be applied to the use of a type.
When we declare a LocalDate
local variable named today
, for example, we are using the LocalDate
type;
we can annotate its use with type annotations, if we so desire.
Similarly, when we declare that the method computeTotal
returns a BigDecimal
object, we are using the BigDecimal
type.
So, the BigDecimal
return type can also be annotated with type annotations.
In this blog post, we'll see two cases when type annotations cannot be used.
The first is local variables declarations which use the var
keyword.
The second is void
method declarations.
Local-Variable Type Inference
Let X
be an annotation defined like so:
@Target(ElementType.TYPE_USE)@interface X {}
From its definition, we can see that X
is a type annotation as it targets types only.
We can use it to annotate the type of a local variable declaration, for example:
@X LocalDate now = LocalDate.now();
In the code above, our annotation X
applies to the LocalDate
type of the now
local variable declaration.
It compiles without errors.
However, if we change our local variable declaration to use the var
keyword instead:
// compilation error@X var now = LocalDate.now();
Then our code fails to compile with the following error message:
TypeAnnotations5.java:18:
error: annotation interface not applicable to this kind of declaration
@X var now = LocalDate.now();
^
While we know for sure that the now
variable refers to a LocalDate
object,
the type of the variable has not been declared explicitly.
Instead, the type of variable is being inferred;
and we cannot annotate it with a type annotation.
Using a Declaration annotation
We can still use a declaration annotation in our var
example.
In other words, if Y
is annotation defined like so:
@Target(ElementType.LOCAL_VARIABLE)@interface Y {}
We can use it to annotate our today
variable declaration:
@Y var today = LocalDate.now();
Here, the Y
annotation applies to the local variable declaration itself, and not to the type of the declaration.
It's All In the JLS
It is all defined in the Java Language Specification (JLS). In Section 9.7.4, titled "Where Annotations May Appear", we find the following (emphasis mine):
If the annotation appears before a void method declaration or a variable declaration that uses var (§14.4, §15.27.1), then there is no closest type. If the annotation's interface is deemed to apply only to the type which is closest to the annotation, a compile-time error occurs.
In other words, the compilation error we saw earlier is defined in the language spec.
Next, we'll quickly discuss void
method declarations.
void Method Declarations
We cannot use type annotations on void
method declarations.
Simply put, a void
method declaration has no return type.
Once again, we can still annotate a method with a declaration annotation.
In other words, if T
and M
are the following annotations:
@Target(ElementType.TYPE_USE)@interface T {}@Target(ElementType.METHOD)@interface M {}
Then this method declaration:
// compilation error@T void foo() {}
Fails to compile because:
-
The
T
annotation targets types only. -
The
foo
method does not declare a return type.
On the other hand, the following method declaration:
@M void foo() {}
Compiles without errors because the M
annotation applies to the method declaration itself.
It should be noted that type annotations can still be used in the following elements of a void
method declaration:
-
The receiver parameter.
-
The type of a formal parameter.
-
The types listed in the
throws
clause.
Conclusion
Type annotations can be used on local variable declarations.
In this case, these annotations apply to the type of the local variable.
However, if the local variable declaration uses the var
keyword, then type annotations cannot be used.
When using the var
keyword, there's no declared type; instead, the type of the variable is inferred by the compiler.
Type annotations can also be used on method declarations.
In this case, these annotations apply to the return type of the method.
If the method declaration has no return type, in other words, if it is a void
method declaration,
then type annotations cannot be used.