Java Type Annotations #5: var and void

Marcio EndoMarcio EndoFeb 9, 2025

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.