我一直在尝试从Java官方文档中找到清晰的协议,确定调用终止操作后Java流会按照什么顺序处理元素并调用中间操作。
例如,让我们看一下这些示例,它们使用Java流版本和普通迭代版本(都产生相同的结果)。
示例1:
List<Integer> ints = Arrays.asList(1, 2, 3, 4, 5);
Function<Integer, Integer> map1 = i -> i;
Predicate<Integer> f1 = i -> i > 2;
public int findFirstUsingStreams(List<Integer> ints){
return ints.stream().map(map1).filter(f1).findFirst().orElse(-1);
}
public int findFirstUsingLoopV1(List<Integer> ints){
for (int i : ints){
int mappedI = map1.apply(i);
if ( f1.test(mappedI) ) return mappedI;
}
return -1;
}
public int findFirstUsingLoopV2(List<Integer> ints){
List<Integer> mappedInts = new ArrayList<>( ints.size() );
for (int i : ints){
int mappedI = map1.apply(i);
mappedInts.add(mappedI);
}
for (int mappedI : mappedInts){
if ( f1.test(mappedI) ) return mappedI;
}
return -1;
}
< p > Java 中 findFirstUsingStreams
方法中的流是否会按照 findFirstUsingLoopV1
中描述的顺序运行 map1
(map
不会为所有元素运行),还是按照 findFirstUsingLoopV2
中描述的顺序运行(map
会为所有元素运行)?
并且在将来的 Java 版本中,这个顺序会改变吗?或者有官方文档保证 map1
调用的顺序吗?
Example2:
Predicate<Integer> f1 = i -> i > 2;
Predicate<Integer> f2 = i -> i > 3;
public List<Integer> collectUsingStreams(List<Integer> ints){
return ints.stream().filter(f1).filter(f2).collect( Collectors.toList() );
}
public List<Integer> collectUsingLoopV1(List<Integer> ints){
List<Integer> result = new ArrayList<>();
for (int i : ints){
if ( f1.test(i) && f2.test(i) ) result.add(i);
}
return result;
}
public List<Integer> collectUsingLoopV2(List<Integer> ints){
List<Integer> result = new ArrayList<>();
for (int i : ints){
if ( f2.test(i) && f1.test(i) ) result.add(i);
}
return result;
}
在调用collect
方法后,collectUsingStreams
方法中的Java流程是否会按照collectUsingLoopV1
中描述的顺序运行f1
和f2>(
f1
在f2
之前被评估),还是按照collectUsingLoopV2
中描述的顺序(f2
在f1
之前被评估)?
未来版本的Java中,这个顺序会改变吗?或者有官方文档保证f1
和f2
调用的顺序吗?
编辑
感谢所有的答案和评论,但很遗憾我仍然没有看到关于处理元素顺序的好解释。文档确实说列表的遇到顺序将被保留,但它们并没有指定这些元素将如何被处理。例如,在findFirst
的情况下,文档保证map1
将首先看到1,然后是2,但它并没有说map1
不会对4和5执行。这是否意味着我们不能保证我们期望的处理顺序将在未来的Java版本中得到满足?可能是的。