我有以下示例代码:
System.out.println(
"Result: " +
Stream.of(1, 2, 3)
.filter(i -> {
System.out.println(i);
return true;
})
.findFirst()
.get()
);
System.out.println("-----------");
System.out.println(
"Result: " +
Stream.of(1, 2, 3)
.flatMap(i -> Stream.of(i - 1, i, i + 1))
.flatMap(i -> Stream.of(i - 1, i, i + 1))
.filter(i -> {
System.out.println(i);
return true;
})
.findFirst()
.get()
);
Run Code Online (Sandbox Code Playgroud)
输出如下:
1
Result: 1
-----------
-1
0
1
0
1
2
1
2
3
Result: -1
Run Code Online (Sandbox Code Playgroud)
从这里我看到,在第一种情况下stream真的表现得懒惰 - 我们使用findFirst()所以一旦我们有第一个元素我们的过滤lambda没有被调用.然而,在使用flatMaps的第二种情况下,我们看到尽管找到满足过滤条件的第一个元素(它只是任何第一个元素,因为lambda总是返回true),流的其他内容仍然通过过滤函数被馈送.
我试图理解为什么它表现得像这样,而不是在第一个元素计算后放弃,如第一种情况.任何有用的信息将不胜感激.
我有很多功能:
String first(){}
String second(){}
...
String default(){}
Run Code Online (Sandbox Code Playgroud)
每个都可以返回一个空值,默认值除外.每个功能可以采用不同的参数.例如,第一个可以不带参数,第二个可以接受一个字符串,第三个可以接受三个参数,等等.我想做的是:
ObjectUtils.firstNonNull(first(), second(), ..., default());
Run Code Online (Sandbox Code Playgroud)
问题在于,由于函数调用,这需要进行急切的评估.我想早点退出,在第二个函数之后说(因为函数调用可能很昂贵,想想API调用等).在其他语言中,您可以执行与此类似的操作:
return first() || second() || ... || default()
Run Code Online (Sandbox Code Playgroud)
在Java中,我知道我可以做类似的事情:
String value;
if (value = first()) == null || (value = second()) == null ...
return value;
Run Code Online (Sandbox Code Playgroud)
由于所有的== null检查,这不是非常易读的IMO.ObjectUtils.firstNonNull()首先创建一个集合,然后迭代,只要该函数被懒惰地评估,这是可以的.
建议?(除了做一堆ifs)
是否可以保证在使用流时,中间操作将按程序顺序执行?我怀疑是这种情况,或者它会导致非常微妙的错误,但我找不到明确的答案.
例:
List<String> list = Arrays.asList("a", "b", "c");
List<String> modified = list.parallelStream()
.map(s -> s + "-" + s) //"a-a", "b-b", "c-c"
.filter(s -> !s.equals("b-b")) //"a-a", "c-c"
.map(s -> s.substring(2)) //"a", "c"
.collect(toList());
Run Code Online (Sandbox Code Playgroud)
这保证总是返回["a", "c"]或["c", "a"]?(如果最后一个映射操作在第一个映射操作之前执行,则可能抛出异常 - 类似地,如果在第二个映射操作之后执行过滤器,则"b"将保留在最终列表中)
我在Java中有这个代码片段:
List<Integer> li= Arrays.asList(1, 2, 3, null, 4, 5, null, 6, 7, 8);
li.stream().filter(e-> e!=null)
.map(e-> {System.out.print(" m "+ e); return e * 2;})
.filter(e-> e % 3 == 0)
.forEach(e-> {System.out.println(" fe " + e);});
Run Code Online (Sandbox Code Playgroud)
输出是
m 1 m 2 m 3 fe 6
m 4 m 5 m 6 fe 12
m 7 m 8
Run Code Online (Sandbox Code Playgroud)
我知道filter,map是中间方法,这意味着它们只有在调用像forEach这样的终端方法时才会开始工作.但我不能只围绕它们被调用的确切顺序,并在这种情况下开始工作.有人可以向我解释这个输出是怎么来的吗?