zoukankan      html  css  js  c++  java
  • 《Effective Java》读书笔记一(创建与销毁对象)

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

    静态工厂方法优势:

    1. 它们有名称,阅读性增强,如:BigInteger.probablePrime;
    2. 不必每次调用它们的时候都创建一个新对象;
    3. 它们可以返回原返回类型的任何子类型的对象;
    4. 在创建参数化类型实例的时候,它们使代码变得更加简洁。

    静态工厂方法缺点:

    1. 类如果不含公有的或者受保护的构造器,就不能被子类化;
    2. 它们与其他的静态方法实际上没有任何区别。

    惯用名称:

    • getInstance       返回的实例是通过方法的参数来描述的;
    • newInstance     像getInstance一样,但newInstance能够确保返回的每个实例都与所有其它实例不同。

    No2 遇到多个构造器参数时要考虑用构建器

    2.1多个构造器(缺点:许多参数时,客户端代码难写;不易于阅读);

    // Telescoping constructor pattern - does not scale well! - Pages 11-12
    
    public class NutritionFacts {
        private final int servingSize;   // (mL)            required
        private final int servings;      // (per container) required
        private final int calories;      //                 optional
        private final int fat;           // (g)             optional
        private final int sodium;        // (mg)            optional
        private final int carbohydrate;  // (g)             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);
        }
    }

    2.2 JavaBeans模式(缺点:对象可能处于不一致的状态);

    // JavaBeans Pattern - allows inconsistency, mandates mutability - Pages 12-13
    
    public class NutritionFacts {
        // Parameters initialized to default values (if any)
        private int servingSize  = -1;  // Required; no default value
        private int servings     = -1;  //     "     "     "      "
        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);
        }
    }

    2.3 Builder模式(用一个专门的对象来存放参数,形如:new NutritionFacts(Builder builder),所有参数封装在Builder类中)。

    // Builder Pattern - Pages 14-15
    
    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 carbohydrate  = 0;
            private int sodium        = 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 carbohydrate(int val)
                { carbohydrate = val;  return this; }
            public Builder sodium(int val)
                { sodium = 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();
        }
    }

    No5 避免创建不必要的对象

    5.1 String对象的使用

    String s = new String(“stringetee”);         // DON’T DO THIS
    String s = “stringetee”;   // 正确方式,引用常量池中的对象

    5.2 注意某些方法调用频繁生成对象时,应考虑将这些对象放置到类(对象)的局部变量中。

    不好的代码如下:

    // Creates lots of unnecessary duplicate objects - page 20-21
    import java.util.*;
     
    
    public class Person {
    
        private final Date birthDate;
     
    
        public Person(Date birthDate) {
            // Defensive copy - see Item 39
            this.birthDate = new Date(birthDate.getTime());
        }
     
    
        // Other fields, methods omitted
     
    
        // DON'T DO THIS!
        public boolean isBabyBoomer() {
            // Unnecessary allocation of expensive object
            Calendar gmtCal =
                Calendar.getInstance(TimeZone.getTimeZone("GMT"));
            gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
            Date boomStart = gmtCal.getTime();
            gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
            Date boomEnd = gmtCal.getTime();
    
            return birthDate.compareTo(boomStart) >= 0 &&
                   birthDate.compareTo(boomEnd)   <  0;
        }
    }

     优化后的代码如下:

    // Doesn't creates unnecessary duplicate objects - page 21
    import java.util.*;
     
    
    class Person {
    
        private final Date birthDate;
     
    
        public Person(Date birthDate) {
            // Defensive copy - see Item 39
            this.birthDate = new Date(birthDate.getTime());
        }
     
    
        // Other fields, methods
     
    
        /**
         * The starting and ending dates of the baby boom.
         */
        private static final Date BOOM_START;
        private static final Date BOOM_END;
    
        static {
            Calendar gmtCal =
                Calendar.getInstance(TimeZone.getTimeZone("GMT"));
            gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
            BOOM_START = gmtCal.getTime();
            gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
            BOOM_END = gmtCal.getTime();
        }
     
    
        public boolean isBabyBoomer() {
            return birthDate.compareTo(BOOM_START) >= 0 &&
                   birthDate.compareTo(BOOM_END)   <  0;
        }
    }

    5.3 JDK1.5之后,自动装箱功能可能导致代码BUG。

    如下代码:

    // Hideously slow program! Can you spot the object creation?
    public static void main(String[] args) {
        Long sum = 0L;
    
    for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; } System.out.println(sum); }

    这段程序算出的结果是正确的,但是比实际情况要更慢一些,只因为打错了一个字符。变量sum被声明成Long而不是long。要优先使用基本类型而不是装箱基本类型,要当心无意意识的自动装箱。

    No7 避免使用终结方法

    Java语言规范不仅不保证终结方法会被及时地执行,而且根本就不保证它们会被执行。

    显式终止方法的典型盒子是InputStream,OutputStream和java.sql.Connection上的close方法。另一个例子是java.util.Timer上的cancel方法,它执行必须的状态改变,使得与Timer实例相关联的该线程温和地终止自己。

    显式的终止方法通常与try-finally结构结合起来使用,以确保及时终止。

  • 相关阅读:
    Java实现 LeetCode 343 整数拆分(动态规划入门经典)
    Java实现 LeetCode 342 4的幂
    Java实现 LeetCode 342 4的幂
    Java实现 LeetCode 342 4的幂
    Java实现 LeetCode 341 扁平化嵌套列表迭代器
    Java实现 LeetCode 341 扁平化嵌套列表迭代器
    Java实现 LeetCode 341 扁平化嵌套列表迭代器
    Java实现 LeetCode 338 比特位计数
    H264(NAL简介与I帧判断)
    分享一段H264视频和AAC音频的RTP封包代码
  • 原文地址:https://www.cnblogs.com/nayitian/p/3245426.html
Copyright © 2011-2022 走看看