Android开发Android知识Android技术知识

《Effective Java》笔记(下)

2016-11-03  本文已影响1646人  OCNYang

《Effective Java》笔记(下)

Enums and Annotations

```java
  // Enum type with constant-specific method implementations
  public enum Operation {
      PLUS   { double apply(double x, double y){return x + y;} },
      MINUS  { double apply(double x, double y){return x - y;} },
      TIMES  { double apply(double x, double y){return x * y;} },
      DIVIDE { double apply(double x, double y){return x / y;} };
      abstract double apply(double x, double y);
  }
```
+  结合constant-specific data
```java
  // Enum type with constant-specific class bodies and data
  public enum Operation {
      PLUS("+") {
          double apply(double x, double y) { return x + y; }
      },
      MINUS("-") {
          double apply(double x, double y) { return x - y; }
      },
      TIMES("*") {
          double apply(double x, double y) { return x * y; }
      },
      DIVIDE("/") {
          double apply(double x, double y) { return x / y; }
      };

      private final String symbol;
      Operation(String symbol) { this.symbol = symbol; }

      @Override public String toString() { return symbol; }
      abstract double apply(double x, double y);
  }
```
+  If switch statements on enums are not a good choice for implementing con- stant-specific behavior on enums, what are they good for? Switches on enums are good for augmenting external enum types with constant-specific behavior.
  // Using ordinal() to index array of arrays - DON'T DO THIS!
  public enum Phase {
      SOLID, LIQUID, GAS;

      public enum Transition {
        MELT, FREEZE, BOIL, CONDENSE, SUBLIME, DEPOSIT;

        // Rows indexed by src-ordinal, cols by dst-ordinal
        private static final Transition[][] TRANSITIONS = {
                { null,    MELT,     SUBLIME },
                { FREEZE,  null,     BOIL    },
                { DEPOSIT, CONDENSE, null    }
        };

        // Returns the phase transition from one phase to another
        public static Transition from(Phase src, Phase dst) {
          return TRANSITIONS[src.ordinal()][dst.ordinal()];
        }
      }
  }

  // Using a nested EnumMap to associate data with enum pairs
  public enum Phase {
      SOLID, LIQUID, GAS;

      public enum Transition {
          MELT(SOLID, LIQUID), FREEZE(LIQUID, SOLID),
          BOIL(LIQUID, GAS),   CONDENSE(GAS, LIQUID),
          SUBLIME(SOLID, GAS), DEPOSIT(GAS, SOLID);

          final Phase src;
          final Phase dst;

          Transition(Phase src, Phase dst) {
              this.src = src;
              this.dst = dst;
          }

          // Initialize the phase transition map
          private static final Map<Phase, Map<Phase,Transition>> m =
              new EnumMap<Phase, Map<Phase,Transition>>(Phase.class);
          static {
              for (Phase p : Phase.values())
                  m.put(p,new EnumMap<Phase,Transition>(Phase.class));
              for (Transition trans : Transition.values())
                  m.get(trans.src).put(trans.dst, trans);
          }

          public static Transition from(Phase src, Phase dst) {
              return m.get(src).get(dst);
          }
      }
  }

当需要增加Phase时,前者需要谨慎地修改TRANSITIONS数组的内容(这一步骤容易出错),而后者则只需要增加相应Transition即可,from函数的逻辑完全不受影响。

函数

```java
ReturnType1 suspect1(Object... args) { }
<T> ReturnType2 suspect2(T... args) { }
```

 如果传入一个基本类型的数组进去(例如int[]),那么这两个方法接受的都是一个int[][],即相当于接受了一个只有一个元素的数组,而这个数组的数据类型是int[]!而如果传入一个对象的数组,则相当于传入了数组长度个数的varargs。`Arrays.asList`方法就存在这个问题!
  // The right way to return a copy of a collection
  public List<Cheese> getCheeseList() {
    if (cheesesInStock.isEmpty())
      return Collections.emptyList(); // Always returns same list
    else
      return new ArrayList<Cheese>(cheesesInStock);
  }

编程通用

```java
  // Can you spot the bug?
  enum Suit { CLUB, DIAMOND, HEART, SPADE }
  enum Rank { ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,
              NINE, TEN, JACK, QUEEN, KING }
  ...
  Collection<Suit> suits = Arrays.asList(Suit.values());
  Collection<Rank> ranks = Arrays.asList(Rank.values());
  List<Card> deck = new ArrayList<Card>();
  for (Iterator<Suit> i = suits.iterator(); i.hasNext(); )
      for (Iterator<Rank> j = ranks.iterator(); j.hasNext(); )
          deck.add(new Card(i.next(), j.next()));
```

`i.next()`在内层循环被调用了多次。以下写法则直观且不易出错:

```java
  // Preferred idiom for nested iteration on collections and arrays
  for (Suit suit : suits)
      for (Rank rank : ranks)
          deck.add(new Card(suit, rank));
```

异常处理

```java
// Exception Translation
try {
    // Use lower-level abstraction to do our bidding
    ...
} catch(LowerLevelException e) {
    throw new HigherLevelException(...);
}
```

并发

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(runnable);
executor.shutdown();
```java
  // Private lock object idiom - thwarts denial-of-service attack
  private final Object lock = new Object();
  public void foo() {
    synchronized(lock) {
      ...
    }
  }
```
```java
  // Lazy initialization holder class idiom for static fields
  private static class FieldHolder {
    static final FieldType field = computeFieldValue();
  }
  
  static FieldType getField() { return FieldHolder.field; }
```
```java
  // Double-check idiom for lazy initialization of instance fields 
  private volatile FieldType field;
  FieldType getField() {
    FieldType result = field;
    if (result == null) {  // First check (no locking)
      synchronized(this) {
        result = field;
        if (result == null)  // Second check (with locking)
          field = result = computeFieldValue();
      } 
    }
    return result;
  }
```

`result`这个局部变量的作用是,通常情况下,`field`已经初始化过了,这时将只会对其产生一次读操作,性能会有所提升

Serialization

```java
  // Serialization proxy for Period class
  private static class SerializationProxy implements Serializable { 
    private final Date start;
    private final Date end;
    
    SerializationProxy(Period p) {
      this.start = p.start;
      this.end = p.end;
    }
    
    // readResolve method for Period.SerializationProxy 
    private Object readResolve() {
      return new Period(start, end);  // Uses public constructor
    }
    
    private static final long serialVersionUID = 234098243823485285L; // Any number will do (Item 75)
  }
```
```java
  // writeReplace method for the serialization proxy pattern
  private Object writeReplace() {
    return new SerializationProxy(this);
  }
```
```java
  // readObject method for the serialization proxy pattern
  private void readObject(ObjectInputStream stream) throws InvalidObjectException {
    throw new InvalidObjectException("Proxy required");
  }
```

摘录来源:https://notes.piasy.com/Android-Java/EffectiveJava.html

上一篇下一篇

猜你喜欢

热点阅读