任何傻瓜都能寫出計算機能夠理解的代碼, 但只有優秀的程序眼才能寫出人類能夠理解的代碼 — Martin Fowler
可是總有渴望編寫高性能代碼的程序員存在吧,讓咱們來看看如何編寫運行更快的Java代碼吧!java
注意:JVM對代碼進行了有效的優化。所以,您不須要針對通常用例對其進行優化。可是,若是您想讓JVM發揮最大性能。咱們開始吧。
全部測試用例都在Macbook Pro 2015的Java12 HotSpot(TM) 64-Bit Server VM上運行
若是你的Collections
只初始化一次,則最好集合構造器中對它的值進行初始化,而不是實例化集合後使用addall
或add
方法設置值.程序員
// 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基準測試來驗證一下
結果的單位是每秒操做的次數(op/s),數值越大,性能越高
@State(Scope.Thread) public static class MyState { @Setup(Level.Trial) public void doSetup() { var arr = new Integer[100000]; for (var i = 0; i < 100000; i++) { arr[i] = i; } list = Arrays.asList(arr); } public List list; } // Faster 🚀 > ~148,344 op/s @Benchmark public HashSet usingConstructor() { var set = new HashSet<>(list); return set; } // Slower 🚶♂️ > ~112,061 op/s @Benchmark public HashSet usingAddAll() { var set = new HashSet<>(); set.addAll(list); return set; }
construtor
版本比addall
版本提供~36000 op/s
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版本的兩倍。app
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
函數
SingleList
代替只有單個元素的數組// Faster 🚀 var list = Collections.singletonList("S"); // Slower 🚶♂️ var list = new ArrayList(Arrays.asList("S"));
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
看這裏性能
// 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;
String.isEmpty()
方法來檢查字符串是否爲空由於String
是一個byte[]
,isEmpty
方法只是檢查數組的長度,因此更快測試
public boolean isEmpty() { return value.length == 0; }
// Faster 🚀 var r = 'R' ; var g = 'G' ; var b = 'B' ; // Slower 🚶♂️ var r = "R" ; var g = "G" ; var b = "B" ;
// 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
比+
更快