Skip to main content

Introduction to Java 8 type annotations and why would you need it?

Java 8 brought many new features like Lambda, functional interfaces and Streams but there is one feature that is not much talked about and that is "type annotations". Who's this new kid on the block? Let's take a look.

What are type annotations?

Java introduced a new feature called annotations in Java 5. Java had some built in like @Override and then the specifications and Frameworks created their own annotations like @Entity, @Autowired etc as well. All these were used as metadata for verification or for code generation in some cases. These annotations were only applied to the declarations - when classes, methods and fields were declared.

What Java 8 brings to the table is type annotations which means these annotations can be used anywhere where the type has been used, for example while accepting an argument in the method definition, you can specify that this argument value cannot be null using a type annotation like @NotNull shown below.

String myMethod(@NotNull someComplexObject){
    .
    someComplexObject.someMethod( );  
    .
    .

}

Call to someMethod( ) would throw compilation error if there is a possibility of myMethod invocation with null parameter and if null check for someComplexObject hasn’t been made before this call.

An important part to understand here is this, these type annotations are only provisions from Java and actual implementations aren’t provided by the compiler. So Java 8 doesn’t have @NotNull built into it. You have to write yourself what that means which means you yourself would define what to check when @NotNull is encountered. Now there are already some libraries/frameworks that provide a wide variety of type annotations that can be useful, the most famous one is Checker Framework which was developed in parallel with the type annotations’ JSR - JSR 308 specification. Checker Framework has @NonNull type annotation ready for your use.

You yourself can also write your own for your own business complexities, there is a good example given in the below article for how two type annotations @BasisPoints and @Percent can be used to identify the values correctly, because the stock’s movement is represented in percentages but the change in interest rates is represented in Basis Points(1/100th part of 1%). This is a good article to read and understand type annotations better: https://www.infoq.com/articles/Type-Annotations-in-Java-8/

Why we need type annotations?

Type annotations make our code more robust and help us with type checking. Java already has Generics for type safety and type annotations take it a step further and also gives us the freedom to define our own checks.

How does it works internally?

Java’s compiler does not check user-defined annotations. Instead, the Java platform exposes two APIs, the Java Compiler Plug-in and Pluggable Annotations Processing APIs, so that 3rd-parties can develop their own analyses - that’s what Checkers Framework and other frameworks do. They run the checks during compilation using Java’s Compiler API.

Conclusion

Type annotations are a step towards meta-programming to boost developers productivity by enforcing type checking and catching variety of issues at compile time. This includes business domain checks because type annotations enable us to write our own type annotations and a way to interpret them. Checker framework is one of the most useful libraries out there that can be used.

Good references

Comments

Most liked posts

Hello Chai..!

Chai is the secret ingredient which stirs my thoughts and helps me understand complex technical concepts. Hopefully, I would be able to make things simple for you.. don't leave if it's the other way around.. :)   More to come...  Cheers! Saurabh