Effective java 第二版 jdk1.5 编程思想 便条

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

2.多个构造器参数时,可考虑使用构建器(静态内部类builder)

3.使用枚举构造器或者枚举类型强化singleton属性

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

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

6.清除过期的对象引用

7.避免使用终结方法

8.重写rquals时请遵守通用约定

9. 覆盖equals总是要覆盖hashCode

10.始终要覆盖toString()   

11.谨慎地覆盖clone

12.考虑实现Comparable接口

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

14.在共有类使用访问方法而非共有域

15.使可变性最小化

16.复合优先于继承

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

18.接口优先于抽象类

19.接口只用于定义类型

20.类层次优先于标签类

21.用函数对象表示指针

22.优先考虑静态成员类

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

24.消除非受检异常

25.列表优先于数组

26.优先考虑泛型

27.优先考虑泛型方法                                                                                           

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

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

30.使用enum代替int常量          

31.使用实例域代替序数

32.使用EnumSet代替位域

33.使用EnumMap代替序列索引

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.谨慎使用本地方法

55.谨慎地进行优化

56.遵循普遍接受的命名惯例

57.只针对异常的情况使用异常

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

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

60.优先使用标准的异常

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

65.不要忽略异常

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

67.避免过度同步

68.executor和task优先于线程

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

71.慎用延迟初始化

72.不要依赖于多线程调度器

73.避免使用线程组

74.谨慎地实现Serializable接口

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

76.保护性的编写readObject方法

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

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


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

       √  静态工厂方法有名称_易读

          不必在每次调用它们的时候都创建一个新对象_性能提高

          可返回原类型的任何子类型_灵活性

          参数化实例代码简洁_HashMap newInstance()

     

     ×  没有可继承的构造器将不能被子类化_提倡复合_所以意义不大

          名字逼格高,其实和普通的静态方法一样

2.多个构造器参数时,可考虑使用构建器(静态内部类builder)

   eg:   重叠构造器 在参数较多的时候编写起来会‘骂人’

               A(E a,T b, K c);

               A(E a,T c);

               A(E a,K b);

               .......

       eg: javaBeans setter方法会导致不一致,阻止了将类变成不可变的可能,需要额外注意线程安全

              a.setE(..);

              a.setT(..);

              a.setK(..);

        

       eg: 构建器

public class BuilderDemo{
    private final int a;
    private final int b;
    private BuilderDemo(Builder builder){
        a = builder.a;
        b = builder.b;
    }
    public static class Bulider{
         private int a;       //外部内可以访问内部类的私有成员——虽然编译之后会产生两个class文件,但是会特殊处理
         private int d;
         
        public Builder(){}
        public Bulider a(int val){
            a = val;
            return this;
        }
        public Bulider b(int val){
            b = val;
            return this;
        }
        
        public BuilderDemo buil(){
            return new BuilderDemo(this);
        }
    }
    public static void main(String args[]){
       BuilderDemo builderDemo = new BuilderDemo.Builder().a(1).b(2).build();
    }
}

 为什么静态内部类是线程安全的?《深入理解JVM虚拟机》

虚拟机会保证一个类的类构造器<clinit>()在多线程环境中被正确的加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的类构造器<clinit>(),其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕。

特别需要注意的是,在这种情形下,其他线程虽然会被阻塞,但如果执行<clinit>()方法的那条线程退出后,其他线程在唤醒之后不会再次进入/执行<clinit>()方法,因为 在同一个类加载器下,一个类型只会被初始化一次。如果在一个类的<clinit>()方法中有耗时很长的操作,就可能造成多个线程阻塞,在实际应用中这种阻塞往往是隐藏的

3.使用枚举构造器或者枚举类型强化singleton属性

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

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

    × string s = new string("hello world");

    √ string s = "hello world";

    √尽量使用静态工厂方法获取某个对象…… newInstance()

    更灵活,如 1 ,可以在代码不变的情况下变成其子类

6.清除过期的对象引用

    通常 object = null;

7.避免使用终结方法

finalize()不能当作c++的析构器,这个方法不能保证被执行……不能用来关闭已经打开的文件,流(貌似没人会这么干^_^)

8.重写rquals时请遵守通用约定

   √自反性:x.equals(x) == true

   √对称性:    x.equals(y) == y.equals(x) == true

   √传递性:    x.equals(y) and y.equals(z) => x.equals(z) == true

   √一致性:   x.equals(y) 始终返回 true or false

   √非空性:    x!=null && x.equals(null) == false   

    @使用 == 检查 对象引用

    @使用instanceof 检查  类型正确

    @equals总是要覆盖hashCode

    @不要将equals声明中的object对象类型替换为其他的类型

9. 覆盖equals总是要覆盖hashCode

     相等的对象必须拥有相等的散列码 

10.始终要覆盖toString()   

     方便使用理解

11.谨慎地覆盖clone

    https://www.jianshu.com/p/acbc3fb53c62

12.考虑实现Comparable接口

    使用compareTo()比较类的关键域

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

14.在共有类使用访问方法而非共有域

15.使可变性最小化

    √使类成为不可变的

     1.不提供任何会修改对象状态的方法

     2.保证类不会别扩展

     3.使所有的域都是final的

     4.使所有的域都成为私有的 

     5.确保对任何可变组件的互斥访问

16.复合优先于继承

      继承打破了封装,子类依赖其超类中特定功能的实现细节,超类的实现有可能会随着发行版本的不同而有所变化,此变化会使子类遭到破坏

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

18.接口优先于抽象类

19.接口只用于定义类型

   常量接口模式是对接口的不良使用

20.类层次优先于标签类

     包含两种或者更多风格的实例类,并包含实例风格的标签域,不建议这样设计

21.用函数对象表示指针

     对象引用作为参数

22.优先考虑静态成员类

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

    使用泛型 灵活

24.消除非受检异常

   必要时 使用@SuppressWarnings("unchecked") 并添加注释说明为什么这么做是安全的

25.列表优先于数组

   数组和泛型有不同的规则 数组是协变且可以具体化的;泛型是不可变且可以消除的

26.优先考虑泛型

27.优先考虑泛型方法                                                                                           

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

           <? extends E>   <? super T> 

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

map set list 等非固定的类型参数                                                                               

30.使用enum代替int常量          

31.使用实例域代替序数

    ordinal()不推荐使用,用实例域替代

32.使用EnumSet代替位域

33.使用EnumMap代替序列索引

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

     枚举继承接口

35.注解优先于命令模式

36.坚持使用Override注解

37.用标记接口定义类型

      serializable

38.检查参数的有效性

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

 不可变类,引用参数拷贝  this.start = new Date(param.getTime());

40.谨慎设计方法签名 

方法命令规范   不要过于追求提供便利的方法 避免过长的参数列表

41.慎用重载

42.慎用可变的参数

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

44.为所有导出的api元素编写文档注释

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

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

    remove()、转换时慎用

47.了解和使用类库

48.如果需要精确的答案,避免使用float和double                                                      

     BigDecimal                                                                                                                                    

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

50.如果其他类型更合适请避免使用字符串

51.当心字符串连接性能

      考虑stringbuilder

52.通过接口引用对象

53.接口优先于反射机制

54.谨慎使用本地方法

55.谨慎地进行优化

56.遵循普遍接受的命名惯例

57.只针对异常的情况使用异常

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

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

60.优先使用标准的异常

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

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

63.在细节中包含能捕获失败的信息

64.努力使失败保持原子性

    在执行操作之前检查参数的有效性

65.不要忽略异常

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

     sychronized

67.避免过度同步

68.executor和task优先于线程

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

70.线程安全的文档化

    出现了’sychronized‘关键字就足以用文档说明线程安全性“是错误的观念

71.慎用延迟初始化

    多线程可能出错,可用静态内部类懒加载实现延迟加载

72.不要依赖于多线程调度器

73.避免使用线程组

74.谨慎地实现Serializable接口

     实现了serializable接口,一旦这个类被发布,就大大降低了”改变这个类的实现“的灵活性   …… springboot  redis使用

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

76.保护性的编写readObject方法

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

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨中漫步t2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值