提高Java性能的9个技巧☕️??️
任何傻瓜都可以编写计算机可以理解的代码。优秀的程序员编写人类可以理解的代码。 – 马丁福勒
但是编写高性能代码的痒总是存在于任何开发人员身上。让我们看看如何使Java代码运行得更快。
注意:JVM可以有效地优化代码。因此,您无需针对一般用例对其进行优化。但是如果你想从JVM中消耗掉最大的性能。开始了。
所有测试均在MacBook Pro 2017笔记本电脑的OpenJDK 12.0.1中进行。
1.在构造函数中实例化
如果您的集合仅初始化一次,则最好初始化集合中的值 constructor
本身而不是实例化集合和使用设置值 addAll
。
// Slower ?♂️ Set<String> set = new HashSet<>(); set.addAll(Arrays.asList("one", "two", "three")); // Faster ? Set<String> set = new HashSet<>(Arrays.asList("one", "two", "three"));
让我们使用JMH基准来验证这一点。
结果单位是
operations/second
(op/s
)。性能越高越好。
// Faster ? > ~18000 op/s @Benchmark public HashSet usingConstructor() { var arr = new int(100000); for (var i = 0; i < 100000; i++) { arr(i) = i; } List list = Arrays.asList(arr); var set = new HashSet<>(list); return set; } // Slower ?♂️ > ~17100 op/s @Benchmark public HashSet usingAddAll() { var arr = new int(100000); for (var i = 0; i < 100000; i++) { arr(i) = i; } List list = Arrays.asList(arr); var set = new HashSet<>(); set.addAll(list); return set; }
该
construtor
版本提供~1000 op / s以上addAll
版。
2. AddAll比Add快
同样的, addAll
与之相比,每秒提供更高的操作 add
。因此,下次当您向数组添加内容时,请确保将它们堆叠并使用它进行添加 addAll
。
// Slower ?♂️ ~116116op/s @Benchmark public ArrayList<Integer> usingAdd() { var a = new int(1000); for (var i = 0; i < 1000; i++) { a(i) = i; } var arr = new ArrayList<Integer>(); for (var i = 0; i < 1000; i++) { arr.add(a(i)); } return arr; } // Faster ? ~299130 op/s @Benchmark public ArrayList<Integer> usingAddAll() { var a = new Integer(1000); for (var i = 0; i < 1000; i++) { a(i) = i; } var arr = new ArrayList<Integer>(); arr.addAll(Arrays.asList(a)); return arr; }
该 addAll
几乎快了两倍 add
版。
3.使用 EntrySet
用于地图 KeySet
你在地图上迭代了多少?然后用 entrySet
过了 keySet
。
// Slower ?♂️ ~37000 op/s @Benchmark public HashMap<Integer, Integer> keySetIteration(Blackhole blackhole) { var someMap = new HashMap<Integer, Integer>(); for (var i = 0; i < 1000; i++) { someMap.put(i, i); } var sum = 0; for(Integer i: someMap.keySet()) { sum += i; sum += someMap.get(i); } blackhole.consume(sum); return someMap; } // Faster ? ~45000 op/s @Benchmark public HashMap<Integer, Integer> entrySetIteration(Blackhole blackhole) { var someMap = new HashMap<Integer, Integer>(); for (var i = 0; i < 1000; i++) { someMap.put(i, i); } var sum = 0; for(Map.Entry<Integer, Integer> e: someMap.entrySet()) { sum += e.getKey(); sum += e.getValue(); } blackhole.consume(sum); return someMap; }
该 entrySet
能跑 9000
操作比它更多 keySet
变体在一秒钟内。
4.使用 SingletonList
而不是 array
单个元素。
// Faster ? var list = Collections.singletonList("S"); // Slower ?♂️ var list = new ArrayList(Arrays.asList("S"));
5.使用 EnumSet
代替 HashSet
。 EnumSet
要快得多。
// Faster ? public enum Color { RED, YELLOW, GREEN } var colors = EnumSet.allOf(Color.class); // Slower ?♂️ var colors = new HashSet<>(Arrays.asList(Color.values()));
更多关于EnumSet的信息。
6.不要随意初始化对象。尝试最大限度地重复使用。
// Faster ? var i = 0 ; i += addSomeNumber(); i -= minusSomeNumber(); return i; // Slower ?♂️ var i = 0 ; var j = addSomeNumber(); var k = minusSomeNumber(); var l = i + j - k; return l;
7.使用 String.isEmpty()
方法检查是否 String
是空的。
字符串是一个 byte()
和 isEmpty
只检查一个长度 Array
。所以它要快得多。
public boolean isEmpty() { return value.length == 0; }
8.如果您使用带有单个字符的String,请将其替换为 Character
// Faster ? var r = 'R' ; var g = 'G' ; var b = 'B' ; // Slower ?♂️ var r = "R" ; var g = "G" ; var b = "B" ;
9.尽可能使用StringBuilder。
// Faster ? StringBuilder str = new StringBuilder(); str.append("A"); str.append("B"); str.append("C"); str.append("D"); str.append("E"); .... // Slower ?♂️ var str = ""; str += "A"; str += "B"; str += "C"; str += "D"; str += "E"; ....
但是,当你必须做一个单一的连接。而不是使用StringBuilder,它使用起来更快
+
。
如果您有一个有趣的性能提示/出了问题,请在评论中留下。
你可以在Twitter上关注我。
如果您喜欢这篇文章,请留下相似或评测。 ❤️