define a method on the annotation. Despite this, defining new custom annotations
is a remarkably compact undertaking.
In addition to the two primary meta-annotations, there are also the @Inherited and
@Documented meta-annotations. These are much less frequently encountered in
practice, and details on them can be found in the platform documentation.
With the release of Java 8, two new values for ElementType were added—
TYPE_PARAMETER and TYPE_USE . These new values allow the use of annotations in
places where they were previously not legal, such as at any site where a type is used.
This enables the developer to write code such as:
@NotNull String safeString = getMyString ();
The extra type information conveyed by the @NotNull can then be used by a special
type checker to detect problems (a possible NullPointerException , in this exam‐
ple) and to perform additional static analysis. The basic Java 8 distribution ships
with some basic pluggable type checkers, but also provides a framework for allow‐
ing developers and library authors to create their own.
In this section, we've met Java's enum and annotation types. Let's move on, to con‐
sider the next important part of Java's type system: nested types.
The classes, interfaces, and enum types we have seen so far in this topic have all
been defined as top-level types . This means that they are direct members of pack‐
ages, defined independently of other types. However, type definitions can also be
nested within other type definitions. These nested types , commonly known as “inner
classes,” are a powerful feature of the Java language.
Nested types are used for two separate purposes, both related to encapsulation:
• A type may be nested because it needs especially intimate access to the internals
of another type—by being a member type, it has access in the same way that
member variables and methods do, and can bend the rules of encapsulation.
• A type may be only required for a very specific reason, and in a very small sec‐
tion of code. It should be tightly localized, as it is really part of the implementa‐
tion detail and should be encapsulated away from the rest of the system.
Another way of thinking of nested types is that they are types that are somehow tied
together with another type—they don't really have a completely independent exis‐
tence as an entity. Types can be nested within another type in four different ways: