java性能优化方案5——使用原始类型和栈

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() 方法。
也不要在包装类上调用构造方法,除非你想得到一个不在堆上创建的实例。
非堆存储
当然了,如果你还想体验下堆外函数库的话,尽管这可能参杂着不少战略决策,而并非最乐观的本地方案。

时间: 2024-10-28 00:59:58

java性能优化方案5——使用原始类型和栈的相关文章

java性能优化方案9——优化自定义hasCode()方法和equals()方法

9.优化自定义hasCode()方法和equals()方法在不能使用EnumMap的情况下,至少也要优化 hashCode() 和 equals() 方法.一个好的 hashCode() 方法是很有必要的,因为它能防止对高开销 equals() 方法多余的调用.在每个类的继承结构中,需要容易接受的简单对象.让我们看一下jOOQ的 org.jooq.Table 是如何实现的?最简单.快速的 hashCode() 实现方法如下:// AbstractTable一个通用Table的基础实现: @Ove

java性能优化方案10——考虑使用set而并非单个元素

10.考虑使用set而并非单个元素最后,还有一种情况可以适用于所有语言而并非仅仅同Java有关.除此以外,我们以前研究的N.O.P.E. 分支也会对了解从 O(N3) 到 O(n log n)有所帮助.不幸的是,很多程序员的用简单的.本地算法来考虑问题.他们习惯按部就班地解决问题.这是命令式(imperative)的"是/或"形式的函数式编程风格.这种编程风格在由纯粹命令式编程向面对象式编程向函数式编程转换时,很容易将"更大的场景(bigger picture)"模

java性能优化方案3——不要使用iterator()方法

3.不要使用iterator()方法这条建议不适用于一般的场合,仅适用于在 N.O.P.E 分支深处的场景.尽管如此也应该有所了解.Java 5格式的循环写法非常的方便,以至于我们可以忘记内部的循环方法,比如:for (String value : strings) { // Do something useful here }当每次代码运行到这个循环时,如果 strings 变量是一个 Iterable 的话,代码将会自动创建一个Iterator 的实例.如果使用的是 ArrayList 的话

java性能优化方案6——避免递归

6.避免递归现在,类似Scala这样的函数式编程语言都鼓励使用递归.因为递归通常意味着能分解到单独个体优化的尾递归(tail-recursing).如果你使用的编程语言能够支持那是再好不过.不过即使如此,也要注意对算法的细微调整将会使尾递归变为普通递归.希望编译器能自动探测到这一点,否则本来我们将为只需使用几个本地变量就能搞定的事情而白白浪费大量的堆栈框架(stack frames).小结这节中没什么好说的,除了在 N.O.P.E 分支尽量使用迭代来代替递归.

java性能优化方案2——避免使用正则表达式

2.避免使用正则表达式正则表达式给人的印象是快捷简便.但是在 N.O.P.E 分支中使用正则表达式将是最糟糕的决定.如果万不得已非要在计算密集型代码中使用正则表达式的话,至少要将 Pattern 缓存下来,避免反复编译Pattern.static final Pattern HEAVY_REGEX = Pattern.compile("(((X)*Y)*Z)*"); 如果仅使用到了如下这样简单的正则表达式的话:1 String[] parts = ipAddress.split(&qu

java性能优化方案1——使用StringBuilder

1.使用StringBuilderStingBuilder 应该是在我们的Java代码中默认使用的,应该避免使用 + 操作符.或许你会对 StringBuilder 的语法糖(syntax sugar)持有不同意见,比如:1 String x = "a" + args.length + "b";将会被编译为: 0 new java.lang.StringBuilder [16] 3 dup 4 ldc [18] 6 invokespecial java.lang.S

java性能优化方案8——使用EnumSet或EnumMap

8.使用EnumSet或EnumMap在某些情况下,比如在使用配置map时,我们可能会预先知道保存在map中键值.如果这个键值非常小,我们就应该考虑使用 EnumSet 或 EnumMap,而并非使用我们常用的 HashSet 或 HashMap.下面的代码给出了很清楚的解释:private transient Object[] vals; public V put(K key, V value) { // ... int index = key.ordinal(); vals[index] =

java性能优化方案——使用entrySet()

7.使用entrySet()当我们想遍历一个用键值对形式保存的 Map 时,必须要为下面的代码找到一个很好的理由:for (K key : map.keySet()) { V value : map.get(key); }更不用说下面的写法:for (Entry entry : map.entrySet()) { K key = entry.getKey(); V value = entry.getValue(); }在我们使用 N.O.P.E. 分支应该慎用map.因为很多看似时间复杂度为 O

java性能优化方案4——不要调用高开销方法

4.不要调用高开销方法有些方法的开销很大.以 N.O.P.E 分支为例,我们没有提到叶子的相关方法,不过这个可以有.假设我们的JDBC驱动需要排除万难去计算 ResultSet.wasNull() 方法的返回值.我们自己实现的SQL框架可能像下面这样:if (type == Integer.class) { result = (T) wasNull(rs, Integer.valueOf(rs.getInt(index))); } // And then...static final T was