java代码提升_几个小细节帮你提升java代码运行效率

引言

千万不要小看代码细节的优化,有时候一个很小的优化就要你的代码执行效率数倍提升,如果这个优化点调用比较频繁,甚至有可能解决你整个系统的性能瓶颈。

orElse和orElseGet

官方文档上是这么说的,

orElse:Return the value if present, otherwise return other.

orElseGet:Return the value if present, otherwise invoke other and return the result of that invocation.

描述可能没这么直观,来个例子你就明白了。

public class App {

public static void main(String[] args) {

String input = "input";

String result = Optional.ofNullable(input).orElse(defaultProcess());

System.out.println(result);

}

public static String defaultProcess() {

System.out.println("defalut process");

return "default";

}

}

运行结果:

defalut process

input

然后你猜下下面这段代码的运行结果是啥,

public class App {

public static void main(String[] args) {

String input = "input";

String result = Optional.ofNullable(input).orElseGet(() -> defaultProcess());

System.out.println(result);

}

public static String defaultProcess() {

System.out.println("defalut process");

return "default";

}

}

结果是:

input

到这里你应该已经明白了,orElse里的逻辑在任何时候都会执行,即使optional不为空。而orElseGet只在optional是空的时候才会执行。

可以想象,如果在实际项目中defaultProcess里的逻辑很耗时,使用后者对性能的提示还是很明显的。

循环中减少重复计算

比如把下面这种循环,

for (int i = 0; i < list.size(); i++)

{...}

改成如下这种:

for (int i = 0, length = list.size(); i < length; i++)

{...}

简单的size计算可能对性能影响不大,但是如果循环中的方法计算是类似从数据库count等耗时类的操作,有可能就成为系统的性能瓶颈。

集合数组类的对象初始化指定初始长度。

如果我们能估计大概的内容长度,集合类的实例在创建时最好分配一个初始空间。可以明显的提升性能。这里拿StringBuilder举个例子,如果我们使用默认的构建器,会初始分配16字符空间,如下:

/**

* Constructs a string builder with no characters in it and an

* initial capacity of 16 characters.

*/

public StringBuilder() {

super(16);

}

append操作的时候,如果发现到达了最大容量,它会将自身容量增加到当前的2倍再加2,然后从旧的空间拷贝数据到新的空间。源码如下:

/**

* This implements the expansion semantics of ensureCapacity with no

* size check or synchronization.

*/

void expandCapacity(int minimumCapacity) {

int newCapacity = value.length * 2 + 2;

if (newCapacity - minimumCapacity < 0)

newCapacity = minimumCapacity;

if (newCapacity < 0) {

if (minimumCapacity < 0) // overflow

throw new OutOfMemoryError();

newCapacity = Integer.MAX_VALUE;

}

value = Arrays.copyOf(value, newCapacity);

}

这是一个耗时的动作,而且有时候会浪费空间。试想一下,如果你知道业务场景是大概需要1000个字符。如果没有指定初始值,StringBuilder在append过程中要多次分配空间,拷贝数据。而且在接近1000的时候如果再次分配也是直接翻倍的增加空间,就造成了空间的浪费。

使用并行流

这里说的是stream和parallelStream的区别。

parallelStream并行流就是一个把内容分成多个数据块,并用不不同的线程分别处理每个数据块的流。最后合并每个数据块的计算结果。处理的线程数就是机器的处理器核心数。

从原理上讲,大部分场景下并行流处理是更快,来看个例子:

@Test

public void streamCostTest(){

List intList = mockData();

useStream(intList);

useParallelStream(intList);

}

/**

* 构造数据

*

* @return

*/

public List mockData() {

List intList = new ArrayList();

for (int i = 0; i < 1000000; i++) {

intList.add(i);

}

return intList;

}

public void useStream(List integerList) {

long start = System.currentTimeMillis();

long count = integerList.stream().filter(x -> (x%2==0)).count();

System.out.println(count);

long end = System.currentTimeMillis();

System.out.println("useStream cost:" + (end - start));

}

public void useParallelStream(List integerList) {

long start = System.currentTimeMillis();

long count = integerList.parallelStream().filter(x -> (x%2==0)).count();

System.out.println(count);

long end = System.currentTimeMillis();

System.out.println("useParallelStream cost:" + (end - start));

}

测试结果:

500000

useStream cost:42

500000

useParallelStream cost:13

注意上面我提到了大部分场景下。也就是说并行流并不是大杀器,一劳永逸的解决方案。有些地方使用并行流反而性能更差,这里只给一个建议,就是一定要自己测试,测试性能,测试多线程安全等。

参考:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值