Effective Java Chapter 6 Enums and Annotations Spring

  • Slides: 25
Download presentation
Effective Java, Chapter 6: Enums and Annotations Spring 2013

Effective Java, Chapter 6: Enums and Annotations Spring 2013

Agenda n Material From Joshua Bloch n n Cover Items 30 through 37 n

Agenda n Material From Joshua Bloch n n Cover Items 30 through 37 n n n “Enums and Annotations” Chapter New Constructs in Java as of Release 1. 5 Moral: n 2 Effective Java: Programming Language Guide Big Improvement over C-Style “Enum Pattern” Enums and Annotations

Item 30: Use Enums instead of int Constants n Enumerated Type n Definition n

Item 30: Use Enums instead of int Constants n Enumerated Type n Definition n n Examples n n n Type With Fixed Set of Constants as Legal Values Seasons of the Year Suits in a Deck of Cards Traditionally (as in “C”) Mapped to “int” n 3 Known as the “Int Enum Pattern” Enums and Annotations

Example: The (Undesirable) “Int Enum Pattern” // The int enum pattern – severely deficient

Example: The (Undesirable) “Int Enum Pattern” // The int enum pattern – severely deficient public static final int APPLE_FUJI = 0; public static final int APPLE_PIPPIN = 1; public static final int APPLE_GRANNY_SMITH = 2; public static final int ORANGE_NAVEL public static final int ORANGE_TEMPLE public static final int ORANGE_BLOOD = 0; = 1; = 2; // Tasty citrus flavored applesauce! int i = (APPLE_FUJI – ORANGE_TEMPLE) / APPLE_PIPPIN; 4 Enums and Annotations

Problems With Int Enum Pattern n n Total Lack of Type Safety Brittle Programs

Problems With Int Enum Pattern n n Total Lack of Type Safety Brittle Programs n n Names Compiled to Constants in Client Code Renumbering Requires Recompiling Clients n n Good Luck with that! Inconvenient to Produce Printable Strings Hard to Iterate Through Alternative “String Enum Pattern” Even Worse 5 n How Well Do Clients Spell? Enums and Annotations

Java Enum Types n Export One Instance For Each Constant n n Guarantee Compile-Time

Java Enum Types n Export One Instance For Each Constant n n Guarantee Compile-Time Type Safety n n n Declaration of Apple Cannot Hold an Orange Each Enum Has its own Namespace n n Generalization of Singleton Pattern No Need To Prefix Constants With Type Name No Need to Recompile Clients But Wait, There’s More! 6 Enums and Annotations

Rich Enum Example public enum Planet { // Enum type with data and behavior

Rich Enum Example public enum Planet { // Enum type with data and behavior MERCURY (3. 302 e+23, 2. 439 e 6); VENUS (4. 869 e+24, 6. 052 e 6); EARTH (5. 975 e+24, 6. 378 e 6); // plus MARS, JUPITER, etc. private final double mass; private final double radius; private final double surface. Gravity; private static final double G = 6. 67300 e-11; // Universal G Planet (double mass, double radius) { // Constructor this. mass = mass; this. radius = radius; surface. Gravity = G* mass / (radius * radius); } public double mass() { return mass; } public double radius() { return radius; } public double surface. Gravity() { return surface. Gravity; } public double surface. Weight (double mass) { return mass * surface. Gravity; } // F = ma 7} Enums and Annotations

Using the Enum Example public class Weight. Table { public static void main (String[]

Using the Enum Example public class Weight. Table { public static void main (String[] args) { double earth. Weight = Double. parse. Double (args[0]); double mass = earth. Weight / Planet. EARTH. surface. Gravity(); // All Enums have a static values() method // All Enums have a sensible (and Overridable) to. String() for (Planet p : Planet. values()) System. out. printf (“Weight on %s is %f%n”, p, p. surface. Weight(mass)); } } // Output: Weight on MERCURY is 66. 133672 Weight on VENUS is 158. 383926 Weight on EARTH is 175. 000000 8. . . Enums and Annotations

Questionable Means of Providing Different Behavior // Enum type that switches on its own

Questionable Means of Providing Different Behavior // Enum type that switches on its own value – Questionable public enum Operation { PLUS, MINUS, TIMES, DIVIDE; // Do the arithmetic op represented by constant double apply (double x, double y) { // Gag! Roll-your-own dynamic dispatching switch (this) { case PLUS: return x + y; case MINUS: return x – y; case TIMES: return x * y; case DIVIDE: return x / y; } throw new Assertion. Error(“Unknown op: “ + this); } } 9 Enums and Annotations

Better: Constant Specific Method Implementations // Enum type with constant-specific public enum Operation {

Better: Constant Specific Method Implementations // Enum type with constant-specific public enum Operation { PLUS { double apply (double x, MINUS { double apply (double x, TIMES { double apply (double x, DIVIDE { double apply (double x, method implementations double y) y) { { return x x + * / y; y; } } }; }; // abstract apply() ensures each constant provide definition abstract double apply(double x, double y); } 10 Enums and Annotations

Both Constant Specific Data and Operations // Enum type with constant-specific class public enum

Both Constant Specific Data and Operations // Enum type with constant-specific class public enum Operation { PLUS(“+”) { double apply (double x, double y) { MINUS(“-”) { double apply (double x, double y) { TIMES(“*”) { double apply (double x, double y) { DIVIDE(“/”) { double apply (double x, double y) { bodies and data return x + y; } }; return x - y; } }; return x * y; } }; return x / y; } }; private final String symbol; Operation (String symbol) { this. symbol = symbol; } @Override public String to. String() { return symbol; } // abstract apply() ensures each constant provide definition abstract double apply(double x, double y); } 11 Enums and Annotations

Item 31: Use Instance Fields Instead of Ordinals n Every Enum has an Assocated

Item 31: Use Instance Fields Instead of Ordinals n Every Enum has an Assocated Ordinal n n Returns the Position of Constant Don’t Use This! n n n Simple Solution n 12 Maintenance Nightmare Brings Back the Problems With “Int Enum Pattern” Use an Instance Field Instead Enums and Annotations

Instance Fields vs. Ordinals // Abuse of ordinal to derive an associated value –

Instance Fields vs. Ordinals // Abuse of ordinal to derive an associated value – DON’T DO THIS public enum Ensemble { SOLO, DUET, TRIO, QUARTET, QUINTET, SEXTET, SEPTET, OCTET, NONET, DECTET; public int number. Of. Musicians() { return ordinal() + 1; } } // What if: you add a DOUBLE_QUARTET? You rearrange the constants? // Good Solution: Use instance fields instead public enum Ensemble { SOLO(1), DUET(2), TRIO(3), QUARTET(4), QUINTET(5), SEXTET(6), SEPTET(7), OCTET(8), DOUBLE_QUARTET(8), TRIPLE_QUARTET(12); private final int number. Of. Musicians; Ensemble(int size) { this. number. Of. Musicians = size; } public int number. Of. Musicians() { return number. Of. Musisians; } } 13 Enums and Annotations

Item 32: Use Enum. Set Instead of Bit Fields // Bit field enumeration constants

Item 32: Use Enum. Set Instead of Bit Fields // Bit field enumeration constants – OBSOLETE! // All the disadvantages of int enum constants and // Classic bit twiddling! // Hard to understand when printed; No easy way to public class Text { public static final int STYLE_BOLD = 1 public static final int STYLE_ITALIC = 1 public static final int STYLE_UNDERLINE = 1 public static final int STYLE_STRIKETHROUGH = 1 more! iterate through << << 0; 1; 2; 3; // // 1 2 4 8 // Parameter is bitwise OR of zero or more STYLE_ constants public void apply. Styles (int styles) {. . . } } 14 Enums and Annotations

Example Use of Enum. Set // Enum. Set – a modern replacement for bit

Example Use of Enum. Set // Enum. Set – a modern replacement for bit fields public class Text { public enum Style {BOLD, ITALIC, UNDERLINE, STRIKETHROUGH} // Any Set could be passed in, but Enum. Set is clearly best // Standard practice to pass interface instead of Class public void apply. Styles (Set<Style> styles) {. . . } } // Client code Text. apply. Styles (Enum. Set. of(Style. BOLD, Style. Italic)); // Bottom line: Just because an enumerated type is used in sets, // there is no reason to represent it in bit fields 15 Enums and Annotations

Item 33: Use Map Instead of Ordinal Indexing n Problem: n n Bad Solution:

Item 33: Use Map Instead of Ordinal Indexing n Problem: n n Bad Solution: n n Use ordinal() method to index into array Good Solution: n 16 You want to index into an array, but instead of ints, you have an enum Use an Enum. Map instead Enums and Annotations

Example Class with Enumerated Type // Example class to represent a culinary herb public

Example Class with Enumerated Type // Example class to represent a culinary herb public class Herb { enum Type {ANNUAL, PERENNIAL, BIENNIAL } final String name; final Type type; // getters would be better here public Herb(String name, Type type) { this. name = name; this. type = type; } @Override public String to. String() { return name; } } 17 Enums and Annotations

Example of What Not to Do // Using ordinal() to index an array –

Example of What Not to Do // Using ordinal() to index an array – DON’T DO THIS! Herb[] garden =. . . ; Set<Herb>[]) herbs. By. Type = // Indexed by her. Type. ordinal() (Set<Herb>[]) new Set[Herb. Type. values(). length]; for (int i= 0; i < herbs. By. Type. length; i++) herbs. By. Type[i] = new Hash. Set<Herb>(); for (Herb h : garden) herbs. By. Type[ h. type. ordinal() ]. add(h); // Print the results for (int i=0; i < herbs. By. Type. length; i++) { System. out. printf(“%s: %s%n”, Herb. Type. values()[i], herbs. By. Type[i]); } // Problems: Arrays don’t play well with generics; unchecked casts; // label outputs by hand; ints don’t provide type-safety of enums 18 Enums and Annotations

Associating Data with an Enum // Using Enum. Map to assoicate data with an

Associating Data with an Enum // Using Enum. Map to assoicate data with an enum Map<Herb. Type, Set<Herb>> herbs. By. Type = new Enum. Map<Herb. Type, Set<Herb>> (Herb. type. class); for (Herb. type t : Herb. Type. values()) herbs. By. Type. put(t, new Hash. Set<Herb>()); for (Herb h : garden) herbs. By. Type. get(h. type). add(h); System. out. println (herbs. By. Type); // This solution is cleaner; shorter; no unsafe cast; // no need to label outputs, no possibility of error in computing // array indices. // Note that an Enum. Map is just a special kind of Map 19 Enums and Annotations

Item 34: Emulate Extensible Enums with Interfaces n Enum Types Cannot be Extended public

Item 34: Emulate Extensible Enums with Interfaces n Enum Types Cannot be Extended public enum Sub extends Super n Arguably, this is a good thing n n // doesn’t compile No True Type Relation in Extensible Enums However, Interfaces Can Help // Emulate enum extension // Client code uses interface I 1, not Sub or Super public enum Super implements I 1 // compiles fine public enum Sub implements I 1 // share interface Collection <I 1> my. Enums =. . . // client uses Sub or Super 20 Enums and Annotations

Item 35: Prefer Annotations to Naming Patterns n n Prior to 1. 5, Naming

Item 35: Prefer Annotations to Naming Patterns n n Prior to 1. 5, Naming Patterns Common Example: JUnit test methods void test. Safety. Override() void tset. Safety. Override() n Annotations Are Far Better n n Diagnostics for Misspelled Annotations Tied to Appropriate Constructs n n 21 // Junit 3. x thinks this is a test // Oops! Engineers can’t type JUnit Tests are Methods, Not Something Else Annotations Allow Parameterization Enums and Annotations

Sample Use of Annotations // Marker annotation type declaration import java. lang. annotation. *;

Sample Use of Annotations // Marker annotation type declaration import java. lang. annotation. *; /** * Indicates that the annotated method is a test method. * Use only on parameterless static methods */ @Retention (Retention. Policy. RUNTIME) @Target(Element. Type. METHOD) public @interface Test {} // Program with annotations public class Sample { @Test public static void m 1() {} // Test should pass public static void m 2() {} // Not a @Test public static void m 3() { // Test should fail throw new Runtime. Exception(“Boom”); } @Test public void m 4() // Invalid nonstatic use } 22 Enums and Annotations

Sample Use Continued – The Simple Version of JUnit // Sample code processes marker

Sample Use Continued – The Simple Version of JUnit // Sample code processes marker annotations – See Bloch for variations import java. lang. reflect. *; public class Run. Tests { public static void main(String[] args) { int tests = 0; int passed = 0; Class test. Class = Class. for. Name(args[0]); for (Method m : test. Class. get. Declared. Methods()) { if (m. is. Annotation. Present(Test. class)) { tests++; try { m. invoke(null); passed++; } catch (Invocation. Target. Exception ite) { System. out. println(m + “ failed: “ + ite. get. Cause()); } catch (Exception e) { System. out. println(“Invalid @Test: “ + m); } } System. out. printf(“Pass: %d, Fail: %d%n”, passed, tests – passed); } } 23 Enums and Annotations

Item 36: Consistently Use the @Override Annotation n Most Important Standard Annotation n Regular

Item 36: Consistently Use the @Override Annotation n Most Important Standard Annotation n Regular Use Prevents Overload/Override Bugs public boolean equals (Some. Class c) {. . . } n IDEs Can Provide Code Inspections n Override Exactly Where You Want n n And nowhere else @Override Allowed on Interface Methods n 24 Important for Abstract Classes and Interfaces Enums and Annotations

Item 37: User Marker Interfaces to Define Types n Marker Annotations (Item 35) Are

Item 37: User Marker Interfaces to Define Types n Marker Annotations (Item 35) Are Not Types n n Marker Interfaces Do Not Add Methods n n Unlike Mixin Interfaces Example Marker Interfaces n n n Interfaces Are Types Serializable Set // Marks Object as Serializable // Arguably a marker interface If You Want a Type, Do Use an Interface 25 n If You Don’t Want a Type, Don’t (See Item 19) Enums and Annotations