2017-07-13 62 views
2

我已經經歷了像How to ensure order of processing in java8 streams?這樣的相關問題,輸出元素的排序還不完全清楚。因此請澄清我的下列疑問。在java流中遇到命令保存

Integer[] intArray = {1, 2, 3, 4, 5, 6, 7, 8 }; 
      List<Integer> listOfIntegers = 
       new ArrayList<>(Arrays.asList(intArray)); 
     listOfIntegers 
      .parallelStream() 
      .unordered() 
      .forEachOrdered(e -> System.out.print(e + " ")); 

我認爲至少在理論上(或根據Java規範),它可以以隨機順序打印大於1,2,3,4,5,6,7,8,對嗎?

還有一個相關的問題 - 遇到訂單保存的決定是在什麼時候執行? 更確切地說,即使在開始執行之前,通過貫穿源代碼,中間操作和終端操作的特性來完成對整個流管線ORDER特性的評估?

回答

4

來源的無序性或通過unordered()顯式釋放訂單合約可能會影響後續的所有管道階段,除非它們引入的訂單隻能在sorted操作中發生。

對於像filtermap無國籍中間業務,是沒有區別的,無論如何,但像skiplimitdistinct操作可能會根據先前的流狀態是否有序或無序表現出不同的行爲。 This answer顯示distinct如何受之前的unordered()影響。

請注意,原則上,sorted在引入順序時可能取決於前一階段的有序狀態,因爲如果前一個流是無序的,它可能會使用不穩定的排序算法。

This answer提供了一種方法來打印流的特徵並評估它們因附加其他操作而發生的變化。

當您鏈接終端操作時,終端操作本身的無序性質或終端操作之前的最後一個階段的無序狀態可能足以爲不嘗試終端操作的終端操作選擇算法保持秩序。

原則上,終端操作的無序性質可以用來影響之前的階段,但因爲無狀態的中間業務是無論如何也受到影響,skiplimitdistinct必須遵守先前的有序狀態,如果存在的話,唯一的可能會受到影響的操作是sorted,如果後續操作無論如何不關心訂單,該操作就會過時。

在當前實現中,自Java 8更新60以來,終端操作的無序性不會影響以前階段的行爲。與之前的實施方式一樣,進行了此更改,它錯誤地影響了skiplimit。放棄過時的分揀步驟的機會並不被認爲是一個問題,因爲鏈接sort與無序的後續操作,是一個角落的情況。如果您想了解更多關於相關討論的信息,請參閱this answer,包括評論。

所以對於

list.stream() // List.stream() returns an ordered stream 
    .unordered() // releases order contract 
    .distinct() // for equal elements, it may pick an arbitrary one 
    .sorted() // re-introduces an order 
    .skip(1) // will skip the minimum element due to the order 
    .forEach(System.out::println); // may print the remaining elements in arbitrary order 

沒有一個單一的有序或無序行爲流管道。

相比之下,

hashSet.stream() // HashSet.stream() has no order (unless being a LinkedHashSet) 
    .filter(Objects::nonNull) // not affected by order 
    .distinct() // may use unorderedness, but has no effect anyway, as already distinct 
    .skip(1) // may skip an arbitrary element 
    .forEachOrdered(System.out::println); // would respect order if there was one 

整個管道運行無序的,只是因爲源是無序的。有了一個有序的來源,它將完全有序。

因此,對「」的回答是評估整個流水線ORDER特徵,即使在執行開始之前通過源,中間操作和終端操作的特徵來完成?「是的,是的,這是在開始實際處理之前完成的,通過爲流水線階段選擇適當的算法,當有選擇時,但是該處理不一定導致整個流水線的單個特性。

+2

很好的答案,比它深得多:) –

+0

@Holger非常thnx人 – nantitv

2

只要您選擇unordered那麼最終結果可以基本上隨機順序通過。請注意,雖然沒有要求,但實際上您可能仍會在輸出中看到一些排序。

forEachOrdered保留'流'的遭遇順序,所以如果你沒有.unordered()那麼它會確保你看到遇到順序的元素。如果流已經是unordered雖然那麼它是毫無意義的,你也可以使用forEach

換句話說forEachOrdered保留已經排序的流中的遭遇順序。它不會做任何排序或其他順序,但如果流已經是unordered那麼任何事情都可能發生。

+2

'forEachOrdered'還保證消費者不會被同時調用,所以你可以說它會引入* some * order,而消費者通過'forEach'可能會被多個線程一次調用,所以它確實是無序的,儘管'System.out.print'的內部同步也會在這種情況下執行一些*命令... – Holger

+0

@Holger請問您能否澄清一下相關問題:在什麼時候採取保護命令的決定? – nantitv