16.1 Standard Annotations: @Override, @FunctionalInterface, @Deprecated, @SuppressWarnings, and @SafeVarargs
Key Takeaways
@Override makes the compiler reject a method that does not override a supertype method, catching mistakes such as equals(Employee).
@FunctionalInterface fails compilation unless the interface has exactly one abstract method, ignoring default, static, private, and public Object methods.
@Deprecated has the since and forRemoval elements, and forRemoval = true triggers removal warnings that @SuppressWarnings("deprecation") does not silence.
@SuppressWarnings requires a value such as "unchecked", "rawtypes", "deprecation", or "removal", and unrecognized names are ignored.
@SafeVarargs is legal only on varargs constructors and on static, final, or private methods, so it fails on a non-final public instance method.
16.1 Standard Annotations: @Override, @FunctionalInterface, @Deprecated, @SuppressWarnings, and @SafeVarargs
Oracle lists annotations among the skills candidates are "also expected" to have, naming five built-in annotations. Each one changes what the compiler checks or reports, so exam questions ask whether code compiles and which warnings appear.
Annotation Syntax in One Minute
An annotation is metadata written with @ before a declaration (class, method, field, parameter, local variable) or a type use. Annotations can have elements:
@Override // marker annotation: no elements
@SuppressWarnings("unchecked") // single element named value: shorthand form
@SuppressWarnings(value = {"unchecked", "rawtypes"}) // array value in braces
@Deprecated(since = "2.0", forRemoval = true) // several named elements
The value = part can be omitted only when the element is named value and it is the only element supplied. Custom annotations are declared with @interface, but the exam focuses on using the standard ones in java.lang, which need no import.
@Override: Ask the Compiler to Verify an Override
@Override makes the compiler confirm that a method overrides or implements a supertype method. If it does not, compilation fails with method does not override or implement a method from a supertype.
class Employee {
int id;
@Override
public boolean equals(Employee other) { return id == other.id; } // COMPILE ERROR: this is an overload
}
The annotation catches the classic equals(Employee) overload mistake from 3.4. It is also legal on methods that implement interface methods. It is illegal on static methods, because static methods are hidden, not overridden: javac reports static methods cannot be annotated with @Override.
@FunctionalInterface: Lock In the Single Abstract Method
@FunctionalInterface asks the compiler to verify that an interface has exactly one abstract method (default, static, private, and public Object methods do not count; see 7.1). An annotated interface with two abstract methods fails with Unexpected @FunctionalInterface annotation. The annotation is optional: an interface with one abstract method is functional either way, but the annotation stops a later edit from silently breaking every lambda that targets it.
@Deprecated: Mark APIs That Should No Longer Be Used
@Deprecated marks a type, method, field, or constructor as discouraged. Since Java 9 it has two optional elements:
| Element | Type | Meaning |
|---|---|---|
since | String | The version in which the API was deprecated |
forRemoval | boolean (default false) | true means the API is scheduled to be deleted |
Using a deprecated API compiles, but javac reports a warning. An ordinary deprecation produces a deprecation note or warning, while forRemoval = true produces a stronger removal warning even without -Xlint, for example [removal] Integer(int) in Integer has been deprecated and marked for removal. Do not confuse the annotation with the Javadoc tag @deprecated (lowercase), which only documents the reason.
@SuppressWarnings: Silence Specific Compiler Warnings
@SuppressWarnings takes one or more warning names and suppresses those warnings inside the annotated declaration:
| Value | Suppresses |
|---|---|
"unchecked" | Unchecked generic operations, such as adding to a raw List |
"rawtypes" | Use of raw types such as List instead of List<String> |
"deprecation" | Warnings for ordinary deprecated APIs |
"removal" | Warnings for APIs deprecated with forRemoval = true |
Rules to remember:
- The
valueelement has no default, so@SuppressWarningswith no argument does not compile. "deprecation"does not suppress removal warnings; code that calls aforRemoval = truemethod needs@SuppressWarnings("removal").- javac ignores names it does not recognize, so a misspelled value compiles but suppresses nothing.
- Put the annotation on the narrowest declaration possible, such as a single local variable, rather than a whole class.
@SafeVarargs: Promise That a Generic Varargs Method Is Safe
A varargs parameter of a generic type, such as T... items, creates a generic array, so javac warns about possible heap pollution at the declaration and at every call site. @SafeVarargs is the method author's promise that the method does not store or expose the array unsafely, and it suppresses those warnings.
The annotation is legal only on methods that cannot be overridden and that actually have a varargs parameter:
| Declaration | @SafeVarargs allowed? |
|---|---|
| Constructor | Yes |
static method | Yes |
final instance method | Yes |
private instance method (Java 9+) | Yes |
| Non-final, non-private instance method | No: Invalid SafeVarargs annotation. Instance method ... is neither final nor private. |
| Method without a varargs parameter | No: Invalid SafeVarargs annotation. Method ... is not a varargs method. |
public class Lists {
@SafeVarargs
static <T> List<T> listOf(T... items) { // legal: static
return Arrays.asList(items);
}
// @SafeVarargs
// public <T> void addAll(T... items) {} // COMPILE ERROR: neither final nor private
}
Quick Comparison
| Annotation | Checked by the compiler | Typical exam question |
|---|---|---|
@Override | Method really overrides | Does equals(Employee) with @Override compile? |
@FunctionalInterface | Exactly one abstract method | Is an interface with toString() plus one method functional? |
@Deprecated | Generates warnings for callers | What do since and forRemoval mean? |
@SuppressWarnings | Silences named warnings | Which value silences a removal warning? |
@SafeVarargs | Placement rules | Which method declarations may use it? |
Declaring and Applying a Custom Annotation
You will mostly apply the built-in annotations, but reading a custom declaration helps with element-syntax questions:
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) // keep it in the class file and visible to reflection
@Target({ElementType.METHOD, ElementType.TYPE}) // allowed on methods and types only
public @interface Audit {
String value(); // required: no default
int priority() default 1; // optional
String[] tags() default {}; // optional array element
}
@Audit("orders") // value shorthand
class OrderService {
@Audit(value = "pay", priority = 3, tags = {"pci", "money"})
void pay() {}
@Audit(value = "refund", tags = "single") // one array element may omit braces
void refund() {}
}
Compile-time rules for annotation elements:
- An element without a
defaultmust be supplied:@Audit(priority = 2)fails withannotation @Audit is missing a default value for the element 'value'. - Element types are limited to primitives,
String,Class, enums, other annotations, and one-dimensional arrays of those; anObjectelement fails withinvalid type for annotation type element. - Default values must be compile-time constants and can never be
null. - Applying an annotation where its
@Targetdoes not allow it, such as@Auditon a local variable here, fails withannotation type not applicable to this kind of declaration. @Retention(RetentionPolicy.RUNTIME)is required if code reads the annotation with reflection, as inOrderService.class.getAnnotation(Audit.class).value(), which returns"orders".
Which method declaration compiles when annotated with @SafeVarargs?
static <T> void print(T item) {}
public abstract <T> void merge(T... items);
public <T> void addAll(T... items) {} in a non-final class
private <T> void collect(T... items) {}
What is the result of compiling this class?
class Point {
int x;
@Override
public boolean equals(Point other) {
return other != null && x == other.x;
}
}
It compiles, and equals(Point) overrides Object.equals(Object).
It fails to compile because equals must be declared final.
It compiles with a warning that equals should accept Object.
It fails to compile because equals(Point) overrides nothing.
Library class Old declares @Deprecated(since = "2", forRemoval = true) public static void gone(). Which annotation on the calling method suppresses the warning javac reports for a call to Old.gone()?
@SuppressWarnings("removal")
@SuppressWarnings("unchecked")
@SuppressWarnings("deprecation")
@Deprecated(forRemoval = false)
Sections you finish are checked off in the contents.