- Java Programming Basics
- Java Tutorial
- Java Overview
- Java Environment Setup
- Java Program Structure
- Java Basic Syntax
- Java First Program
- Java Constants
- Java Separators
- Java Keywords
- Java Data Types
- Java Data Types
- Java Integers
- Java Floating Point
- Java Characters
- Java Booleans
- Java Numbers
- Java Programming Variables
- Java Variables
- Java Variable Types
- Java Variable Scope
- Java Type Conversion
- Java Type Casting
- Java Auto Type Promotion
- Java Type Promotion Rules
- Java Programming Arrays
- Java Arrays
- Java One Dimensional Array
- Java Multidimensional Array
- Java Programming Operators
- Java Operators
- Java Arithmetic Operators
- Java Increment Decrement
- Java Bitwise Operators
- Java Left Shift
- Java Right Shift
- Java Relational Operators
- Java Boolean Logical Operators
- Java Ternary(?) Operator
- Java Operator Precedence
- Java Control Statements
- Java Decision Making
- Java if if-else if-else-if
- Java switch Statement
- Java Loops
- Java while Loop
- Java do-while Loop
- Java for Loop
- Java for-each Loop
- Java Nested Loops
- Java break Statement
- Java continue Statement
- Java Class Object Method
- Java Classes and Objects
- Java Class
- Java Object
- Java new Operator
- Java Methods
- Java Constructors
- Java this Keyword
- Java Stack
- Java Overloading Recursion
- Java Method Overloading
- Java Constructor Overloading
- Java Object as Parameter
- Java Call by Value Reference
- Java Returning Objects
- Java Recursion
- Java Modifier Types
- Java Encapsulate Poly String
- Java Encapsulation
- Java Polymorphism
- Java Nested Inner Class
- Java Strings
- Java Command Line Arguments
- Java Variable Length Arguments
- Java Inheritance Abstraction
- Java Inheritance
- Java super Superclass
- Java Multilevel Hierarchy
- Java Method Overriding
- Java Abstraction
- Java Packages Interfaces
- Java Packages
- Java Access Protection
- Java Import Statement
- Java Interfaces
- Java Programming Exceptions
- Java Exception Handling
- Java try catch
- Java throw throws
- Java finally Block
- Java Built In Exceptions
- Java Exception Subclasses
- Java Chained Exceptions
- Java Multithreading
- Java Multithreading
- Java Thread Model
- Java Main Thread
- Java Create Thread
- Java Thread Priorities
- Java Synchronization
- Java Inter Thread Communication
- Java Suspend Resume Stop Thread
- Java Get Thread State
- Java Enum Autobox Annotation
- Java Enumerations
- Java Type Wrappers
- Java Autoboxing
- Java Annotation
- Java Marker Annotations
- Java Single Member Annotation
- Java Built In Annotations
- Java Type Annotations
- Java Repeating Annotations
- Java Data File Handling
- Java Files I/O
- Java Streams
- Java Read Console Input
- Java Write Console Output
- Java PrintWriter Class
- Java Read Write Files
- Java Automatically Close File
- Java Programming Advance
- Java Date and Time
- Java Regular Expressions
- Java Collections Framework
- Java Generics
- Java Data Structures
- Java Network Programming
- Java Serialization
- Java Send Email
- Java Applet Basics
- Java Documentation
- Java Programming Examples
- Java Programming Examples
Java Type Annotations
Beginning with JDK 8, the places in which the annotations can be used has been expanded. As mentioned earlier, annotations were originally allowed only on declarations. However, with the advent of JDK 8, annotations can also be specified in most of the cases in which a type is used. This expanded aspect of annotations is called as type annotation. For example, you can annotate the return type of a method, the type of this within a method, a cast, array levels, an inherited class, and a throws clause. You can also annotate the generic types, including generic type parameter bounds and generic type arguments.
Type annotations are important because they enable tools to perform additional checks on code to help prevent the errors. Understand that, as a general rule, javac will not perform these checks itself. A separate tool is used for this purpose, although such a tool might operate as a compiler plug-in.
A type annotation must include the ElementType.TYPE_USE as a target. From earlier discussions, valid annotation targets are specified using the @Target annotation. A type annotation applies to the type that the annotation precedes. For example, assuming some type annotation called @TypeAnnotat, the following is legal:
void myMethod() throws @TypeAnnotat NullPointerException { // ...
Here, the @TypeAnnotat annotates the NullPointerException in the throws clause.
You can also annotate the type of this (called the receiver). As you know, this is an implicit argument to all the instance methods and it refers to the invoking object. To annotate its type requires the use of another new JDK 8 feature. Beginning with JDK 8, you can explicitly declare this as the first parameter to a method. In the following declaration, the type of this must be the type of its class, for example:
class MyClass { int myMethod(MyClass this, int i, int j) { // ...
Here, because myMethod() is a method defined by MyClass, the type of this is MyClass. Using this declaration, you can now annotate the type of this. For example, again assuming that the @TypeAnnotat is a type annotation, the following is legal:
int myMethod(@TypeAnnotat MyClass this, int i, int j) { // ...
It is important to understand that it is not necessary to declare this unless you are annotating it. If this is not declared, it is still implicitly passed. JDK 8 doesn't change this fact. Also, explicitly declaring this doesn't change any aspect of the method's signature because this is implicitly declared, by default. Again, you will declare this only if you want to apply a type annotation to it. If you do declare this, it must be the first parameter.
The upcoming program shows a number of the places that a type annotation can be used. It defines the several annotations, of which several are for type annotation. The names and targets of the annotations are shown in the following table:
Annotation | Target |
---|---|
@TypeAnnotat | ElementType.TYPE_USE |
@MaxLen | ElementType.TYPE_USE |
@NotZeroLen | ElementType.TYPE_USE |
@Unique | ElementType.TYPE_USE |
@What | ElementType.TYPE_PARAMETER |
@EmptyOK | ElementType.FIELD |
@Recommended | ElementType.METHOD |
Notice that @EmptyOK, @Recommended, and @What are not type annotations. They are included for the comparison purposes. Of special interest is @What, which is used to annotate a generic type parameter declaration and is another new annotation feature added by JDK 8.
Java Type Annotations Example
Here is an example program, demonstrates the type annotations in Java. The comments in the program described each use:
/* Java Program Example - Java Type Annotations * This program demonstrate several type annotations */ import java.lang.annotation.*; import java.lang.reflect.*; /* a marker annotation that can be applied to a type */ @Target(ElementType.TYPE_USE) @interface TypeAnnotat { } /* another marker annotation that can be applied to a type */ @Target(ElementType.TYPE_USE) @interface NotZeroLen { } /* still another marker annotation that can be applied to a type */ @Target(ElementType.TYPE_USE) @interface Unique { } /* a parameterized annotation that can be applied to a type */ @Target(ElementType.TYPE_USE) @interface MaxLen { int value(); } /* an annotation that can be applied to a type parameter */ @Target(ElementType.TYPE_PARAMETER) @interface What { String description(); } /* an annotation that can be applied to a field declaration */ @Target(ElementType.FIELD) @interface EmptyOK { } /* an annotation that can be applied to a method declaration */ @Target(ElementType.METHOD) @interface Recommended { } /* use an annotation on a type parameter */ class TypeAnnotatDemo<@What(description = "Generic data type") T> { /* use a type annotation on a constructor */ public @Unique TypeAnnotatDemo() { } /* annotate the type (in this case String), not the field */ @TypeAnnotat String str; /* this annotates the field test */ @EmptyOK String test; /* use a type annotation to annotate this (the receiver) */ public int fun(@TypeAnnotat TypeAnnotatDemo<T> this, int x) { return 10; } /* annotate the return type */ public @TypeAnnotat Integer fun2(int j, int k) { return j+k; } /* annotate the method declaration */ public @Recommended Integer fun3(String str) { return str.length() / 2; } /* use a type annotation with a throws clause */ public void fun4() throws @TypeAnnotat NullPointerException { // ... } /* annotate array levels */ String @MaxLen(10) [] @NotZeroLen [] w; /* annotate the array element type */ @TypeAnnotat Integer[] vec; public static void myMethod(int i) { /* use a type annotation on a type argument */ TypeAnnotatDemo<@TypeAnnotat Integer> obj = new TypeAnnotatDemo<@TypeAnnotat Integer>(); /* use a type annotation with new */ @Unique TypeAnnotatDemo<Integer> obj2 = new @Unique TypeAnnotatDemo<Integer>(); Object x = new Integer(10); Integer y; /* use a type annotation on a cast */ y = (@TypeAnnotat Integer) x; } public static void main(String args[]) { myMethod(10); } /* use type annotation with inheritance clause */ class MyClass extends @TypeAnnotat TypeAnnotatDemo<Boolean> { } }
Although what most of the annotations in the above program refer to is clear, four uses require a bit of discussion. The first is the annotation of a method return type versus the annotation of a method declaration. In the program, pay special attention to these two method declarations :
/* annotate the return type */ public @TypeAnnotat Integer fun2(int j, int k) { return j+k; } /* annotate the method declaration */ public @Recommended Integer fun3(String str) { return str.length() / 2; }
Notice that in both the cases, an annotation precedes the method's return type which is Integer. However, the two annotations annotate the two different things. In first case, the @TypeAnnotat annotation annotates the fun2()'s return type. This is because the @TypeAnnotat has its target specified as ElementType.TYPE_USE, which means that it can be used to annotate type uses. In second case, the @Recommended annotates the method declaration itself. This is because the @Recommended has its target specified as ElementType.METHOD. As a result, @Recommended applies to the declaration, not the return type. Therefore, the target specification is used to eliminate what, at first glance, appears to be ambiguity between the annotation of a method declaration and the annotation of the method's return type.
One other things about annotating a method return type, you can not annotate a return type of void.
The second point of interest are the field annotations, shown here:
/* annotate the type (in this case String), not the field @TypeAnnotat String str; /* this annotates the field test */ @EmptyOK String test;
Here, @TypeAnnotat annotates the type String, but @EmptyOK annotates the field test. Even though both the annotations precede the entire declaration, their targets are different, based on the target element type. If the annotation has the ElementType.TYPE_USE target, then the type is annotated. If it has ElementType.FIELD as a target, then the field is annotated. Thus, the situation is similar to that just described for the methods, and no ambiguity exists. The same mechanism also disambiguates annotations on the local variables.
Next, notice how this (the receiver) is annotated here:
public int fun(@TypeAnnotat TypeAnnotatDemo<T> this, int x) {
Here, this is specified as the first parameter and is of the type TypeAnnotatDemo (which is the class of which the fun() method is a member). As explained, beginning with JDK 8, an instance method declaration can explicitly specify the this parameter for the sake of applying a type annotation.
Finally, look at how array levels are annotated by the following statement :
String @MaxLen(10) [] @NotZeroLen [] w;
In this declaration, @MaxLen annotates the type of the first level and @NotZeroLen annotates the type of the second level. In this declaration
@TypeAnnotat Integer[] vec;
the element type Integer is annotated.
« Previous Tutorial Next Tutorial »