蓝桥-10种简单的Java性能优化

10种简单的Java性能优化

2017-09-04

  Java代码优化的金科玉律不外乎以下内容:

    良好的设计将会使优化变得更加容易。

    过早的优化并不能解决多有的性能问题,但是不良的设计将会导致优化难度的增加。

    理论就先谈到这里。假设我们已经发现了问题出现在了右分支上,很有可能是因产品中的简单处理因耗费了大量的时间而失去响应(假设N、O和 P 的值非常大), 请注意文章中提及的左分支的时间复杂度为 O(N3)。这里所做出的努力并不能扩展,但可以为用户节省时间,将困难的性能改善推迟到后面再进行。今天蓝桥先给大家推荐5条改善Java性能的小建议:


  1、使用StringBuilder

    StingBuilder 应该是在我们的Java代码中默认使用的,应该避免使用 + 操作符。或许你会对 StringBuilder 的语法糖(syntax sugar)持有不同意见,比如:

4.png

  将会被编译为:

1504489381339443.png

  但究竟发生了什么?接下来是否需要用下面的部分来对 String 类改善呢?

6.png

  现在使用到了第二个 StringBuilder,而且这个 StringBuilder 不会消耗堆中额外的内存,但却给 GC 带来了压力。

7.png


  2、避免使用正则表达式

    正则表达式给人的印象是快捷简便。但是在 N.O.P.E 分支中使用正则表达式将是最糟糕的决定。如果万不得已非要在计算密集型代码中使用正则表达式的话,至少要将 Pattern 缓存下来,避免反复编译Pattern。

8.png

    如果仅使用到了如下这样简单的正则表达式的话:

9.png

    这是最好还是用普通的 char[] 数组或者是基于索引的操作。比如下面这段可读性比较差的代码其实起到了相同的作用。

1504489445844995.png

    上面的代码同时表明了过早的优化是没有意义的。虽然与 split() 方法相比较,这段代码的可维护性比较差。


  3、不要使用iterator()方法

这条建议不适用于一般的场合,仅适用于在 N.O.P.E 分支深处的场景。尽管如此也应该有所了解。Java 5格式的循环写法非常的方便,以至于我们可以忘记内部的循环方法,比如:

11.png

    当每次代码运行到这个循环时,如果 strings 变量是一个 Iterable 的话,代码将会自动创建一个Iterator 的实例。如果使用的是 ArrayList 的话,虚拟机会自动在堆上为对象分配3个整数类型大小的内存。

1504489474524425.png

    也可以用下面等价的循环方式来替代上面的 for 循环,仅仅是在栈上“浪费”了区区一个整形,相当划算。

13.png

    如果循环中字符串的值是不怎么变化,也可用数组来实现循环。

14.png

  4、不要调用高开销方法

    有些方法的开销很大。以 N.O.P.E 分支为例,我们没有提到叶子的相关方法,不过这个可以有。假设我们的JDBC驱动需要排除万难去计算 ResultSet.wasNull() 方法的返回值。我们自己实现的SQL框架可能像下面这样:在上面的逻辑中,每次从结果集中取得 int 值时都要调用 ResultSet.wasNull() 方法,但是 getInt() 的方法定义为:返回类型:变量值;如果SQL查询结果为NULL,则返回0。所以一个简单有效的改善方法如下:

16.png

    这是轻而易举的事情。


  5、使用原始类型和栈

    上面介绍了来自 jOOQ的例子中使用了大量的泛型,导致的结果是使用了 byte、 short、 int 和 long 的包装类。但至少泛型在Java 10或者Valhalla项目中被专门化之前,不应该成为代码的限制。因为可以通过下面的方法来进行替换:

17.png

    ……如果这样写的话:

18.png

    在使用数组时情况可能会变得更加糟糕:

19.png

    ……如果这样写的话:

20.png

    例外下面的情况对这条规则例外:因为 boolean 和 byte 类型不足以让JDK为其提供缓存方法。我们可以这样写:

1504489656494704.png

    其它整数基本类型也有类似情况,比如 char、short、int、long。不要在调用构造方法时将这些整型基本类型自动装箱或者调用 TheType.valueOf() 方法。也不要在包装类上调用构造方法,除非你想得到一个不在堆上创建的实例。这样做的好处是为你为同事献上一个巨坑的愚人节笑话。


  非堆存储

    当然了,如果你还想体验下堆外函数库的话,尽管这可能参杂着不少战略决策,而并非最乐观的本地方案。一篇由Peter Lawrey和 Ben Cotton撰写的关于非堆存储的很有意思文章请点击: OpenJDK与HashMap——让老手安全地掌握(非堆存储!)新技巧。


上一篇:还没学会用成本思维做决策?

下一篇:三十五年经验分享:程序员进阶八法