Java 考虑创建过滤流后添加的列表元素

Java 考虑创建过滤流后添加的列表元素,java,java-8,java-stream,Java,Java 8,Java Stream,给定以下代码: List<String> strList = new ArrayList<>(Arrays.asList("Java","Python","Php")); Stream<String> jFilter = strList.stream().filter(str -> str.startsWith("J")); strList.add("JavaScript"); // element added after filter creati

给定以下代码:

List<String> strList = new ArrayList<>(Arrays.asList("Java","Python","Php"));

Stream<String> jFilter = strList.stream().filter(str -> str.startsWith("J"));

strList.add("JavaScript"); // element added after filter creation
strList.add("JQuery"); // element added after filter creation

System.out.println(Arrays.toString(jFilter.toArray())); 
为什么
JavaScript
JQuery
即使是在创建过滤流之后添加的,也会出现在过滤结果中?

简短回答 在这一点之后,您将假设:

Stream<String> jFilter = strStream.filter(str -> str.startsWith("J"));
首先创建一个由两个字符串组成的列表:“一”;和“两个”。然后创建一个流 从那个名单上。接下来,通过添加第三个字符串修改列表: “三”。最后收集并连接流的元素 在一起因为列表在终端收集之前已修改 操作开始后,结果将是一串“一二三”。 所有从JDK集合返回的流,以及大多数其他JDK 类,在这种方式下表现良好

直到声明

System.out.println(Arrays.toString(jFilter.toArray()));
流运行时,流不会做任何事情。需要一个终端操作(
toArray
,在本例中)来遍历流并执行中间操作(
filter

在这种情况下,您可以做的是,例如,在添加其他元素之前捕获列表的大小:

int maxSize = strList.size();
Stream<String> jFilter = strStream.limit(maxSize)
                                  .filter(str -> str.startsWith("J"));
intmaxsize=strList.size();
Stream jFilter=strStream.limit(maxSize)
.filter(str->str.startsWith(“J”));

其中,
limit(maxSize)
将不允许超过初始元素通过管道。

如官方文档中所述,流没有存储,因此更像迭代器而不是集合,并且被延迟评估


因此,在调用terminal操作toArray()之前,流实际上不会发生任何事情,因为流从未得到计算。您从未在该流上调用“终端操作”,因为它们是懒惰的

查看对代码和输出的修改。当您呼叫终端操作员时,实际上会进行过滤

 public static void main(String []args){
         List<String> strList = new ArrayList<>();
    strList.add("Java");
    strList.add("Python");
    strList.add("Php");

    Stream<String> strStream = strList.stream();

    Stream<String> jFilter = strStream.filter(str -> {
        System.out.println("Filtering" + str);
        return str.startsWith("J");
        });

 System.out.println("After Stream creation");
    strList.add("JavaScript"); // element added after filter creation
    strList.add("JQuery"); // element added after filter creation

    System.out.println(Arrays.toString(jFilter.toArray()));

     }

@哈迪J的评论,但它应该是根据规则的答案

因为
是惰性的,当您调用终端操作时,它会被执行


toArray
方法是终端操作,它可以处理列表的全部内容。要获得可预测的结果,请不要将
保存到临时变量中,因为这将导致误导性结果。更好的代码是:

String[] arr = strList.stream().filter(str -> str.startsWith("J")).toArray();
 public static void main(String []args){
         List<String> strList = new ArrayList<>();
    strList.add("Java");
    strList.add("Python");
    strList.add("Php");

    Stream<String> strStream = strList.stream();

    Stream<String> jFilter = strStream.filter(str -> {
        System.out.println("Filtering" + str);
        return str.startsWith("J");
        });

 System.out.println("After Stream creation");
    strList.add("JavaScript"); // element added after filter creation
    strList.add("JQuery"); // element added after filter creation

    System.out.println(Arrays.toString(jFilter.toArray()));

     }
After Stream creation
FilteringJava
FilteringPython
FilteringPhp
FilteringJavaScript
FilteringJQuery
[Java, JavaScript, JQuery]
String[] arr = strList.stream().filter(str -> str.startsWith("J")).toArray();