如何避免无意间创建多余对象

简介: 6 避免创建不必要的对象从字面意思上来看,大家肯定都知道创建不必要的对象是错误的做法。但这一节其实主要是提醒我们避免无意识的创建不必要对象的代码写法。

6 避免创建不必要的对象


从字面意思上来看,大家肯定都知道创建不必要的对象是错误的做法。但这一节其实主要是提醒我们避免无意识的创建不必要对象的代码写法。


例1:


String s = new String("abc");


是错误的写法,正确的写法应该是:


String s = "abc";


原因是第一种写法每次被执行的时候都会创建一个新的String实例,但这些全都是重复的!



例2:


我们要优先使用静态工厂方法而不是构造器来避免创建不必要的对象,如Boolean.valueOf(String)总是要优先于构造器Boolean(String)使用。因为构造器每次被调用都会创建一个新对象,静态工厂不这样。



例3:


创建成本昂贵的对象时,应该将其缓存起来。


例如正则表达式匹配的代码中,String.matches方法内部创建了一个Pattern实例,这个创建的成本很高,因为需要将正则表达式编译成有限状态机,所以应该将其缓存起来:

public class RomanNumerals {
  private static final Pattern ID = Pattern.compile("^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$");
  static boolean isRomanNumeral(String s){
    return ID.matcher(s).matches();
  }
}


这样一来,每次调用isRomanNumeral时都会重用同一个ID实例



例4:


上面的Pattern实例是不变的,但在某些场景下实例是可变的,这时就可以考虑适配器。适配器是这样一个对象:它将功能委托给一个后备对象,为后备对象提供一个替代前面功能的接口。


例如Map接口的KeySet方法,每次调用返回的都是同一个Set实例,虽然Set实例是可变的,但其中一个变化时其他的也会跟着变,因为他们本身就是一个。



例5:


优先使用基本类型而不是装箱类型,原因在于下面这个例子:


private static long sum(){
  Long sum = 0L;
  for(long i = 0; i <= Integer.MAX_VALUE; i ++)
    sum += i;
  return sum;
}

这段程序执行起来没有任何问题,但实际情况会慢一点,因为sum的类型是Long而不是long,所以程序构造了大约2^31个Long实例。


这一点在我记忆中和工作里的要求不一致,为此我专门去翻阅了阿里巴巴Java开发手册,里面是这样描写的:


28.png

可见公司在这个问题的考虑上是业务优先了,所以小伙伴们可以斟酌使用时的取舍,我个人还是推荐使用包装类型的。


避免一个误区:

不要看完这一章节就陷入了创建对象的代价非常昂贵的逻辑怪圈里去了,反之维护自己的对象池来避免创建对象是一种错误的做法。因为现代JVM的实现里有高度优化的垃圾收集器,其性能很容易就超过了轻量级对象池的性能。


一个正确的示例是数据库连接池,因为建立一个数据库的连接是非常昂贵的。


相关文章
|
7月前
【BUG】循环中重复使用对象一定要注意
【BUG】循环中重复使用对象一定要注意
|
8月前
|
Arthas 运维 监控
定位频繁创建对象导致内存溢出风险的思路
定位频繁创建对象导致内存溢出风险的思路
176 1
|
设计模式 消息中间件 JavaScript
干掉 “重复代码”,这三种方式绝了!
干掉 “重复代码”,这三种方式绝了!
36912 2
干掉 “重复代码”,这三种方式绝了!
|
Java
JAVA数组批量设值(初始化)的办法
JAVA数组批量设值(初始化)的办法
126 0
|
设计模式 算法 Java
干掉 “重复代码” 的技巧有哪些
软件工程师和码农最大的区别就是平时写代码时习惯问题,码农很喜欢写重复代码而软件工程师会利用各种技巧去干掉重复的冗余代码。
106 0
干掉 “重复代码” 的技巧有哪些
|
数据库连接 数据库 数据安全/隐私保护
对象变量或with块变量未设置————问题根源
对象变量或with块变量未设置————问题根源
1111 0
对象变量或with块变量未设置————问题根源
你真的明白关于迭代器的方法、使用异常、并发修改异常介绍嘛?
关于迭代器的方法、使用异常、并发修改异常介绍的使用
103 0
你真的明白关于迭代器的方法、使用异常、并发修改异常介绍嘛?
|
Web App开发 存储 JavaScript
JavaScript原生之标记清理原理
JavaScript原生之标记清理原理
90 0
|
编译器 C++
C++当心资源管理类中的拷贝行为
C++当心资源管理类中的拷贝行为
124 0
集合或映射迭代过程进行删除或修改操作的时候会导致并发异常
集合或映射迭代过程进行删除或修改操作的时候会导致并发异常
126 0
集合或映射迭代过程进行删除或修改操作的时候会导致并发异常