effective Java 第三版学习笔记

时间:2023-03-08 18:31:37

创建对象类型的

1,静态工厂方法代替构造器

  • 静态工厂方法有名称,不容易混乱他的作用
  • 不必再每次调用他的时候创建实例,创建实例的代价是高的,可以重复利用缓存的对象
  • 静态工厂甚至能返回子类对象,例如在接口上(Java8 )的静态方法上,返回一个直接可以用的类
  • 根据参数值,决定不同的返回类型(貌似和上面有点像
  • 返回的类型,可以在写静态工厂时候不存在(貌似用在rpc方面)
  • 缺点
  • 如果不包含公有或包含的构造器,就不能让子类实例化
  • javadoc不能很好解释
  • ps
  • vauleOf,转换方法
  • instance或者getInstance,通过方法参数获得实例,但不能说每次实例都是一样的,A a =  A.getInstance(option)
  • create或者createInstance,通过静态方法获得实例,每次都说新的实例
  • getType,在不同类中返回不同的对象,type可以是其他意思,比如getA,getB
  • newType,和上面一样,返回新的实例

2,遇到多个构造器参数的时候,使用构建器

  • 构建器有同样的参数列表
  • 构建器构造函数写必须的参数,后面再添加可选的参数
  • build方法返回实例的引用

effective Java 第三版学习笔记

effective Java 第三版学习笔记

3,用枚举强化单例模式

4,在一些静态工具类中,将构造方法私有化,不能abstract抽象化,别人还以为你是专门用来继承的

5,不要用单例和静态工具类来实现一个或多个资源的类(他们都只能假设有一种资源)(静态工具类不能用状态),因为资源的行为会影响类的行为,应该将资源交给工厂(spring),通过他们进行依赖注入来创建类

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

  • string
  • 像解析token,正则表达式,这些,缓存创建好的对象
  • 自动装箱问题,尽量使用基本类型

7,消除过期的对象引用

  • 像栈这种需要自己维护一些数组的需要引用指空来防止内存泄漏
  • 缓存也会内存泄漏,当缓存的生命周期由该键的外部引用决定时,可以用weakhashmap

8,-

9,使用try-with-resource 代替try- catch

所有对象通用的方法

10,equal的一些性质,(几个特性,没认真记住

  •  重写equal前重写hashcode
  • 不要重写时候换了入参对象,因为这样是重载不是重载

11,重写equal前重写hashcode

12,始终覆盖tostring,尽可能输出又用的信息

13,谨慎重写clone(未看)

14,实现comparable接口的时候,比较值避免使用《》,用装箱基本类型的类的compare方法,或者Comparator接口中的比较器

类和接口

15,类和成员的可访问性最小化(未怎么看

16,要在公有类而非公有域使用访问方法(set,get

17,可变性最小,为了成为不可变类的条件

  • 不要设置方法
  • 类被final修饰,(不可被扩展
  • 域都是被final修饰
  • 域都是私有的
  • 不被其他引用指向
  • 缺点
  • 每次都要new一个,改进,一些计算的域适当可变

18,复合优于继承

  • 继承的时候是否满足is a的关系
  • 在使用继承来实现功能的时候,超类方法可能又自己方法的自用性,当你不够了解超类的实现的时候,重写的方法可能在别的地方被调用了,所有一般又组合的方式,写个装饰者模式

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

  • 必须又文档说明可覆盖的方法和自用性
  • 比如在一个remove方法里面,说明他调用了equal了方法,那么重写equal这个方法的时候就会得到注意
  • 构造器不能调用重写的方法,毕竟超类在构造的时候,重写方法还没实现
  • clone和serializable的实现方法也不能调用重写方法
  • 必须要用,可以抽象出来一个私有方法调用

20,接口优于抽象类,如果是个很重要的接口,考虑提供骨架类,例如:AbstractList

21,为后代设计接口,虽然Java8又default,但也要慎重设计接口

22,常量不应该定义在接口

23,类层次优于标签结构,很无聊,就是不要写太多具体的东西和模板在同个类中,用继承来层次化他

24,解释了内部类,和外部类没有一一对应的关系的时候可以选择static

25,单个源文件为单个*类,想多个的时候,请使用静态类,防止编译的时候发生错误,少编译了类

泛型

26,不要使用原生态类型,collection这些,用泛型,这样可以尽早检查出错误

27,受检警告很重要,尽量不要删除它,如果要删除,请确定再最小范围,还有注释为什么要删除

28,用list代替数组

29,优先考虑使用泛型

30,优先考虑泛型方法

31,利用限定符提升api的灵活性

  • extend 作为生产者
  • super 作为消费者
  • 当方法中没有用到具体的泛型,入参可以考虑使用?,但方法中需要插入或者删除,封装多一层的泛型

32,谨慎并用泛型和可变参数(没看懂

33,优先考虑类型安全的异构容器(没看懂

枚举和注解

34,优先使用常量对比于枚举

35,不要依赖枚举本来的ordinary值,自己set值

36,用EnumSet代替位域

37,用EnumMap代替序数索引

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

39,注解优于命名模式(看了题目,没深入看

40,坚持使用@Override注解,防止自己写了重载而不是重写这种错误

41,用标记接口来定义类型

lambda和stream

42,lambda代替匿名类

43,方法引用优于lambda

44,写函数接口的时候,看看是否又官方库类,比如predicate,function,consumer,还有基于基本类型的接口

45,慎重使用stream

  • 统一转换元素序列
  • 过滤元素序列
  • 利用单个操作(如添加,连接,计算最小值)合并元素顺序
  • 分组
  • 搜索满足某些条件

46,优先选择stream无副作用的函数,就是用collectors里面的

47,stream优先使用collectior作为返回类型(看不懂

48,谨慎,少用stream的并发流

方法

49,检查方法入参的有效性

50,必要时进行保护性拷贝,别把需要的引用给暴露出去,要的话给他拷贝一个,如果你觉得这样伤害性能,就建议在安全环境下进行

51,谨慎设计方法签名,名字参考jdk,参数用枚举代替Boolean

52,慎用重载,重载是再编译期的,没有重写的在运行期再决定动作,可以考虑改接口名来,自动装箱也有问题remove(e),remove(int),确定传进去相同参数的时候,行为是一样的

53,慎用可变参数

effective Java 第三版学习笔记

54,返回数组和集合的时候,返回一个空的比null好,避免客户端代码出错

55,使用optional,当一个方法无法给出返回值的时候,有两种选择,

  • null,但会让客户端代码有npe
  • 抛出异常,异常栈有代价的
  • 返回optional,强迫客户端思考,有点像受检异常

56,为api写javadoc

Java通用编程(一些细枝末节

57,局部变量作用域最小化

58,foreach 代替for

  • 除了用remove方法
  • 除了不需要全部遍历
  • 除了两个集合同时遍历

59,使用官方库类,不然就用第三方

60,要准确数据用bigDecimal,long(不超过18),int(不超过9)代替float,double

61,尽量使用基本类型

  • 自动装箱带来的性能问题
  • 自动拆箱带来的npe
  • 集合和其他容器用装箱

62,如果其他类型更加适合,就不用字符串,(很虚

63,拼接字符串使用stringBuilder

64,通过接口引用对象(面向抽象编程?

65,接口优于反射(不懂

66,谨慎使用本地方法

67,谨慎地进行优化(不要浪费时间搞有的没的

68,改名规范

  •   不可实例化的工具类加s结尾,collections,collectors
  • 返回Boolean的用isxxxx
  • 转换对象类型,tostring,toxxx

effective Java 第三版学习笔记

69,异常不可以作为控制语句来混用

70,可以回复的异常使用受检异常

71,避免使用受检异常(不太会

72,使用官方异常

effective Java 第三版学习笔记

73,抛出与抽象对应的异常,高层次的异常吃掉低层次的异常,然后抛出高层次的异常,这就叫异常的转换

effective Java 第三版学习笔记

74,每个抛出的异常都应该又文档支持

75,细节异常的信息(不太很理解

76,出现异常的时候,保留原子性(原来的状态

  • 在改变对象状态前抛出异常
  • 在拷贝对象上修改

77,永远不要忽略异常

并发

78,共享变量需要同步(废话?)(不用thread。stop,用Boolean让自己的线程停止自己的线程

79,把同步区域做到最小

80,使用executor,stream,task代替手写线程

81,使用aqs框架的工具代替手写notify,wait

82,为线程安全添加必要的文档

83,慎用延迟初始化,有必要用双重锁检测

84,不要依赖线程调度器(不太理解

序列化

85,用json和protobuf代替Java序列化

86,谨慎实现serilianize接口(不太理解

87,考虑使用自定义的序列化形式(不太理解