Effective Java

2022-12-31  本文已影响0人  kaiker

第二章 创建和销毁对象

1、静态工厂代替构造器

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

建造者

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

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

5、优先考虑依赖注入引用资源

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

7、消除过期的对象引用

过期对象引用

8、避免使用终结方法和清除方法

9、try-with-resources优先于try-final

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

10、覆盖equals时遵守通用约定

11、覆盖equals时总要覆盖hashCode

12、始终覆盖toString

13、谨慎地覆盖clone

14、考虑实现Comparable接口

第四章 类和接口

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

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

17、使可变性最小化

18、复合优先于继承

19、要么设计继承并提供文档说明,要么禁止继承

下面的例子,super调用父类构造器,override调用子类的,但是此时还未完成初始化


继承

无论是clone还是readObject,都不可以调用可覆盖的方法,不管是直接还是间接。覆盖的方法将在子类被序列化或是修正克隆对象状态之前运行,就得不到想要的结果。

20、接口优于抽象类

21、为后代设计接口

22、接口只用于定义类型

23、类层次优于标签类

24、静态成员类优于非静态成员类

25、限制源文件为单个顶级类

第五章 泛型

26、请不要使用原生态类型

27、消除非受检的警告

28、列表优于数组

29、优先考虑泛型

30、优先考虑泛型方法

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

? super T

32、谨慎并用泛型和可变参数

static void f(List<String>... stringLists) {
    List<Integer> intList = List.of(42);
    Object[] objects = stringLists;
    object[0] = intList;  // Heap pollution;
    String s = stringLists[0].get(0);
}

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

第6章 枚举和注解

34、用enum代替int常量

35、用实例域代替序数

36、用EnumSet代替位域

37、用EnumMap代替序数索引

38、用接口模拟可扩展的枚举

public interface Operation {
    double apply(double x, double y);
}

public enum BasicOperation implements Operation {
    PLUS("+") {
        public double apply(double x, double y) {return x + y;}
    }
}

39、注解优先于明明模式

40、坚持使用Override注解

41、用标记接口定义类型

第7章 Lambda和Stream

42、Lambda优先于匿名类

43、方法引用优先于Lambda

44、坚持使用标准函数接口

UnaryOperator<T>
BinaryOperator<T>
Predicate<T>
Function<T,R>
Supplier<T>
Consumer<T>

45、谨慎使用Stream

46、优先选择Stream中无副作用的函数

47、Stream要优先用Collection作为返回类型

48、谨慎使用Stream并行

第8章 方法

49、检查参数的有效性

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

51、谨慎设计方法签名

52、慎用重载

53、慎用可变参数

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

55、谨慎返回optional

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

第9章 通用编程

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

58、for-each循环优先于传统for循环

59、了解和使用类库

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

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

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

63、了解字符串连接的性能

64、通过接口引用对象

65、接口优先于反射机制

66、谨慎地使用本地方法

67、谨慎地进行优化

68、遵守普遍接受的命名习惯

第10章 异常

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

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

71、避免不必要地使用受检异常

72、优先使用标准异常

73、抛出与抽象对应的异常

74、每个方法抛出的所有异常都要建立文档

75、在细节消息中包含失败-捕获信息

76、努力使失败保持原子性

public Object pop() {
    if (size == 0) throw new EmptyStackException();
}

77、不要忽略异常

第11章 并发

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

79、避免过度同步

80、executor、task和stream优先于线程

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

82、线程安全性的文档化

private final object lock = new Object();

public void foo() {
    synchronized(lock) {
    }
}

83、慎用延迟初始化

private static class FieldHolder {
    static final FieldType field = computeFieldValue();
}

private static FieldTpe getField() {
    return FieldHolder.field;
}
private volatile FieldType field;

private FieldType getField() {
    FieldType result = field;
    if (result == null) {
        synchronized(this) {
            if (field == null) field = result = computeFieldValue();
        }
    }
}

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

第12章 序列化

85、其他方法优先于Java序列化

86、谨慎地实现Serializable接口

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

88、保护性地编写readObject方法

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

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

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;
    }

    private Object writeReplace() { return new SerializationProxy(this); }

}


上一篇 下一篇

猜你喜欢

热点阅读