java开发中代码级别的优化方法总结,有效提高程序性能

代码级别的优化

负载测试和应用程序监控对于确定应用程序的一些关键性能瓶颈非常有用。但同时,我们需要遵循良好的编码习惯,以避免在对应用程序进行监控的时候出现过多的性能问题。

在下一章节中,我们将来看一些最佳实践。

使用StringBuilder来连接字符串

字符串连接是一个非常常见的操作,也是一个低效率的操作。简单地说,使用+=来追加字符串的问题在于每次操作都会分配新的String。

下面这个例子是一个简化了的但却很典型的循环。前面使用了原始的连接方式,后面使用了构建器:

public String stringAppendLoop() {
    String s = "";    for (int i = 0; i < 10000; i++) {        if (s.length() > 0)
            s += ", ";
        s += "bar";
    }    return s;
}public String stringAppendBuilderLoop() {
    StringBuilder sb = new StringBuilder();    for (int i = 0; i < 10000; i++) {        if (sb.length() > 0)
            sb.append(", ");
        sb.append("bar");
    }    return sb.toString();
}

上面代码中使用的StringBuilder对性能的提升非常有效。请注意,现代的JVM会在编译或者运行时对字符串操作进行优化。

避免递归

导致出现StackOverFlowError错误的递归代码逻辑是Java应用程序中另一种常见的问题。如果无法去掉递归逻辑,那么尾递归作为替代方案将会更好。

我们来看一个头递归的例子:

public int factorial(int n) {    if (n == 0) {        return 1;
    } else {        return n * factorial(n - 1);
    }
}

现在我们把它重写为尾递归:

private int factorial(int n, int accum) {    if (n == 0) {        return accum;
    } else {        return factorial(n - 1, accum * n);
    }
}public int factorial(int n) {    return factorial(n, 1);
}

其他JVM语言(如Scala)已经在编译器级支持尾递归代码的优化,当然,对于这种优化目前也存在着一些争议。

谨慎使用正则表达式

正则表达式在很多场景中都非常有用,但它们往往具有非常高的性能成本。了解各种使用正则表达式的JDK字符串方法很重要,例如String.replaceAll()、String.split()。

如果你不得不在计算密集的代码段中使用正则表达式,那么需要缓存Pattern的引用而避免重复编译:

static final Pattern HEAVY_REGEX = Pattern.compile("(((X)*Y)*Z)*");

使用一些流行的库,比如Apache Commons Lang也是一个很好的选择,特别是在字符串的操作方面。

避免创建和销毁过多的线程

线程的创建和处置是JVM出现性能问题的常见原因,因为线程对象的创建和销毁相对较重。

如果应用程序使用了大量的线程,那么使用线程池会更加有用,因为线程池允许这些昂贵的对象被重用。

为此,Java的ExecutorService是线程池的基础,它提供了一个高级API来定义线程池的语义并与之进行交互。

Java 7中的Fork/Join框架也值得提一下,因为它提供了一些工具来尝试使用所有可用的处理器核心以帮助加速并行处理。为了提高并行执行效率,框架使用了一个名为ForkJoinPool的线程池来管理工作线程。

原文发布于微信公众号 - Java学习网(javalearns)

原文发表时间:2018-10-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java一日一条

8种常见的Java不规范代码

在工作上,我最近对一个现有的Java项目代码进行了清理。完成之后,我发现了一些反复出现的不规范代码。所以,我把它们整理成了一个列表出来分享给我的同行希望能引起注...

1301
来自专栏冰霜之地

高效的数据压缩编码方式 Protobuf

Protocol buffers 是一种语言中立,平台无关,可扩展的序列化数据的格式,可用于通信协议,数据存储等。

2961
来自专栏杂烩

duubo分组聚合 原

除了官网上有这部分的简单介绍外,在别的地方几乎找到真正可行的测试了,这里自己捣鼓一下,已做备忘。

781
来自专栏技术栈大杂烩

Python: 受限制的 "函数调用"

函数功能简单明了, 对于结果, 大家应该也不会有太大的异议:func分别是取得全局命名空间中a的值和使用内置命名空间中的函数id获取了a的地址. 熟悉Pytho...

1553
来自专栏猿人谷

C++内存管理学习堆和栈

一 C++内存管理 1.内存分配方式   在讲解内存分配之前,首先,要了解程序在内存中都有什么区域,然后再详细分析各种分配方式。 1.1 C语言和C++内存分...

3676
来自专栏宋凯伦的技术小栈

分享调用Java private方法

上周在修复bug时,发现Java类中某方法是private,且类中没有用到,第一感觉是方法多余。其实通过分析,发现原来Native Code会通过JNI调到此方...

2245
来自专栏IT技术精选文摘

深入浅出Java 10的实验性JIT编译器Graal

1735
来自专栏Java后端技术栈

Spring AOP中JDK和CGLib动态代理哪个更快?

昨天一位知识星球的小伙伴面试的时候被问到:Spring AOP中JDK和CGLib动态代理哪个效率更高?在知识星球整理了一下,今天特分享出来,供大家参考!

1141
来自专栏技术博文

js中判断浏览器版本

var ai = { ovb: { /** * 该对象用于判断系统,系统版本,浏览器,...

5115
来自专栏代码GG之家

android MVVM开发模式(五)

android MVVM开发模式(五) 上一讲我们说了@InverseBindingAdapter标记的事情。通过这个,我们可以实现view向数据方向的传递。从...

2216

扫码关注云+社区

领取腾讯云代金券