《Effective Java》读书笔记

Item 1: Consider static factory methods instead of constructors

Item 2: Consider a builder when faced with many constructor parameters

Item 3: Enforce the singleton property with a private constructor

Item 4: Enforce noninstantiability with a private constructor Occasionally you’ll want to write a class that is just a grouping of static methods and static fields.

1
2
3
4
5
6
7
public class UtilityClass {
    // Suppress default constructor for noninstantiability
    private UtilityClass() {
        throw new AssertionError();
    }
    ... // Remainder omitted
}

Item 5: Prefer dependency injection to hardwiring resources

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Bad, Inappropriate use of static utility - inflexible & untestable!
public class SpellChecker {
    private static final Lexicon dictionary = ...;

    private SpellChecker() {} // Noninstantiable

    public static boolean isValid(String word) { ... }
    public static List<String> suggestions(String typo) { ... }
}


// Good, Dependency injection provides flexibility and testability
public class SpellChecker {
    private final Lexicon dictionary;

    public SpellChecker(Lexicon dictionary) {
        this.dictionary = Objects.requireNonNull(dictionary);
    }

    public boolean isValid(String word) { ... }
    public List<String> suggestions(String typo) { ... }
}

Item 6: Avoid creating unnecessary objects

Item 7: Eliminate obsolete object references 消除过时的对象引用

Item 8: Avoid finalizers and cleaners Finalizers are unpredictable, often dangerous, and generally unnecessary. As of Java 9, finalizers have been deprecated, but they are still being used by the Java libraries. The Java 9 replacement for finalizers is cleaners. Cleaners are less dangerous than finalizers, but still unpredictable, slow, and generally unnecessary.

Item 9: Prefer try-with-resources to try-finally

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Bad, try-finally is ugly when used with more than one resource!
static void copy(String src, String dst) throws IOException {
    InputStream in = new FileInputStream(src);
    try {
        OutputStream out = new FileOutputStream(dst);
        try {
            byte[] buf = new byte[BUFFERSIZE];
            int n;
            while ((n = in.read(buf)) >= 0)
                out.write(buf, 0, n);
        } finally {
            out.close();
        }
    } finally {
        in.close();
    }
}

// Good, try-with-resources on multiple resources - short and sweet
static void copy(String src, String dst) throws IOException {
    try (InputStream   in = new FileInputStream(src);
         OutputStream out = new FileOutputStream(dst)) {
        byte[] buf = new byte[BUFFERSIZE];
        int n;
        while ((n = in.read(buf)) >= 0)
            out.write(buf, 0, n);
    }
}

Item 10: Obey the general contract when overriding equals Overriding the equals method seems simple, but there are many ways to get it wrong, and consequences can be dire. The easiest way to avoid problems is not to override the equals method, in which case each instance of the class is equal only to itself.

Item 11: Always override hashCode when you override equals You must override hashCode in every class that overrides equals. If you fail to do so, your class will violate the general contract for hashCode, which will prevent it from functioning properly in collections such as HashMap and HashSet.

Item 12: Always override toString providing a good toString implementation makes your class much more pleasant to use and makes systems using the class easier to debug

Item 13: Override clone judiciously

Item 14: Consider implementing Comparable

Item 15: Minimize the accessibility of classes and members make each class or member as inaccessible as possible

Item 16: In public classes, use accessor methods, not public fields

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Encapsulation of data by accessor methods and mutators
class Point {
    private double x;
    private double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() { return x; }
    public double getY() { return y; }

    public void setX(double x) { this.x = x; }
    public void setY(double y) { this.y = y; }
}

Item 17: Minimize mutability

Item 18: Favor composition over inheritance Unlike method invocation, inheritance violates encapsulation

Item 19: Design and document for inheritance or else prohibit it the class must document its self-use of overridable methods

Item 20: Prefer interfaces to abstract classes

Item 21: Design interfaces for posterity ???

Item 22: Use interfaces only to define types

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Bad, Constant interface antipattern - do not use!
public interface PhysicalConstants {
    // Avogadro's number (1/mol)
    static final double AVOGADROSNUMBER   = 6.022140857e23;

    // Boltzmann constant (J/K)
    static final double BOLTZMANNCONSTANT = 1.38064852e-23;

    // Mass of the electron (kg)
    static final double ELECTRONMASS      = 9.10938356e-31;
}

// Good, Constant utility class
package com.effectivejava.science;

public class PhysicalConstants {
  private PhysicalConstants() { }  // Prevents instantiation

  public static final double AVOGADROSNUMBER = 6.022140857e23;
  public static final double BOLTZMANNCONST  = 1.38064852e-23;
  public static final double ELECTRONMASS    = 9.10938356e-31;
}

Item 23: Prefer class hierarchies to tagged classes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// Bad, Tagged class - vastly inferior to a class hierarchy!
class Figure {
    enum Shape { RECTANGLE, CIRCLE };

    // Tag field - the shape of this figure
    final Shape shape;

    // These fields are used only if shape is RECTANGLE
    double length;
    double width;

    // This field is used only if shape is CIRCLE
    double radius;

    // Constructor for circle
    Figure(double radius) {
        shape = Shape.CIRCLE;
        this.radius = radius;
    }

    // Constructor for rectangle
    Figure(double length, double width) {
        shape = Shape.RECTANGLE;
        this.length = length;
        this.width = width;
    }

    double area() {
        switch(shape) {
          case RECTANGLE:
            return length * width;
          case CIRCLE:
            return Math.PI * (radius * radius);
          default:
            throw new AssertionError(shape);
        }
    }
}

// Good, Class hierarchy replacement for a tagged class
abstract class Figure {
    abstract double area();
}

class Circle extends Figure {
    final double radius;

    Circle(double radius) { this.radius = radius; }

    @Override double area() { return Math.PI * (radius * radius); }
}
class Rectangle extends Figure {
    final double length;
    final double width;

    Rectangle(double length, double width) {
        this.length = length;
        this.width  = width;
    }
    @Override double area() { return length * width; }
}

Item 24: Favor static member classes over nonstatic

Item 25: Limit source files to a single top-level class

1
2
3
4
5
6
7
8
// Two classes defined in one file. Don't ever do this!
class Utensil {
    static final String NAME = "pan";
}

class Dessert {
    static final String NAME = "cake";
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Good, Static member classes instead of multiple top-level classes
public class Test {
    public static void main(String[] args) {
        System.out.println(Utensil.NAME + Dessert.NAME);
    }

    private static class Utensil {
        static final String NAME = "pan";
    }

    private static class Dessert {
        static final String NAME = "cake";
    }
}

Item 26: Don’t use raw types

1
2
3
4
5
// Bad
private final Collection stamps = ... ;

// Parameterized collection type - typesafe
private final Collection<Stamp> stamps = ... ;

Item 27: Eliminate unchecked warnings Eliminate every unchecked warning that you can.

Item 28: Prefer lists to arrays

1
2
3
4
5
6
7
// Bad, Fails at runtime!
Object[] objectArray = new Long[1];
objectArray[0] = "I don't fit in"; // Throws ArrayStoreException

// Good, Won't compile!
List<Object> ol = new ArrayList<Long>(); // Incompatible types
ol.add("I don't fit in");

Item 29: Favor generic types

1
2
Stack.java:8: generic array creation
        elements = new E[DEFAULTINITIALCAPACITY];
As explained in Item 28, you can’t create an array of a non-reifiable type, such as E.

Item 30: Favor generic methods

1
2
3
4
5
6
7
8
9
10
11
12
13
// Uses raw types - unacceptable! (Item 26)
public static Set union(Set s1, Set s2) {
    Set result = new HashSet(s1);
    result.addAll(s2);
    return result;
}

// Generic method
public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
    Set<E> result = new HashSet<>(s1);
    result.addAll(s2);
    return result;
}