[关闭]
@caos 2014-11-20T04:24:32.000000Z 字数 22320 阅读 2965

effective Java 读书笔记

读书笔记 编程


第二章 创建和销毁对象

1、考虑用静态工厂方法替代构造器

2、遇到多个构造器参数是要考虑用构造器

  1. // Builder Pattern - Pages 14-15
  2. public class NutritionFacts {
  3. private final int servingSize;
  4. private final int servings;
  5. private final int calories;
  6. private final int fat;
  7. private final int sodium;
  8. private final int carbohydrate;
  9. //static inner builder class
  10. public static class Builder {
  11. // Required parameters
  12. private final int servingSize;
  13. private final int servings;
  14. // Optional parameters - initialized to default values
  15. private int calories = 0;
  16. private int fat = 0;
  17. private int carbohydrate = 0;
  18. private int sodium = 0;
  19. public Builder(int servingSize, int servings) {
  20. this.servingSize = servingSize;
  21. this.servings = servings;
  22. }
  23. public Builder calories(int val)
  24. { calories = val; return this; }
  25. public Builder fat(int val)
  26. { fat = val; return this; }
  27. public Builder carbohydrate(int val)
  28. { carbohydrate = val; return this; }
  29. public Builder sodium(int val)
  30. { sodium = val; return this; }
  31. public NutritionFacts build() {
  32. return new NutritionFacts(this);
  33. }
  34. }
  35. private NutritionFacts(Builder builder) {
  36. servingSize = builder.servingSize;
  37. servings = builder.servings;
  38. calories = builder.calories;
  39. fat = builder.fat;
  40. sodium = builder.sodium;
  41. carbohydrate = builder.carbohydrate;
  42. }
  43. //test method
  44. public static void main(String[] args) {
  45. NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).
  46. calories(100).sodium(35).carbohydrate(27).build();
  47. }
  48. }

3、用私有构造器或者枚举类型强化Singleton属性。

  1. // Singleton with public final field - Page 17
  2. public class Elvis {
  3. public static final Elvis INSTANCE = new Elvis();
  4. private Elvis() { }
  5. public void leaveTheBuilding() {
  6. System.out.println("Whoa baby, I'm outta here!");
  7. }
  8. // This code would normally appear outside the class!
  9. public static void main(String[] args) {
  10. Elvis elvis = Elvis.INSTANCE;
  11. elvis.leaveTheBuilding();
  12. }
  13. }
  14. // Singleton with static factory - Page 17
  15. public class Elvis {
  16. private static final Elvis INSTANCE = new Elvis();
  17. private Elvis() { }
  18. public static Elvis getInstance() { return INSTANCE; }
  19. public void leaveTheBuilding() {
  20. System.out.println("Whoa baby, I'm outta here!");
  21. }
  22. // This code would normally appear outside the class!
  23. public static void main(String[] args) {
  24. Elvis elvis = Elvis.getInstance();
  25. elvis.leaveTheBuilding();
  26. }
  27. }
  1. // Enum singleton - the preferred approach - page 18
  2. public enum Elvis {
  3. INSTANCE;
  4. public void leaveTheBuilding() {
  5. System.out.println("Whoa baby, I'm outta here!");
  6. }
  7. // This code would normally appear outside the class!
  8. public static void main(String[] args) {
  9. Elvis elvis = Elvis.INSTANCE;
  10. elvis.leaveTheBuilding();
  11. }
  12. }

4、通过私有构造器强化不可实例化的能力

5、避免创建不必要的对象

  1. public class Sum {
  2. // Hideously slow program! Can you spot the object creation?
  3. public static void main(String[] args) {
  4. Long sum = 0L;
  5. //long to Long is not a good idea.
  6. for (long i = 0; i < Integer.MAX_VALUE; i++) {
  7. sum += i;
  8. }
  9. System.out.println(sum);
  10. }
  11. }

6、消除过期的对象引用

  1. //it method could be better
  2. public Object pop() {
  3. if (size == 0)
  4. throw new EmptyStackException();
  5. return elements[--size];
  6. }
  7. //whatch this method
  8. public Object pop(){
  9. if (size == 0)
  10. throw new EmptyStackException();
  11. Object result = elements[--size];
  12. element[size]=null;//Eliminate obsolete reference
  13. return result;
  14. }

7、避免使用终结方法(finalizer)

不要被System.gc和System.runFinalization这两个方法所诱惑,他们确实增加了终结方法被执行的机会,但是他们不保证终结方法一定被执行。唯一声称保证终结方法被执行的方法是System.runFinalizersOnExit,以及他臭名昭著的孪生兄弟Runtime.runFinalizersOnExit。这两个方法都有致命的缺陷,都被废弃了。

第三章 对于所有对象都通用的方法

8、覆盖equals时请遵守通用约定

9、覆盖equals时总要覆盖hashCode,在每个覆盖了equals方法的类中,也必须覆盖hashCode方法。

  1. // A decent hashCode method - Page 48
  2. @Override public int hashCode() {
  3. int result = 17;
  4. result = 31 - result + areaCode;
  5. result = 31 - result + prefix;
  6. result = 31 - result + lineNumber;
  7. return result;
  8. }
  1. // Lazily initialized, cached hashCode - Page 49
  2. private volatile int hashCode; // (See Item 71)
  3. @Override public int hashCode() {
  4. int result = hashCode;
  5. if (result == 0) {
  6. result = 17;
  7. result = 31 - result + areaCode;
  8. result = 31 - result + prefix;
  9. result = 31 - result + lineNumber;
  10. hashCode = result;
  11. }
  12. return result;
  13. }

10、始终要覆盖toString

11、谨慎地覆盖clone

12、考虑实现Comparable接口

第四章 类和接口

13、使类和成员的可访问性最小化

  1. private static final Thing[] PRIVATE_VALUES = {...};
  2. public static final List<Ting> VALUES = Collecations.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
  3. //或者
  4. private static final Thing[] PRIVATE_VALUES = {...};
  5. public static final Thing[] values() {
  6. return PRIVATE_VALUES.clone;
  7. }

14、在公有类中使用访问方法而非公有域

15、使可变性最小化

16、复合优先于继承

17、要么为继承而设计,并提供文档说明,要么就禁止继承。

18、接口优于抽象类

19、接口只能用于定义类型

20、类层次优于标签类

21、用函数对象表式策略

  1. Arrays.sort(stringArray,new Comparator<String>() {
  2. @Override
  3. public int compare(String o1, String o2) {
  4. return 0;
  5. }
  6. });

22、优先考虑静态成员类

第四章、泛型

23、请不要在新代码中使用原生态类

24、消除非受检警告-SuppressWarnings("unchecked")

25、列表优先于数组

  1. //这是被允许的
  2. Object[] objectArray = new Long[1];
  3. objectArray[0] = "hello world";//Throws java.lang.ArrayStoreException
  4. //Won't compile! 不被允许:Type mismatch: cannot convert from LinkedList<Long> to List<Object>
  5. List<Object> list = new LinkedList<Long>();
  1. //Cannot create a generic array of List<String>
  2. List<String>[] stringLists = new List<String>[1];

26、优先考虑泛型

27、优先考虑泛型方法

28、利用有限制通配符来提升API的灵活性

  1. public static <T extends Comparable<? super T>> T max(
  2. List<? extends T> list) {
  3. Iterator<? extends T> i = list.iterator();
  4. T result = i.next();
  5. while (i.hasNext()) {
  6. T t = i.next();
  7. if (t.compareTo(result) > 0)
  8. result = t;
  9. }
  10. return result;
  11. }
  1. public void pushAll(Iterable<? extends E> src) {
  2. for (E e : src)
  3. push(e);
  4. }
  1. public void popAll(Collection<? super E> dst) {
  2. while (!isEmpty())
  3. dst.add(pop());
  4. }

29、优先考虑类型安全的异构容器

第六章、枚举和注解

30、用enum代替int常量

31、用实例域代替序数

  1. // Enum with integer data stored in an instance field
  2. public enum Ensemble {
  3. SOLO(1), DUET(2), TRIO(3), QUARTET(4), QUINTET(5),
  4. SEXTET(6), SEPTET(7), OCTET(8), DOUBLE_QUARTET(8),
  5. NONET(9), DECTET(10), TRIPLE_QUARTET(12);
  6. private final int numberOfMusicians;
  7. Ensemble(int size) { this.numberOfMusicians = size; }
  8. public int numberOfMusicians() { return numberOfMusicians; }
  9. }

32、用EnumSet代替位域

  1. public class Text {
  2. public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }
  3. // Any Set could be passed in, but EnumSet is clearly best
  4. public void applyStyles(Set<Style> styles) {
  5. // Body goes here
  6. }
  7. // Sample use
  8. public static void main(String[] args) {
  9. Text text = new Text();
  10. text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
  11. }
  12. }

33、用EnumMap代替序数索引

  1. //使用Map(起始阶段,Map(目标阶段,阶段过渡))形式代替使用序数组成二维数组的形式,这样更加利于维护。
  2. public enum Phase {
  3. SOLID, LIQUID, GAS;
  4. public enum Transition {
  5. MELT(SOLID, LIQUID), FREEZE(LIQUID, SOLID),
  6. BOIL(LIQUID, GAS), CONDENSE(GAS, LIQUID),
  7. SUBLIME(SOLID, GAS), DEPOSIT(GAS, SOLID);
  8. private final Phase src;
  9. private final Phase dst;
  10. //将转换所需要的值src为初始阶段,dst为目标阶段
  11. Transition(Phase src, Phase dst) {
  12. this.src = src;
  13. this.dst = dst;
  14. }
  15. // Initialize the phase transition map
  16. private static final Map<Phase, Map<Phase,Transition>> m =
  17. new EnumMap<Phase, Map<Phase,Transition>>(Phase.class);
  18. static {
  19. //放入初始阶段
  20. for (Phase p : Phase.values())
  21. m.put(p,new EnumMap<Phase,Transition>(Phase.class));
  22. //根据起始阶段的键放入目标阶段与状态的映射表
  23. for (Transition trans : Transition.values())
  24. m.get(trans.src).put(trans.dst, trans);
  25. }
  26. public static Transition from(Phase src, Phase dst) {
  27. //直接根据初始阶段获取映射在根据目标阶段获取过渡状态
  28. return m.get(src).get(dst);
  29. }
  30. }
  31. // Simple demo program - prints a sloppy table
  32. public static void main(String[] args) {
  33. for (Phase src : Phase.values())
  34. for (Phase dst : Phase.values())
  35. if (src != dst)
  36. System.out.printf("%s to %s : %s %n", src, dst,
  37. Transition.from(src, dst));
  38. }
  39. }

34、用接口模拟可伸缩的枚举

35、注解优先于命名模式

36、坚持使用Override注解

37、用标记接口定义类型

第七章 方法

38、检查参数的有效性

39、必要时进行保护性拷贝

40、谨慎设计方法签名

41、慎用重载

42、慎用可变参数

43、返回零长度的数组或集合,而不是null

44、为所有导出的API元素编写文档注释

第八章 通用程序设计

45、将局部变量的作用域最小化

46、for-each循环优先于传统的for循环

47、了解和使用类库

48、如果需要精确地答案,请避免使用float和double

49、基本类型优先于装箱基本类型

50、如果其他类型更合适,则尽量避免使用字符串

51、当心字符串连接的性能

52、通过接口引用对象

53、接口优先于反射机制

54、谨慎地使用本地方法(Java Native Interface)允许Java应用程序可以调用本地方法,也就是调用本地程序设计语言,比如C或者C++来编写的特殊方法。

55、谨慎地进行优化

56、遵守普遍接受的命名惯例

- 类型参数名称通常由单个字母组成,通常是以下五种类型之一

第九章 异常

57、只针对异常的情况才使用异常

58、对可恢复的情况使用受检异常,对编程错误使用运行时异常

59、避免不必要的使用受检的异常

60、优先使用标准的异常

常用异常
- 上述经常被重用的异常所适用的情况并不是互相排斥的。

61、抛出与抽象相对应的异常

62、每个方法抛出的异常都要有文档

63、在细节消息中包含能捕获失败的信息。

64、努力使失败保持原子性。

65、不要忽略异常

第十章 并发

66、同步访问共享的可变数据

67、避免过度同步

68、executor和task优先于线程

69、并发工具优先于wait和notify

70、线程安全性的文档化。

71、慎用延迟初始化

72、不要依赖于线程调度器

73、避免使用线程组

第十一章 序列化

74、谨慎的实现Serializable接口

75、考虑使用自定义的序列化形式

76、保护性地编写readObject方法

77、对于实例控制,枚举类型优先于readResolve

78、考虑用序列化代理代替序列化实例

服务提供者框架有三个重要的组件

  1. 服务接口——提供者实现
  2. 提供者注册API——是系统用来注册实现,让客户端访问他们。
  3. 服务访问API——客户端用来获取服务的实例。
  4. 可选的第四个组件为服务提供者接口——负责创建其服务实现的实例。
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注