5、使用原始类型和栈
之前介绍了来自 jOOQ的例子中使用了大量的泛型,导致的结果是使用了 byte、 short、 int 和 long 的包装类。但至少泛型在Java 10或者Valhalla项目中被专门化之前,不应该成为代码的限制。因为可以通过下面的方法来进行替换:
//存储在堆上
Integer i = 817598;
……如果这样写的话:
// 存储在栈上
int i = 817598;
在使用数组时情况可能会变得更加糟糕:
//在堆上生成了三个对象
Integer[] i = { 1337, 424242 };
……如果这样写的话:
// 仅在堆上生成了一个对象
int[] i = { 1337, 424242 };
小结
当我们处于 N.O.P.E. 分支的深处时,应该极力避免使用包装类。这样做的坏处是给GC带来了很大的压力。GC将会为清除包装类生成的对象而忙得不可开交。
所以一个有效的优化方法是使用基本数据类型、定长数组,并用一系列分割变量来标识对象在数组中所处的位置。
遵循LGPL协议的 trove4j 是一个Java集合类库,它为我们提供了优于整形数组 int[] 更好的性能实现。
例外
下面的情况对这条规则例外:因为 boolean 和 byte 类型不足以让JDK为其提供缓存方法。我们可以这样写:
Boolean a1 = true; // ... syntax sugar for:
Boolean a2 = Boolean.valueOf(true);
Byte b1 = (byte) 123; // ... syntax sugar for:
Byte b2 = Byte.valueOf((byte) 123);
其它整数基本类型也有类似情况,比如 char、short、int、long。
不要在调用构造方法时将这些整型基本类型自动装箱或者调用 TheType.valueOf() 方法。
也不要在包装类上调用构造方法,除非你想得到一个不在堆上创建的实例。
非堆存储
当然了,如果你还想体验下堆外函数库的话,尽管这可能参杂着不少战略决策,而并非最乐观的本地方案。