The compiler will issue a warning about this method. It’ll warn that we’re using a raw-typed collection. If we don’t want to fix the warning, then we can suppress it with the @SuppressWarnings annotation.

This annotation allows us to say which kinds of warnings to ignore. While warning types can vary by compiler vendor, the two most common are deprecation and unchecked.

deprecation tells the compiler to ignore when we’re using a deprecated method or type.

unchecked tells the compiler to ignore when we’re using raw types.

So, in our example above, we can suppress the warning associated with our raw type usage:

To suppress a list of multiple warnings, we set a String array containing the corresponding warning list:

@SuppressWarnings({"unchecked", "deprecated"})

3.3. @Deprecated

As a project evolves its API changes. Over time, there’re certain constructors, fields, types or methods that we don’t want people to use anymore.

Instead of breaking the backward compatibility of the project’s API, we can tag these elements with the @Deprecated annotation.

@Deprecated tells other developers that the marked element should no longer be used. It’s common to have a Javadoc accompany the @Deprecated annotation to explain what would be a better alternative that serves the right behavior:

Remember that a compiler only displays the deprecated API warning if the given Java element is used somewhere in the code. So, in this case, it’d only show if there was code that called the calculate method.

Also, we can communicate deprecated status in documentation as well by using the Javadoc @deprecated tag in the method description.

3.4. @SafeVarargs

Java 5 introduced the concept of varargs, or a method parameter of variable length, as well as parameterized types.

Now, this would’ve compiled without the @FunctionalInterface annotation. So, what does it give us?

Like @Override, this annotation protects us against future programmer error. Even though it’s legal to have more than one method on an interface, it isn’t when that interface is being used as a lambda target. Without this annotation, the compiler would break in the dozens of places where Adder was used as a lambda. Now, it just breaks in Adder itself.

4. Meta-Annotations

Next, meta-annotations are annotations that can be applied to other annotations.

For example, these meta-annotations are used for annotation configuration:

@Target

@Retention

@Inherited

@Documented

@Repeatable

4.1. @Target

The scope of annotations can vary based on the requirements. While an annotation is only used with methods, another annotation can be consumed with constructor and field declarations.

To determine the target elements of a custom annotation, we need to label it with a @Target annotation.

@Target can work with eight different element types. If we look at the source code of @SafeVarargs, then we can see that it must be only attached to constructors or methods: