Effective Java 3

《Effective Java》做者是美国的Joshua Bloch,连Gosling都说须要看的书,讨论的是更深层次的Java开发技术,适合于有必定Java基础的人看。html

这是一本分享经验于指引您少走弯路的经典著做,针对如何编写高效、设计优良的程序提出了最实用的方针。程序员

 

 

Item1 考虑用静态工厂方法代替构造器数组

一、优势缓存

可读性强。安全

不会每次调用就经过构造器建立一个新的实例。工具

能够返回原始类型的任何子类型。性能

二、缺点ui

只有私有构造器没法被子类化。this

 

Item 2 遇到多个构造器参数考虑用构建器Builderspa

 

一、传统的重叠构造器模式

 

public class NutritionFacts {
    private final int servingSize;  // (mL)            required
    private final int servings;     // (per container) required
    private final int calories;     // (per serving)   optional
    private final int fat;          // (g/serving)     optional
    private final int sodium;       // (mg/serving)    optional
    private final int carbohydrate; // (g/serving)     optional

    public NutritionFacts(int servingSize, int servings) {
        this(servingSize, servings, 0);
    }

    public NutritionFacts(int servingSize, int servings,
                          int calories) {
        this(servingSize, servings, calories, 0);
    }

    public NutritionFacts(int servingSize, int servings,
                          int calories, int fat) {
        this(servingSize, servings, calories, fat, 0);
    }

    public NutritionFacts(int servingSize, int servings,
                          int calories, int fat, int sodium) {
        this(servingSize, servings, calories, fat, sodium, 0);
    }
    public NutritionFacts(int servingSize, int servings,
                          int calories, int fat, int sodium, int carbohydrate) {
        this.servingSize  = servingSize;
        this.servings     = servings;
        this.calories     = calories;
        this.fat          = fat;
        this.sodium       = sodium;
        this.carbohydrate = carbohydrate;
    }

    public static void main(String[] args) {
        NutritionFacts cocaCola =
                new NutritionFacts(240, 8, 100, 0, 35, 27);
    }
    
}

  

若是读者想了解那些值是什么意思,必须很费劲的仔仔细细的数着这些参数来探究。若是客户端不当心颠倒了这些参数的顺序,编译器也不会报错,可是程序在运行时会出现错误行为。

JavaBeans模式

public class NutritionFacts {
    // Parameters initialized to default values (if any)
    private int servingSize  = -1; // Required; no default value
    private int servings     = -1; // Required; no default value
    private int calories     = 0;
    private int fat          = 0;
    private int sodium       = 0;
    private int carbohydrate = 0;

    public NutritionFacts() { }
    // Setters
    public void setServingSize(int val)  { servingSize = val; }
    public void setServings(int val)     { servings = val; }
    public void setCalories(int val)     { calories = val; }
    public void setFat(int val)          { fat = val; }
    public void setSodium(int val)       { sodium = val; }
    public void setCarbohydrate(int val) { carbohydrate = val; }

    public static void main(String[] args) {
        NutritionFacts cocaCola = new NutritionFacts();
        cocaCola.setServingSize(240);
        cocaCola.setServings(8);
        cocaCola.setCalories(100);
        cocaCola.setSodium(35);
        cocaCola.setCarbohydrate(27);
    }
}

  

这样实例建立很容易,客户端代码读起来很清晰明朗,可是,程序员须要付出额外的努力来确保它的线程安全

Builder模式

public class NutritionFacts {
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;

    public static class Builder {
        // Required parameters
        private final int servingSize;
        private final int servings;

        // Optional parameters - initialized to default values
        private int calories      = 0;
        private int fat           = 0;
        private int sodium        = 0;
        private int carbohydrate  = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings    = servings;
        }

        public Builder calories(int val)
        { calories = val;      return this; }
        public Builder fat(int val)
        { fat = val;           return this; }
        public Builder sodium(int val)
        { sodium = val;        return this; }
        public Builder carbohydrate(int val)
        { carbohydrate = val;  return this; }

        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
    }

    private NutritionFacts(Builder builder) {
        servingSize  = builder.servingSize;
        servings     = builder.servings;
        calories     = builder.calories;
        fat          = builder.fat;
        sodium       = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }

    public static void main(String[] args) {
        NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
                .calories(100).sodium(35).carbohydrate(27).build();
    }
}

  

builder设置方法返回this,造成了链式调用,这个一个流式的API,客户端代码很容易编写,更为重要的是易于阅读。

二、使用构建器的好处。

在多参数时写法优雅,参数具备可读性,保证线程安全,适合类的继承。

三、使用构建器的坏处。

花费会更高,所以在参数有许多的时候建议使用,特别是有不少可选参数时。

 

Item 3 Singleton的最佳实现方式是枚举类型

一、什么是枚举类

public class EnumTest {
    public static void main(String[] args) {
        Scanner in=new Scanner(System.in);
        System.out.println("put:");
        String input=in.next().toUpperCase();
        Size size=Enum.valueOf(Size.class,input);
        System.out.println(size);
        System.out.println(size.getAbbreviation());
        System.out.println(Size.SMALL.getAbbreviation());
    }

}
enum Size{
    SMALL("S"),MEDIUM("M"),LARGE("L");
    private String abbreviation;
    private Size(String abbreviation){this.abbreviation=abbreviation;}
    public  String getAbbreviation(){return abbreviation;}

}

  

二、优势

提供序列化机制,甚至在反射机制下也能确保只有单例。

三、缺点

没法继承自除了Enum以外的超类以及其余子类进行继承。

 

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

一、优势

在须要建立相似工具类等不须要实例化的类时,将构造器私有化,以保证该类在任何状况下都不会被实例化。

二、缺点

没法被继承

 

Item 5 使用依赖注入去链接资源

一、依赖注入

public class dependency {
	private final String str;

	public dependency(String str) {
		this.str = str;
	}
}

  

二、优势

对于一个行为由其余资源所参数化所决定的类来讲,使用静态工具类或者单例是不适合的。而是应该当建立一个实例是将资源传入构造器。

 

Item 6 避免建立没必要要的对象

一、优势

对于一些不会发生改变的变量或是常量,使用static块进行初始化,使某些类不会被重复建立,减小开销。例如 new String就是一个很差的习惯。

在构造器中使用静态工厂就是个不错的方法。重点是对静态的使用static(final)。自动装箱也极可能引发巨大的开销。

 

Item 7消除过时的对象引用

一、优势

例如对于Stack类中的数组当执行pop()操做后,被弹出的元素并不会自动被gc所回收。所以须要手动进行释放。

    public Object pop() {
        if (size == 0)
            throw new EmptyStackException();
        Object result = elements[--size];
        elements[size] = null; // Eliminate obsolete reference
        return result;
    }

  

当一个类本身进行内存的管理时,这种情况就尤为要注意。

进行缓存时也须要注意这个问题。

对于监听器以及回调操做,也须要注意。

 

Item 8 尽可能避免使用Finalizers

一、优势

因为Finalizers的优先级很低,不能保证Finalizers什么时候会被调用,会致使内存开销的增长,而且会大幅下降程序的性能。

永远不要Finalizers来更新持久状态。

对含有Finalizers方法的类进行子类化会有严重的安全隐患。

使用try-with-resources做为某些资源的结束方法。而且对于其状态是否被关闭须要在私有域中进行记录。这样其余方法调用时能够对状态进行检测。

Finalizers有两种合理的用法:

一、在忘记调用close方法时做为一张安全网,但这也只是一个不得以的备用措施,仍然会形成很大开销,而且不知什么时候会进行。

二、native peer (?)

 

Item 9 更偏向使用 try-with-resources 块

一、try-with-resources

在try()中进行一个或多个的资源连接或读取。而且这些资源是必须被关闭的的,使用这个语法将会被自动关闭无需显示调用close方法。

在{}进行实际操做。

 一样可使用catch语句

    static void copy(String src, String dst) throws IOException {
        try (InputStream   in = new FileInputStream(src);
             OutputStream out = new FileOutputStream(dst)) {
            byte[] buf = new byte[BUFFER_SIZE];
            int n;
            while ((n = in.read(buf)) >= 0)
                out.write(buf, 0, n);
        }
    }

  

二、优势

能够同时打开多个资源,并保证被关闭,而无需显式调用close方法。

exception不会被覆盖,能够查看每一个exception.

 

 

参考:《Effective Java》第3版

参考:https://www.cnblogs.com/WutingjiaWill/p/9139520.html

相关文章
相关标签/搜索