Enums and Annotations

Two special-purpose families of reference types: Enums and Annotations.
Item 34: Use enums instead of int constants
int constants
public static final int APPLE_FUJI = 0;
Disadvantages:
- No type safety (other values can be used, even if not present in enum)
- Expressiveness (nothing descriptive printed in logs, only values)
- No namespace (prefix required)
- Constant variables -> compiled (high coupling) to client code -> brittle programs
- Performance problems (
Stringconstants uses string comparison)
Java enum
They are full-fledged classes and much more powerful than the ones provided by C, C++ or C#.
Basic Idea:
- export each instance via
public static finalfield - no accessible constructor => effectively final => no instantiation or extension (they implicitly extend
java.lang.Enumthus no more extensions possible) - instance controlled
- generalization of Singletons
Advantages:
- compile-time type safety
- namespace, same names can co-exist with different namespace
- add or reorder constants, without recompiling clients
- descriptive printable strings
- add associated, arbitrary methods, fields, implement interface
- high quality implementation of
Objectmethods,implements Comparable, Serializable - useful
staticmethods likevalues(),valueOf(),name()etc.
constant-specific method implementations:
- declare an
abstractmethod inenumand override it in the constant with constant-specific implementation. - to allow reuse we can provide a default implementation instead and override only when needed.
- prefer this instead of switch statements, as they have to changed every time, someone may just forget
- consider the strategy enum pattern if some, but not all, enum constants share common behaviours (can use
privatenested enum for this).
switch in enum
- augmenting enum types with constant-specific behavior, useful if enum not in our control
- if enum is in control, but method doesn't belong in enum type
enum constructors can't access static fields except constant variables because when constructor is being executed the static fields wouldn't have initialised. Similarly, enum constants can't access other enum constants from their constructor.
Item 35: Use instance fields instead of ordinals
Never derive a value associated with an enum from its ordinal; store it in an instance field instead. The Enum specification has this to say about ordinal: “Most programmers will have no use for this method. It is designed for use by general-purpose enum based data structures such as EnumSet and EnumMap.”
Item 36: Use EnumSet instead of bit fields
The EnumSet class combines the conciseness and performance of bit fields with all the many advantages of enum types. It extends the Set interface.
Item 37: Use EnumMap instead of ordinal indexing
It is rarely appropriate to use ordinals to index into arrays: use EnumMap instead. If the relationship you are representing is multidimensional, use EnumMap<..., EnumMap<...>>. This is a special case of the general principle that application programmers should rarely, if ever, use Enum.ordinal. EnumMap use arrays internally, so we pay little in space or time cost for the added clarity, safety, and ease of maintenance.
Item 38: Emulate extensible enums with interfaces
While we cannot write an extensible enum type, we can emulate it by writing an interface to accompany a basic enum type that implements the interface. This allows clients to write their own enums (or other types) that implement the interface. Instances of these types can then be used wherever instances of the basic enum type can be used, assuming APIs are written in terms of the interface.
<T extends Enum<T> & Operation> here extends means that T is a subtype of Enum and Operation as its not possible to extend more than one class.
Item 39: Prefer annotations to naming patterns
There is simply no reason to use naming patterns when you can use annotations instead. Naming patterns were used earlier like in testing the method should start with Test which makes the code brittle as someone may misspell and the test would be silently ignored. Annotations provide a much robust method, having features of repeatable inside containers etc.
Item 40: Consistently use the @Override annotation
We should use the @Override annotation on every method declaration that we believe to override a superclass declaration to avoid overloading or overriding a non-existent method (may be in future). It gives helpful compile time error.
Item 41: Use marker interfaces to define types
A marker interface is an interface that contains no method declarations like Serializable.
Marker interfaces are not obsolete after marker annotations because:
- they define a type
- they can be targeted more precisely
Make a choice between annotation and interface when using Element.TYPE in annotation. If you want marking other than class/interface then use annotation. If you do want to define a type, do use an interface.
This is it!



