避免创建不必要的对象
在每次需要时重用一个对象而不是创建一个新的相同功能对象通常是恰当的。重用可以更快更流 行。如果对象是不可变的(详见第 17 条),它总是可以被重用。 作为一个不应该这样做的极端例子,请考虑以下语句:
String s = new String("bikini");
语句每次执行时都会创建一个新的 String 实例,而这些对象的创建都不是必需的。String 构造方法 ("bikini") 的参数本身就是一个 bikini 实例,它与构造方法创建的所有对象的功能相同。如果 这种用法发生在循环中,或者在频繁调用的方法中,就会毫无必要地创建数百万个 String 实例。 改进后的版本如下
xxxxxxxxxx
String s = "bikini";
通过使用静态工厂方法(详见第 1 条)和构造器,可以避免创建不需要的对象。例如,工厂方法 Boolean.valueOf(String) 比构造方法 Boolean(String) 更可取,后者在 Java 9 中被弃用。构 造方法每次调用时都必须创建一个新对象,而工厂方法永远不需要这样做,在实践中也不需要。除了重 用不可变对象,如果知道它们不会被修改,还可以重用可变对象。
假设你想写一个方法来确定一个字符串是否是一个有效的罗马数字。 以下是使用正则表达式完成此操作时最简单方 法:
xxxxxxxxxx
// Performance can be greatly improved!
static boolean isRomanNumeral(String s) {
return s.matches("^(?=.)M*(C[MD]|D?C{0,3})"
+ "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
}
这个实现的问题在于它依赖于 String.matches 方法。 虽然 String.matches 是检查字符串 是否与正则表达式匹配的最简单方法,但它不适合在性能临界的情况下重复使用。 问题是它在内部为正 则表达式创建一个 Pattern 实例,并且只使用它一次,之后它就有资格进行垃圾收集。 创建 Pattern 实例是昂贵的,因为它需要将正则表达式编译成有限状态机(finite state machine)
为了提高性能,作为类初始化的一部分,将正则表达式显式编译为一个 Pattern 实例(不可变),缓存它,并在 isRomanNumeral 方法的每个调用中重复使用相同的实例
xxxxxxxxxx
// Reusing expensive object for improved performance
public class RomanNumerals {
private static final Pattern ROMAN = Pattern.compile(
"^(?=.)M*(C[MD]|D?C{0,3})"
+ "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
static boolean isRomanNumeral(String s) {
return ROMAN.matcher(s).matches();
}
}
另一种创建不必要的对象的方法是自动装箱(auto boxing)
xxxxxxxxxx
// Hideously slow! Can you spot the object creation?
private static long sum() {
Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++)
sum += i;
return sum;
}
变量 sum 被声明成了 Long 而不是 long ,这意味着程序构造了大约 231 不必要的 Long 实例(大约每次往 Long 类型的 sum 变量中增加一个 long 类型构造的实例),把 sum 变量的类型由 Long 改为 long ,在我的机器上运行时间从 6.3 秒降低到 0.59 秒。这个教训很明显:优先使用基本类型而不是装 箱的基本类型,也要注意无意识的自动装箱
来源:https://www.cnblogs.com/lIllIll/p/12556567.html