Lambda expressions are by far the most discussed and promoted feature of Java 8. While I agree that Lambdas are a large improvement I think that some other Java 8 feature go a bit short because of the Lambda hype. In this post I want to show a number of examples from another nice Java 8 feature: Type Annotations.
Type Annotations are annotations that can be placed anywhere you use a type. This includes the new operator, type casts, implements clauses and throws clauses. Type Annotations allow improved analysis of Java code and can ensure even stronger type checking.
Introducing a new type annotation is as simple as defining an annotation with the ElementType.TYPE_PARAMETER target, ElementType.TYPE_USE target, or both targets:
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
public @interface Encrypted { }
Following are the examples of type annotations syntax:
@NonNull List<String> list;
@Email String str2;
@NotNull @NotBlank String str3;
List<@NonNull String> list;
void divideInteger(int a, int b) throws @ZeroDivisor ArithmeticException
@Encrypted File file;
@Open Connection connection
Java Repeating Annotations
In Java 8 release, Java allows you to repeating annotations in your source code. It is helpful when you want to reuse annotation for the same class. You can repeat an annotation anywhere that you would use a standard annotation.
For compatibility reasons, repeating annotations are stored in a container annotation that is automatically generated by the Java compiler. In order for the compiler to do this, two declarations are required in your code.
- Declare a repeatable annotation type
- Declare the containing annotation type
1) Declare a repeatable annotation type
Declaring of repeatable annotation type must be marked with the @Repeatable meta-annotation. In the following example, we have defined a custom @Player repeatable annotation type.
@Repeatable(Players.class)
@interface Player {
String name();
int age();
}
The value of the @Repeatable meta-annotation, in parentheses, is the type of the container annotation that the Java compiler generates to store repeating annotations. In the following example, the containing annotation type is Players. So, repeating @Player annotations is stored in an @Players annotation.
2) Declare the containing annotation type
Containing annotation type must have a value element with an array type. The component type of the array type must be the repeatable annotation type. In the following example, we are declaring Players containing annotation type:
@interface Players {
Player[] value();
}
Java Repeating Annotations Example
Java8RepeatingAnnotation.java
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
// 1. Declaring repeatable annotation type
@Repeatable(Players.class)
@interface Player {
String name();
int age();
}
// 2. Declaring container for repeatable annotation type
@Retention(RetentionPolicy.RUNTIME)
@interface Players {
Player[] value();
}
// 3. Repeating annotation
@Player(name = "Raja", age = 27)
@Player(name = "Ram", age = 30)
@Player(name = "John", age = 25)
public class Java8RepeatingAnnotation {
public static void main(String[] args) {
// 4. Getting annotation by type into an array
Player[] players = Java8RepeatingAnnotation.class.getAnnotationsByType(Player.class);
for (Player p : players) { // Iterating values
System.out.println("Name = " + p.age() + ", age = " + p.age());
}
}
}
Compile the class using javac compiler as follows −
C:\hitechpoints\workspace\java8\src>javac Java8RepeatingAnnotation.java
Now run the Java8RepeatingAnnotation as follows −
C:\hitechpoints\workspace\java8\src>java Java8RepeatingAnnotation
It should produce the following output −
Name = 27, age = 27
Name = 30, age = 30
Name = 25, age = 25