簡體   English   中英

Java 8中的非干擾示例

[英]Example of non-interference in Java 8

根據這個問題 ,我們可以修改源,它不稱為干擾:

您可以修改流元素本身,不應將其稱為“干擾”。

根據這個問題 ,代碼

List<String> list = new ArrayList<>();
  list.add("test");
  list.forEach(x -> list.add(x));

將拋出ConcurrentModificationException

但我的代碼,

Employee[] arrayOfEmps = {
                new Employee(1, "Jeff Bezos"),
                new Employee(2, "Bill Gates"),
                new Employee(3, "hendry cavilg"),
                new Employee(4, "mark cuban"),
                new Employee(5, "zoe"),
                new Employee(6, "billl clinton"),
                new Employee(7, "ariana") ,
                new Employee(8, "cathre"),
                new Employee(9, "hostile"),
                new Employee(10, "verner"),
            };
        Employee el=new Employee(1, "Jeff Bezos");
        List<Employee> li=Arrays.asList(arrayOfEmps);
        li.stream().map(s->{s.setName("newname");return s;}).forEach(System.out::print);

不會拋出ConcurrentModificationException ,即使它實際上更改了源。

而這段代碼,

Employee[] arrayOfEmps = {
                new Employee(1, "Jeff Bezos"),
                new Employee(2, "Bill Gates"),
                new Employee(3, "hendry cavilg"),
                new Employee(4, "mark cuban"),
                new Employee(5, "zoe"),
                new Employee(6, "billl clinton"),
                new Employee(7, "ariana") ,
                new Employee(8, "cathre"),
                new Employee(9, "hostile"),
                new Employee(10, "verner"),
            };
        Employee el=new Employee(1, "Jeff Bezos");
        List<Employee> li=Arrays.asList(arrayOfEmps);
        li.stream().map(s->{s.setName("newname");li.add(s);return s;}).limit(10).forEach(System.out::print);

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractList.add(Unknown Source)
    at java.util.AbstractList.add(Unknown Source)
    at java8.Streams.lambda$0(Streams.java:33)
    at java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
    at java.util.Spliterators$ArraySpliterator.forEachRemaining(Unknown Source)
    at java.util.stream.AbstractPipeline.copyInto(Unknown Source)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
    at java.util.stream.AbstractPipeline.evaluate(Unknown Source)
    at java.util.stream.ReferencePipeline.forEach(Unknown Source)

所以,我並不完全明白哪些類型的修改允許來源,哪些不允許。 看到一個干擾並產生有狀態和副作用產生流的例子將是非常有幫助的,並且適當地指示哪個是哪個。

當你這樣做:

li.stream().map(s->{s.setName("newname");return s;})

你沒有改變列表本身,而是改變了這個列表中的元素 ; 所以它不會像你期望的那樣觸發ConcurrentModificationException

在最后一個代碼段中,您使用的是Array.asList
您必須知道Array.asList在數組(特定的內部ArrayList類)上返回僅僅是只讀的包裝器 ,解釋了為什么不支持add

實際上,這個內部類沒有按設計覆蓋AbstractList #add方法; 導致UnsupportedOperationException ; 仍然沒有像你期望的那樣ConcurrentModificationException

這是一個類似於上一個片段的示例,它會拋出ConcurrentModificationException

public static void main(String[] args) {
    Employee[] arrayOfEmps = {
      new Employee(1, "Jeff Bezos")
    };
    Employee el = new Employee(11, "Bill Gates");
    List<Employee> li = new ArrayList<>(Arrays.asList(arrayOfEmps)); // to avoid read-only restriction
    li.stream().peek(s -> li.add(el)).forEach(System.out::print);
} 

請注意,我正在使用“true” ArrayList包裝Arrays.List ,允許寫入,因為這個實現了add方法;)

您的第一個示例更改了Stream的現有元素,但未添加或刪除源中的元素。 因此,這不是干擾。

您的第二個示例嘗試通過在Stream管道期間向源添加元素來進行干擾。 但是,您將獲得UnsupportedOperationException而不是ConcurrentModificationException ,因為您嘗試將元素添加到固定大小的List (由Arrays.asList返回)。

將您的第二個示例更改為:

List<Employee> li=new ArrayList<>(Arrays.asList(arrayOfEmps));
li.stream().map(s->{s.setName("newname");li.add(s);return s;}).limit(10).forEach(System.out::print);

你應該得到ConcurrentModificationException

這就是所謂的源的非結構變化的結構 Stream 例如, ArrayList doc說:

僅設置元素的值不是結構修改......

因此,在您的示例中,這意味着更改Employee per-se不會更改List本身(不會刪除或添加元素)。 但更改List本身將失敗並出現ConcurrentModificationException

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);

list.stream().forEach(x -> list.remove(x));

但有些來源的干擾不僅僅是OK,稱為弱一致遍歷 ,如ConcurrentHashMap

 ConcurrentHashMap<Integer, String> chm = new ConcurrentHashMap<>();
 chm.put(1, "one");
 chm.put(2, "two");
 chm.put(3, "three");

 chm.entrySet().stream()
         .forEach(x -> chm.remove(x.getKey()));

這不會因ConcurrentModificationException而失敗。

您無法更改正在處理的列表的大小。

在第一個示例中,您將更改列表中Employee對象的值。

在第二個中,您將在列表中添加一個項目。

那是不同的!

您的代碼正在修改流元素,而不是列表本身:

s->{s.setName("newname")更改流的元素中的字段名稱,這不會干擾流或其源。

java.lang.UnsupportedOperationException也是無關的,它是由於您嘗試在固定大小的列表(這是Arrays.asList的結果)上調用add而引起的。 每當在Arrays.asList的結果上調用addremove等時,就會引發不支持的操作異常,因為collect的大小是固定的。

你的第一個例子修改初始列表。

流只是列表中的一個視圖 ,因此初始列表完全不受流代碼的影響。

而第二個示例明確使用了list.add()

這就是全部。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM