【读书笔记】Effective Java(创建和销毁对象)

Effective Java是Joshua Bloch(Java集合类编写者)写的关于从Java开发中总结出的提高Java开发效率的一套方法。

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

这里说的静态工厂方法和设计模式中的工厂方法不同,本书提及的静态工厂方法旨在提供一个工厂方法返回类的实例。这样既有优势又有劣势。

优势:

  • 由于构造器必须和类同名, 唯一区别不同的构造器构造的实例对象的方法就是通过参数列表,而有时程序员常常会混淆两个参数相同,顺序不同的构造器。而工厂方法则能通过名字来返回具有不同含义的实例对象,比如BigInteger.probablePrime返回可能为素数的对象。
  • 不必在每次调用这个类的时候都实例化一个对象
  • 它们可以返回原返回类型的任何子类型对象,这样可以对调用者隐藏这个类的实现类,比如java.util.Collections,它可以返回不可修改集合和同步集合,这些类的实现都是非公开的。
  • 所返回的对象的类可以随着每次调用而发生变化,这取决于方法的参数值。比如EnumSet,如果枚举类的大小小于64,那么静态工厂方法就会返回一个RegalarEnumSet,否则返回一个JumboEnumSet,如果事实证明RegalarEnumSet对性能提升并无多大优势,那么就可以删除RegalarEnumSet类,而对于调用者,由于静态工厂方法隐藏了内部细节,调用者不知道返回的是哪个实现类,那么删除或者添加几个实现类,对调用者并无任何影响。
  • 方法返回的对象所属的类,在编写包含静态工厂方法的类时可以不存在。这种灵活的静态工厂方法构成了服务提供者框架的基础,例如JDBC的API。

缺点:

  • 类如果不含公有的或者受保护的构造器,就不能被子类化。比如java.util.Collections中的集合实现类,不过这样也有好处,这样可以使得程序员使用复合而不是继承。
  • 程序员很难发现它们,在API文档中,他们没有像构造器那样明显地被标记出来。同时,如果对这些工厂方法地实现类遵守标准的命名规范,也可以弥补这一劣势。

静态工厂类一些常见的命名规范:

  • from:类型转换方法,如Date d = Date.from(instance)
  • of:聚合方法,带有多个参数,如SetRank> s = EnumSet.of(JACK, QUEEN, KING);
  • valueOf:比from和of更繁琐的一种方法,比如BigInteger.valueOf(Integer.MAX_VALUE):
  • instance或者getInstance():返回的实例可以通过参数名来描述。
  • create后者newInstance():和上述类似,不过这个方法确保每次返回一个新的实例。
  • getType:和上述类似,但是在工厂方法处于不同的类中的时候使用,Type表示工厂方法所返回的对象类型。比如Files.getFileStore(path)。
  • newType:和上述类似,比如Files.newBufferedReader(path)。
  • type:上述两种方法的简写。如Collections.list()

2.遇到多个构造器参数时考虑使用构建器

静态工厂方法和构造器方法的局限性在于,如果一个类中有多个属性,其中部分必需而其他为非必需,那么就要提供多个构造器或者方法返回不同的实例对象,或者使用JavaBean,即只提供一个空参构造器,属性使用get,set方法注入,但是这样的话,构造过程被分到了几个调用中,JavaBean可能处于不一致的状态。构造者模式就能有效缓解这一现象。

比如:

class Student {
    
    private String stuNo;
    private String name;
    private int classNo;
    private String gender;
    private int age;
    private int rank;
    
    
    public static class Builder {
        // 必须的属性
        private final String stuNo;
        private final String name;
        private final int classNo;
        // 非必须的属性
        private String gender = "";
        private int age = 0;
        private int rank = 0;
        public Builder(String stuNo, String name, int classNo) {
            this.stuNo = stuNo;
            this.name = name;
            this.classNo = classNo;
        }
        
        public Builder gender(String gender) {
            this.gender = gender;
            return this;
        }
        
        public Builder age(int age) {
            this.age = age;
            return this;
        }

        public Builder rank(int rank) {
            this.rank = rank;
            return this;
        }
        
        public Student build() {
            return new Student(this);
        }
    }
    
    public Student(Builder builder) {
        this.stuNo = builder.stuNo;
        this.name = builder.name;
        this.classNo = builder.classNo;
        this.gender = builder.gender;
        this.age = builder.age;
        this.rank = builder.rank;
    }
}

客户端只需要这样调用:

Student stu = new Student().Builder(xxx, xxx, xxx).age(18).build();

Builder也适用于类层次结构。

这样写的好处是十分灵活,同时它又增加了额外的开销。

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

声明一个包含单个元素的枚举类型。

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

将构造器私有化,但这样也有副作用,这个类的子类无法调用父类的构造器。

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

将依赖的属性放入类的构造器参数列表中,而不是由类来实例化依赖,每次实例化,注入依赖的资源。

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

要优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱。

7.清除过期的对象引用

.清除对象引用应该是一种例外,而不是一种规范行为。内存泄露另外一个来源是缓存,第三个来源是监听器和其他回调。

8.避免使用终结方法(finalizer)和清除方法(cleaner)

  • 它们的缺点在于不能保证或被即使执行。
  • 如果终结方法执行过程中抛出异常,对象的终结过程会中止,如果另一个线程企图调用这种被破坏的对象,则可能发生任何不确定的行为,甚至警告都不会被打印出来。
  • 使用终结方法和清除方法有一个非常严重的性能损失
  • 终结方法有一个严重的安全问题。如果类的构造器或者序列化对等体(readObject和readResolve)抛出异常,恶意子类的终结方法可以在构造了一部分应该已经半途夭折的对象上执行,这个终结方法会将对该对象的引用记录在一个静态域中,阻止它被垃圾回收。final类不会受到攻击,为了防止final类受到攻击,要编写一个空的final的finalize方法。

终结方法和清除方法的用途:

  • 充当安全网,当未及时调用close方法时,可以回收资源,虽然不是那么的及时。
  • 清除本地对等体,本地对等体并不是普通对象,垃圾回收器不会知道它。

9.try-with-resources优先于try-finally

需要实现AutoCloseable接口

  • 相较于嵌套的try-finally,这样代码结构更加清晰。
  • 对于嵌套的try-finally,异常信息会发生覆盖,影响代码的调试,使用try-with-resources则会保留异常信息 调用getSuppressed可以看到这些异常信息。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值