Annotations
1. What Is an Annotation?
-
An annotation is metadata added to Java code.
-
It provides information to:
-
The compiler
-
Development/build tools
-
The runtime
-
-
Annotations do not directly change what your code does; they provide additional information that other tools or the Java runtime can use.
Common uses:
Compiler → detect errors / suppress warnings
Tools → generate code or files
Runtime → inspect metadata
2. Basic Annotation Syntax
An annotation starts with @:
@Override
void print() {
}
Annotations can also have elements:
@Author(name = "John", date = "2026")
class User {
}
If there is only one element named value, its name can be omitted:
@SuppressWarnings("unchecked")
Instead of:
@SuppressWarnings(value = "unchecked")
If an annotation has no elements, parentheses are unnecessary:
@Override
3. Where Can Annotations Be Used?
Annotations can be applied to many Java elements:
Classes
Methods
Fields
Constructors
Parameters
Local variables
Packages
Modules
Type parameters
Record components
Types
Example:
@Deprecated
class OldClass {
}
@Deprecated
void oldMethod() {
}
Since Java 8, annotations can also be applied directly to types:
@NonNull String name;
List<@NonNull String> names;
This is called a type annotation.
4. Creating Your Own Annotation
You can define a custom annotation using @interface:
public @interface Author {
String name();
String date();
}
Then use it:
@Author(
name = "John Doe",
date = "2026"
)
class User {
}
Annotation elements can have default values:
public @interface Author {
String name();
String date();
int version() default 1;
}
Now version is optional:
@Author(
name = "John",
date = "2026"
)
class User {
}
5. Common Built-in Annotations
@Override
Tells the compiler that a method is intended to override a superclass method.
@Override
public void display() {
}
If the method doesn't actually override anything, the compiler reports an error.
@Deprecated
Marks something as old or discouraged from being used.
@Deprecated
void oldMethod() {
}
Using it can produce a compiler warning.
Since Java 9, it can also indicate planned removal:
@Deprecated(forRemoval = true)
void oldMethod() {
}
@SuppressWarnings
Tells the compiler to suppress specific warnings.
@SuppressWarnings("unchecked")
void process() {
}
Multiple warnings:
@SuppressWarnings({"unchecked", "deprecation"})
void process() {
}
@FunctionalInterface
Indicates that an interface is intended to have exactly one abstract method.
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
}
It helps the compiler detect accidental changes that would make the interface non-functional.
@SafeVarargs
Used with certain generic varargs methods to indicate that the method performs no unsafe operations on its varargs parameter.
@SafeVarargs
static <T> void print(T... values) {
for (T value : values) {
System.out.println(value);
}
}
6. Meta-Annotations
Meta-annotations are annotations used to describe how another annotation behaves.
@Retention
Specifies how long an annotation should be retained.
SOURCE → available only in source code
CLASS → stored in .class files
RUNTIME → available at runtime through reflection
Example:
@Retention(RetentionPolicy.RUNTIME)
@interface Author {
String name();
}
@Target
Specifies where an annotation can be used.
@Target(ElementType.METHOD)
@interface Important {
}
Now:
@Important
void doSomething() {
}
is valid, while using @Important on an unsupported element is not.
Common targets include:
TYPE
METHOD
FIELD
PARAMETER
CONSTRUCTOR
LOCAL_VARIABLE
TYPE_PARAMETER
TYPE_USE
@Documented
Specifies that an annotation should appear in generated Javadoc.
@Documented
@interface Author {
String name();
}
@Inherited
Allows a class-level annotation to be inherited by subclasses.
@Inherited
@interface Important {
}
Then:
@Important
class Parent {
}
class Child extends Parent {
}
Child can inherit the annotation from Parent.
@Repeatable
Allows the same annotation to be used multiple times on the same declaration.
@Schedule(day = "Monday")
@Schedule(day = "Friday")
void cleanup() {
}
This is useful when one annotation needs to hold multiple configurations.
7. Type Annotations
Java 8 introduced the ability to place annotations wherever a type is used.
For example:
@NonNull String name;
Inside generics:
List<@NonNull String> names;
On a cast:
String value = (@NonNull String) obj;
These annotations can be used by external tools such as type-checking frameworks to provide additional compile-time checks.
For example:
@NonNull String name;
can communicate:
"name should never be null"
The annotation itself doesn't automatically enforce this unless a tool/framework processes it.
8. Repeating Annotations
Java allows an annotation to be applied multiple times when it is declared with @Repeatable.
Example:
@Schedule(day = "Monday")
@Schedule(day = "Friday")
void cleanup() {
}
A repeatable annotation normally has a container annotation behind it.
Conceptually:
@Schedule
@Schedule
↓
container annotation
↓
stores multiple Schedule annotations
This allows APIs to represent multiple pieces of the same kind of metadata cleanly.
9. Annotations vs. Comments
A comment:
// This method calculates the total
is mainly for humans.
An annotation:
@Override
has a defined meaning that Java tools/compiler/runtime can process.
So:
Comment
→ information for humans
Annotation
→ structured metadata for tools/compiler/runtime
Quick Revision
| Feature | Purpose | Example |
|---|---|---|
| Annotation | Add metadata | @Override |
| Custom annotation | Define your own metadata | @interface Author |
@Override |
Verify method overriding | @Override |
@Deprecated |
Mark old API | @Deprecated |
@SuppressWarnings |
Suppress compiler warnings | @SuppressWarnings("unchecked") |
@FunctionalInterface |
Enforce functional interface | @FunctionalInterface |
@SafeVarargs |
Mark safe generic varargs | @SafeVarargs |
@Retention |
Control annotation lifetime | RUNTIME |
@Target |
Restrict where annotation can be used | METHOD |
@Documented |
Include in Javadoc | @Documented |
@Inherited |
Inherit class annotation | @Inherited |
@Repeatable |
Allow repeated annotations | @Schedule |
| Type annotation | Annotate a type usage | List<@NonNull String> |
In short
Annotation
↓
Metadata about your code
↓
Compiler / Tools / Runtime
↓
Can check, process, generate, or interpret information
The most important distinction to remember is:
@Override tells the compiler something about your code, while custom annotations allow you to define your own metadata that tools or your program can process.