【问题标题】:Possible Java1.8 stream anomaly可能的 Java1.8 流异常
【发布时间】:2014-11-20 17:25:59
【问题描述】:

有人可以解释以下代码的行为吗?特别是为什么流中的forEach会改变原来的List?:

import java.util.ArrayList;
import java.util.List;

public class foreachIssue {
        class justanInt {   
        public int anint; 
        public justanInt(int t){
            anint=t;
        }
    }

    public static void main(String[] args){
        new foreachIssue();
    }
    public foreachIssue(){
        System.out.println("The Stream Output:"); 
        List<justanInt> lst = new ArrayList<>();
        justanInt j1=new justanInt(2);
        justanInt j2=new justanInt(5);
        lst.add(j1);lst.add(j2);
        lst.stream()
                .map((s)->{
                    s.anint=s.anint*s.anint;
                    return s;
                })
                .forEach((s)->System.out.println("Anything"));
        System.out.println(" lst after the stream:"); 
        for(justanInt il:lst)
            System.out.println(il.anint); 

        List<justanInt> lst1 = new ArrayList<>();
        justanInt j3=new justanInt(2);
        justanInt j4=new justanInt(5);
        lst1.add(j3);lst1.add(j4);
        lst1.stream()
                    .map((s)->{
                    s.anint=s.anint*s.anint;
                    return s;
                });
        System.out.println(" lst1 after the stream without forEach:"); 
        for(justanInt il:lst1)
            System.out.println(il.anint); 
    }
}

输出是:

流输出:

任何东西

任何东西

在流之后:

4

25

lst1 在没有 forEach 的流之后:

2

5

【问题讨论】:

  • 参考JavaDoc,很明显map是一个中间操作。
  • 谢谢,这很有帮助。是否有原因导致我没有收到错误甚至警告(在 NetBeans 中)我没有终止流?
  • 没有理由收到警告!每个中间操作都返回一个 Stream 对象,只要您不在该流上调用终端操作,您就可以使用该流。就像写一行代码一样 "SubStringReturnAStringNotManipulateTheString".substring(0,1);我并不是说这些错误不能被检测到,但目前只有 intellijIDE 可以发现其中一些错误。

标签: java java-8 java-stream


【解决方案1】:

map 是一个intermediate operation

流操作分为中间(流生产) 操作和终端(产生价值或副作用)操作。 中间操作总是懒惰的。

因此,您提供给mapFunction 在您使用Stream 之前不会被应用。在第一种情况下,您使用forEach 执行此操作,这是一个终端操作。第二个,你没有。

【讨论】:

  • 副作用Functions 往往是危险且不可取的,尽管您可以使用peek 而不是map 更准确地表达您尝试编写的操作。
  • 如果它无论如何都应该是终端操作,.forEach(s -&gt; s.anint=s.anint*s.anint) 将是正确的解决方案(而且它更简单......)你甚至可以进一步简化它:.forEach(s -&gt; s.anint*=s.anint)
猜你喜欢
  • 2012-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多