提升Java代码质量(一)

博主双12入手了一本"Effective Java第二版",本系列文章将初步梳理书中内容,我也查了些资料,我会针对知识点做一点展开,方便以后复习回顾;

Item1.考虑用静态工厂代替构造器:

    静态工厂的优势:

更易于阅读(有名称)

可以做成单例(Singleton)的
可以实现多态(返回多个子类型的对象)
在创建参数化类型的实例时,他们使代码变得更加简洁

     静态工厂存在的不足:

      1.类如果不含共有的或者受保护的构造器,就不能被子类化;

      2.他们与其它的静态方法其实没区别,因此对于客户来说如何使用变成了难题.

 

 Item2:对于多个构造器参数时,利用构建器(Builder Mode):

    利用构造器重载确实可以解决少量构造器参数对象的初始化,但大量比如十几个甚至几十个的时候,客户端的代码很难编写,更别说阅读了,建议用建造者模式来解决;

    建造者模式的核心就是:将需要的域(包括必须的参数和不必须的参数)放在一个Builder类中,必须的参数放在Builder的构造器中初始化(只要用到Builder对象就会调用其构造器),可选参数利用对应的set方法供客户端调用实现初始化:

//Builder Parttern
public class User {
        private final String userName;
        private final String pwd;
        private final String mobile;
        private final String e_mail;

        public static class Builder {
                //Required parameters
                private final String userName;
                private final String pwd;
                
                //Optional parameters - initialized to default values
                private final String mobile = "13900000000";
                private final String e_mail = "1@1.com";
                
                public Builder(String userName, String pwd){
                        this.userName = userName;
                        this.pwd = pwd;
                }
                
                public Builder mobile(String mobile){
                        this.mobile = mobile;
                        return this;
                }

                public Builder e_mail(String e_mail){
                        this.e_mail = e_mail;
                        return this;
                 }

                 public User build(){
                         return new User(this);
                 }
        }
        
        private User(Builder builder){
                userName = builder.userName;
                pwd = builder.pwd;
                mobile = builder.mobile;
                e_mail = builder.e_mail;
        }
}


//Client Code
User user = new User.Builder("Joey","123").mobile("13512511111").
                        e_mail("joey@gmail.com");

    但建造者模式实现也不是完美的,为了创建对象,必须先创建其构建器,在十分注重性能的场景下,它有可能比重载构造器更加冗长,如果要用建造者模式,最好一开始就用(不要和构造器或静态工厂混用).

 

Item3:用私有构造器或者枚举类型强化Singleton属性:

    我们平常构造Singleton的时候,一般先私有化构造器,再利用静态工厂控制对象,但享有特权的客户端可以借助AccessibleObject.setAccessible方法,通过反射机制调用私有构造器,如果要抵御这种攻击,可以改造构造器,让构造器创建第二个实例的时候抛出异常;

    当然有更好的方法,只需编写一个包含单个元素的枚举类型:

public enum Singleton {
        INSTANCE;
        
        public void leaveTheBuilding(){...}
}

     此方法既可以完美地防止了多次实例化,并无偿提供了序列化机制,即便面对复杂序列化或反射攻击的时候.....

 

 Item4:避免创建不必要的对象:

    此条目涵盖的内容比较多,中心点就是能重用(immutable)的对象就不要去创建一个相同功能的对象.下面有些例子:

      1.尽量少用new String(),推荐把字符串放入常量池:String str = "abc";

      2.方法中实例化Calendar类的对象,若多次调用,会产生多个相同功能的对象,解决办法:写一个静态代码块,可重用的对象或者变量都可以放进去;

      3.适配器(adapter)模式中,有些特定的适配器不需要多个适配器实例,例如:Map接口的keySet方法返回Map中key的Set,感觉上,每次调用keySet都创建了一个新的实例,实际上用的是同一个实例,因为此实例的作用是一样的,虽然多个实例是没有害处的,同样,没有必要这么做;

      4.再Java1.5的发行版本中,拥有自动装箱(autoboxing)的新特性,观察以下代码:

public static coid main(String []args){
        Long sum = 0L;
        for(long i = 0; i < Integer.MAX_VALUE; i++){
                sum += i;   //无意识的自动装箱
        }
        System.out.println(sum);
}

 

        自动装箱的过程中会自动创建包装类的实例,如果执行完上面的代码,JVM会多构造了大约231个实例,如果将sum定义为基本数据类型long,性能将会提高几倍..

    

    当然并不意味着我们必须尽可能地避免创建对象,通过创建代价不大的小对象来提升程序的清晰性和间接性是非常好的.

    总结一句就是:当你应该重用对象的时候,请不要创建新的对象;当你应该创建新对象的时候,请不要重用对象..

 

    

 

posted @ 2018-12-20 13:53  Joey44  阅读(1370)  评论(0编辑  收藏  举报
BACK TO TOP