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); } }