Java经典书籍《Effective Java(第二版)》相信大家都看过,此书共有78条关于编写高质量Java代码的建议,这里是通俗易懂地讲解,会持续全部更新完78条,希望大家每天读一篇,一起学完这78条,相信可以写出高质量代码。今天先看第一章的1到7条。
第1条:考虐用静态工厂方法代替构造器
用静态工厂方法就是类提供一个公有的静态共有方法,它就是一个返回类实例的方法;如下面所示:
public static People getInstance() {
return new People();
}
用静态工厂方法有如下的几个优点:
1、方法有名称,代码的阅读性更好
2、不需要每次在调用时都创建一个新的对象出来,创建新的对象需要的代价很高,这样极大的提高了性能。
3、可以返回原类型的任何子类型的对象
4、在创建参数化的对象实例时,它会使代码很简洁。用书中的例子;
Map<String,List<String>> map = new HashMap<String,List<String>>()//繁琐
给集合类提供静态工厂方法后:
public static <K,V> HashMap<K,V> newInstance(){
return new HashMap<K,V>();
}
HashMap<String,List<String>> map = HashMap.newInstance();
第2条:遇到多个构造器参数时要考虑用构建器
前面说的静态工厂和构造器都有一个共同的局限性:不能很好的扩展到大量的可选参数。
这时可以用到Builder模式:不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造函数,得到一个builder对象,然后在builder对象上面调用类似setter的方法,来设置每个相关的可选的参数。最后调用无参的build方法来生成不可变的对象。
/**
* 构建器模式
*
*/
public class Student {
/*必填*/
private String name;
private int age;
/*选填*/
private String sex;
private String grade;
public static class Builder {
private String name;
private int age;
private String sex = "";
private String grade = "";
public Builder(String name, int age) {
this.name = name;
this.age = age;
}
public Builder sex(String sex) {
this.sex = sex;
return this;
}
public Builder grade(String grade) {
this.grade = grade;
return this;
}
public Student build() {
return new Student(this);
}
}
private Student(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.sex = builder.sex;
this.grade = builder.grade;
}
}
上面的例子的本质就是一个内部类。
客户端代码:
Student student = new Student.Builder("joan","mea").grade("1年级").build();
这样在很多参数时,客户端的代码实现很容易,可读性也很好,builder利用单独的方法来设置每个参数,你想要多少个可变的参数都可以,主要每个setter方法中都有一个可变的参数即可。
第3条:用私有构造器或者枚举类型强化Singleton属性
Singlteton就是单例的意思,指仅仅被实例化一次的类。单例模式有很多种写法,像饿汉模式、饱汉模式、内部类、双重检验锁、枚举等写法。利用implements serializable 可以让单例变得可以序列化,但是这里需要注意的一点是可序列化的单例,在反序列化之后就不一定还是单例了,这可以提供一个readResolve方法,让反序列化之后还是同一个实例对象。
import java.io.Serializable;
/**
* Created by shidong.wu on 2017/9/18.
*/
public class Instance implements Serializable{
private static final Instance obj = new Instance();
private Instance(){
}
public static Instance getInstance(){
return obj;
}
private Object readResolve(){
return obj;
}
}
第4条:通过私有构造器强化不可实例化的能力
我们都有自己的工具类,类似java.lang.Math, java.lang.Arrays 这样的,里面全是静态方法。对于这样的工具类我们不希望被实例化,然而在缺少显示构造器的情况下,编译器会自动提供一个公有的、无参的缺省构造器。因此,我们让这个类包含一个私有的构造器,他就不会被实例化了。
第5条:避免创建不必要的对象
该条目建议的是最好能重用对象,让不是每次在调用的时候在创建一个新的对象出来,这里有3点建议;
1、构造器在每次调用的时候会创建新的对象,而静态工厂则不会,优先使用静态工厂
2、合适的场景,可以使用final静态域代替局部变量,
3、要优先使用基本类型而不是装箱类型,要当心无意识的自动装箱。
第6条:清除过期的对象引用
一般java的内存回收机制会回收已经用完的对象,但是某个对象引用要是一直不被释放,则就不能被回收,长时间就会出现内存泄漏。所以过期不用的对象一定要注意及时的清除掉。一般内存泄漏常见出现下面的几种情况:
1、类的内存是自己管理的
2、把对象的引用放到缓存中,很容易被遗忘掉,么有被回收
3、监听器和其他的回调
第7条:避免使用终结方法
终结方法:finalize通常是不可预测的,一般不建议使用
有如下的缺点:
1、不能保证被及时的执行
2、非常的耗性能
但是也一样有如下合法用处
1、忘记使用显示的终止方法时,终结方法可以充当“安全网”,虽然不能保证终结方法及时的执行,但总比没有的强,这里的终止方法简单介绍一下,典型的例子就是InputStream的close方法,一般和try、finally一起用。
2、与对象本地对等体有关,本地对等体对象不是一个普通的对象,所以Java 垃圾回收器不会回收它,用终结方法执行回收任务最合适不过了。