3 回答

TA貢獻1871條經(jīng)驗 獲得超13個贊
對于諸如所示的簡單情況,它們基本上是相同的。但是,有許多細微的差別可能很重要。
一個問題是訂購。使用Stream.forEach,順序不確定。順序流不太可能發(fā)生,但是,它在規(guī)范中可以Stream.forEach以任意順序執(zhí)行。這確實在并行流中經(jīng)常發(fā)生。相反,如果指定Iterable.forEach了Iterable,則總是按的迭代順序執(zhí)行。
另一個問題是副作用。Stream.forEach必須指定中的動作為非干擾動作。(請參閱java.util.stream軟件包doc。)Iterable.forEach可能具有較少的限制。對于集合java.util,Iterable.forEach通常會使用該集合的Iterator,其中大部分被設(shè)計成快速失敗的,并且將拋出ConcurrentModificationException,如果集合在迭代過程中結(jié)構(gòu)修飾。但是,在迭代過程中允許進行非結(jié)構(gòu)化的修改。例如,ArrayList類文檔說“僅設(shè)置元素的值不是結(jié)構(gòu)修改”。因此,針對ArrayList.forEach允許在底層中設(shè)置值A(chǔ)rrayList而不會出現(xiàn)問題。
并發(fā)集合又一次不同。它們不是快速失敗,而是設(shè)計為弱一致性。完整定義在該鏈接上。不過,請簡要考慮一下ConcurrentLinkedDeque。傳遞給它的操作forEach方法是允許修改底層雙端隊列,即使結(jié)構(gòu)上,并且ConcurrentModificationException永遠不會拋出。但是,發(fā)生的修改在此迭代中可能可見,也可能不可見。(因此保持“弱”一致性。)
如果Iterable.forEach在同步的集合上進行迭代,則仍然可以看到另一個差異。在這樣的集合上,Iterable.forEach 獲取一次該集合的鎖,并在對action方法的所有調(diào)用中保持該鎖。該Stream.forEach調(diào)用使用集合的分隔符,該分隔符不鎖定,并且依賴于不干擾的流行規(guī)則。支持該流的集合可以在迭代期間進行修改,如果是,則ConcurrentModificationException可能導(dǎo)致行為不一致或行為不一致。

TA貢獻1868條經(jīng)驗 獲得超4個贊
該答案本身與循環(huán)的各種實現(xiàn)的性能有關(guān)。它與被稱為“非常頻繁”的循環(huán)(如數(shù)百萬次調(diào)用)的邊際相關(guān)。在大多數(shù)情況下,循環(huán)的內(nèi)容將是迄今為止最昂貴的元素。對于確實經(jīng)常循環(huán)的情況,這可能仍然很有趣。
您應(yīng)該在目標系統(tǒng)下重復(fù)此測試,因為這是特定于實現(xiàn)的(完整的源代碼)。
我在快速的Linux機器上運行openjdk版本1.8.0_111。
我編寫了一個測試,使用此代碼在列表上循環(huán)10 ^ 6次,該代碼的大小各不相同integers(10 ^ 0-> 10 ^ 5個條目)。
結(jié)果如下,最快的方法取決于列表中條目的數(shù)量。
但是,即使在最糟糕的情況下,表現(xiàn)最差的人也要花10秒循環(huán)10 ^ 5個條目10 ^ 6次,因此實際上在所有情況下其他考慮因素都更為重要。
public int outside = 0;
private void forCounter(List<Integer> integers) {
for(int ii = 0; ii < integers.size(); ii++) {
Integer next = integers.get(ii);
outside = next*next;
}
}
private void forEach(List<Integer> integers) {
for(Integer next : integers) {
outside = next * next;
}
}
private void iteratorForEach(List<Integer> integers) {
integers.forEach((ii) -> {
outside = ii*ii;
});
}
private void iteratorStream(List<Integer> integers) {
integers.stream().forEach((ii) -> {
outside = ii*ii;
});
}
這是我的時間安排:毫秒/功能/列表中的條目數(shù)。每次運行為10 ^ 6循環(huán)。
1 10 100 1000 10000
for with index 39 112 920 8577 89212
iterator.forEach 27 116 959 8832 88958
for:each 53 171 1262 11164 111005
iterable.stream.forEach 255 324 1030 8519 88419
如果您重復(fù)實驗,我將發(fā)布完整的源代碼。請編輯此答案,并在結(jié)果中加上已測試系統(tǒng)的注釋。
使用MacBook Pro,2.5 GHz Intel Core i7、16 GB,macOS 10.12.6:
1 10 100 1000 10000
for with index 49 145 887 7614 81130
iterator.forEach 27 106 1047 8516 88044
for:each 46 143 1182 10548 101925
iterable.stream.forEach 393 397 1108 8908 88361

TA貢獻1798條經(jīng)驗 獲得超7個贊
您提到的兩者之間沒有任何區(qū)別,至少從概念上講,這Collection.forEach()只是一個簡寫。
在內(nèi)部,stream()由于創(chuàng)建對象,該版本的開銷會更大一些,但是從運行時間來看,該版本都沒有開銷。
兩種實現(xiàn)都最終對collection內(nèi)容進行一次迭代,并在迭代過程中打印出元素。
添加回答
舉報