Lambda 表達式是 Java 8 的新語法,能夠極大地簡化代碼,加強語言的表達力。這裏不贅述 Lambda 表達式的語法,主要從一道題目出發來講 Lambda 表達式的一個特性。java
從前陣子開始,堅持天天在 LeetCode 作一道題。這是前話。今天在作這道題的時候,碰到一個問題,記錄下來備忘。框架
題目自己很好理解:給幾個區間,將其中重疊相交的合併,返回合併後的區間。優化
作法也不難:將區間按照"起點小的在前,起點同樣的則終點小的在前"排序。spa
選定第一個區間 A,按序依次遍歷剩下的區間 B,若是 B 的起點比 A 的終點小,則 A 和 B 能夠合併。code
不斷重複這個選定第一個區間的操做,直至將全部可合併的區間進行合併。排序
最後返回剩下的區間便可。leetcode
按理說不難,作完以後,也能經過了。代碼以下:資源
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, (o1, o2) -> {
if (o1[0] != o2[0]) {
return Integer.compare(o1[0], o2[0]);
}
return Integer.compare(o1[1], o2[1]);
});
boolean[] vis = new boolean[intervals.length];
Arrays.fill(vis, true);
for (int i = 0; i < intervals.length; i++) {
if (!vis[i]) {
continue;
}
for (int j = i + 1; j < intervals.length; j++) {
if (intervals[j][0] <= intervals[i][1]) {
vis[j] = false;
if (intervals[i][1] < intervals[j][1]) {
intervals[i][1] = intervals[j][1];
}
}
}
}
int count = 0;
for (boolean v : vis) {
if (v) {
count++;
}
}
int[][] ans = new int[count][];
for (int i = 0, j = 0; i < intervals.length; i++) {
if (!vis[i]) {
continue;
}
ans[j++] = intervals[i];
}
return ans;
}
複製代碼
不太理解的是 LeetCode 上的執行時間是 84 ms,已經打敗 28.32 % 的 java 提交記錄
。我冥思苦想,這已是 O(N) 複雜度的解法(固然還有常數級別的優化空間),難道還能有更高效的作法?get
因而我看了一下別人的解法,大致上是同樣的,複雜的也是 O(N)。由於一些細節上的處理,會有常數級別的差距,但應該不至於有這麼大的差距纔對。io
一開始懷疑是數據量很大,在遍歷的過程須要訪問當前數據和以前的數據,多是在這時發生了取數據的耗時操做。因而嘗試把須要比較的數據用臨時變量存儲下來。結果發現耗時並無什麼變化。
最後實在想不出來,因而照着別人的代碼,一點點改,邊改邊看執行時間。
最後發現是排序這裏的 lambda 表達式形成了效率的差距。
Google 搜索後看到了 Stack Overflow 上的這個提問 Java lambdas 20 times slower than anonymous classes。
能夠看到 Lambda 表達式的一些特性:
因此,程序使用 Lambda 表達式後慢的緣由也就呼之而出了:LeetCode 執行提交的代碼以前,沒有使用到 Lambda 表達式。當執行咱們的代碼時,要先加載處理 Lambda 表達式的框架。加載框架的時間會算到程序的運行時間裏。
雖然原理已經知道,但也要用代碼從實際來驗證一遍。