给出以下代码:
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()));
输出:
[Java, JavaScript, JQuery]
即使JavaScript
和JQuery
在创建过滤后的流之后添加,为什么仍会出现在过滤结果中?
答案 0 :(得分:13)
您假设在这一点之后:
Stream<String> jFilter = strStream.filter(str -> str.startsWith("J"));
返回以“ J”开头的新元素流,即仅返回Java
。但是,不是情况;
流是惰性的,即它们不执行任何逻辑,除非终端操作另行通知。
流管道的实际执行从toArray()
调用开始,由于列表在终端toArray()
操作开始之前被修改,因此结果为[Java, JavaScript, JQuery]
。
这是documentation的一部分,其中提到了这一点:
对于行为良好的流源,可以先修改源 终端操作开始,这些修改将是 反映在覆盖的元素中。例如,考虑以下 代码:
List<String> l = new ArrayList(Arrays.asList("one", "two")); Stream<String> sl = l.stream(); l.add("three"); String s = sl.collect(joining(" "));
首先创建一个列表,该列表由两个字符串组成:“一个”;和“两个”。然后创建一个流 从该列表中。接下来,通过添加第三个字符串来修改列表: “三”。最后,流的元素被收集并加入 一起。由于列表是在终端收集之前被修改的 操作开始后,结果将为字符串“一二三”。 从JDK集合以及大多数其他JDK返回的所有流 类,以这种方式表现良好;
答案 1 :(得分:8)
直到语句
System.out.println(Arrays.toString(jFilter.toArray()));
运行,流不执行任何操作。要遍历流并执行中间操作(在这种情况下为toArray
,则需要执行终端操作(在示例中为filter
)。
在这种情况下,您可以做的是,例如,在添加其他元素之前捕获列表的大小:
int maxSize = strList.size();
Stream<String> jFilter = strStream.limit(maxSize)
.filter(str -> str.startsWith("J"));
其中limit(maxSize)
不允许超过初始元素的流水线。
答案 2 :(得分:3)
这是因为流从未得到评估。您从来没有在该流上调用“ 终端操作”,因为它们懒惰会被执行。
查看对代码和输出的修改。过滤实际上是在您呼叫终端操作员时进行的。
Lines <- "
date firms return
5/1/1988 A 5
6/1/1988 A 6
7/1/1988 A 4
8/1/1988 A 5
9/1/1988 A 6
11/1/1988 A 6
12/1/1988 A 13
13/01/1988 A 3
14/01/1988 A 2
15/01/1988 A 5
16/01/1988 A 2
18/01/1988 A 7
19/01/1988 A 3
20/01/1988 A 5
21/01/1988 A 7
22/01/1988 A 5
23/01/1988 A 9
25/01/1988 A 1
26/01/1988 A 5
27/01/1988 A 2
28/01/1988 A 7
29/01/1988 A 2
5/1/1988 B 5
6/1/1988 B 7
7/1/1988 B 5
8/1/1988 B 9
9/1/1988 B 1
11/1/1988 B 5
12/1/1988 B 2
13/01/1988 B 7
14/01/1988 B 2
15/01/1988 B 5
16/01/1988 B 6
18/01/1988 B 8
19/01/1988 B 5
20/01/1988 B 4
21/01/1988 B 3
22/01/1988 B 18
23/01/1988 B 5
25/01/1988 B 2
26/01/1988 B 7
27/01/1988 B 3
28/01/1988 B 9
29/01/1988 B 2
"
DF <- read.table(text = Lines, header = TRUE)
输出:
// Set up the models
var User = sequelize.define('User', {});
var Login = sequelize.define('Login', {});
...
User.create({
name: "name",
Login:
{
users: {..i.e several users if a user belongs to another user..}
}
},{
include:{
model: Login,
include: User //nested model.Create
}
})
答案 3 :(得分:1)
如官方文档,https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html所述,流没有存储空间,因此更像迭代器而不是集合,并且被懒惰地评估。
因此,在调用终端操作toArray()之前,流实际上不会发生任何事情
答案 4 :(得分:1)
@Hadi J的评论,但应该按照规则回答。
因为
streams
很懒,当您调用终端操作时,它会执行。
答案 5 :(得分:0)
toArray
方法是终端操作,适用于列表的全部内容。为了获得可预测的结果,请不要将stream
保存到临时变量中,因为这会导致误导结果。更好的代码是:
String[] arr = strList.stream().filter(str -> str.startsWith("J")).toArray();