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();