EffectiveJava 1创建和销毁对象 5避免创建不必要的对象


1    重点关注

1.1  代码演练部分

1.2  本节精髓

不要错误的认为本条目介绍的内容暗示着”创建对象的代价非常昂贵,我们应该尽可能地避免创建对象”
  相反,由于小对象的构造器只做很少量的事情,所以它们的创建和销毁的代价都是非常廉价的,尤其是在现代的的JVM实现上更是的如此。通过创建附加的对象,提升程序的清晰性、间接性、和功能性,这通常是件好事。
  反之,通过维护不必要的线程池来避免创建兑现更并不是一种好的做法,除非对象池中的对象非常重量级比如 数据库连接池、线程池,这些对象创建的代价非常昂贵、因此重用这些对象就显得非常有意义。一般而言,维护自己的对象池,可能会把代码弄的非常乱,同时增加了内存的占用(除非你的对象池有非常好释放)。

2    课程内容

2.1  避免创建不必要对象的场景

对象不可变,重用,参考3.1

已知不会修改的可变对象,重用,参考3.2

基本数据类型和装箱基本数据类型,使用基本数据类型,参考3.3

适配器,重用 参考3.4(这个我理解只是告知,一般开发我们用不到这)

2.2  创建对象而不是重用的场景

提倡使用保护性拷贝时,创建重复对象代价更小,

2.3  本节精髓

参考2.1

3    代码演练

3.1  boolean案例 重用不可变对象

package com.ddwei.test.core.chapter5.demo1;

public class BooleanTest {

    /**
     * 对于同时提供静态工厂方法和构造器的不可变类,通常使用静态工厂方法而不是构造器
     * 如下方案例,使用valueof 而不是new 新对象
     * @author weidoudou
     * @date 2022/6/22 7:46
     * @param args 请添加参数描述
     * @return void
     **/
    public static void main(String[] args) {


        String s1 = "true";
        Boolean b1 = new Boolean(s1);
        Boolean b2 = Boolean.valueOf(s1);

        String s2 = "57";
        Integer i1 = new Integer(s2);
        Integer i2 = Integer.valueOf(s2);


    }

}

3.2  重用不会被修改的可变对象

反例:

package com.ddwei.test.core.chapter5.demo2;

import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

/**
 * 生育高峰期的小孩(1946-1964)
 */
public class Person {

    /**
     *
     * @author weidoudou
     * @date 2022/6/22 7:52
     * @param birthday 请添加参数描述
     * @return boolean
     **/
    public boolean isBabyBoomer(Date birthday){
        Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        //分别拿到1946 和 1964年的日期
        gmtCal.set(1946,Calendar.JANUARY,1,0,0,0);
        Date beginDate = gmtCal.getTime();
        gmtCal.set(1965,Calendar.JANUARY,1,0,0,0);
        Date endDate = gmtCal.getTime();
        return birthday.compareTo(beginDate)>=0 &&
                birthday.compareTo(endDate)<0;

    }

}

正例:

package com.ddwei.test.core.chapter5.demo2;

import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

/**
 * 生育高峰期的小孩(1946-1964)
 */
public class Person2 {

    private final static Date BEGIN_DATE;
    private final static Date END_DATE;

    static{
        Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        //分别拿到1946 和 1964年的日期
        gmtCal.set(1946,Calendar.JANUARY,1,0,0,0);
        BEGIN_DATE = gmtCal.getTime();
        gmtCal.set(1965,Calendar.JANUARY,1,0,0,0);
        END_DATE = gmtCal.getTime();
    }

    /**
     *
     * @author weidoudou
     * @date 2022/6/22 7:52
     * @param birthday 请添加参数描述
     * @return boolean
     **/
    public boolean isBabyBoomer(Date birthday){
        return birthday.compareTo(BEGIN_DATE)>=0 &&
                birthday.compareTo(END_DATE)<0;

    }

}

3.3  数据量较大时,建议使用基本数据类型而不是装箱基本类型(装箱拆箱耗时)

反例:运行6秒 (我的8核)

package com.ddwei.test.core.chapter5.demo3;

public class CreateObject {

    public static void main(String[] args) {
        Long sum = 0L;
        for(long i = 0;i < Integer.MAX_VALUE; i++){
            sum+=i;
        }
        System.out.println(sum);
    }

}

正例:运行2秒

package com.ddwei.test.core.chapter5.demo3;

public class CreateObject2 {

    public static void main(String[] args) {
        Long sum = 0L;
        long sum2 = sum.longValue();
        for(long i = 0;i < Integer.MAX_VALUE; i++){
            sum2+=i;
        }
        System.out.println(sum2);
    }

}

3.4  针对给定对象的特定适配器,不需要创建多个适配器

package com.ddwei.test.core.chapter5.demo4;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class KeySet {

    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("1","a");
        map.put("2","b");
        map.put("3","c");
        map.put("4","d");
        Set key1 = map.keySet();
        Set key2 = map.keySet();
        Set key3 = map.keySet();
        System.out.println(key1);
        System.out.println(key2);
        System.out.println(key3);

        key1.remove("1");
        System.out.println(key1);
        System.out.println(key2);
        System.out.println(key3);

    }

}