我一直试图从官方 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;
}
Java流会进来吗findFirstUsingStreams
之后的方法findFirst
被称为运行map1
按照中描述的顺序findFirstUsingLoopV1
(map
不适用于所有元素)或如中所述findFirstUsingLoopV2
(map
为所有元素运行)?
这个顺序在 Java 的未来版本中会改变吗?或者有一个官方文档可以保证我们的顺序map1
calls?
示例2:
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;
}
Java 流将再次传入collectUsingStreams
之后的方法collect
被称为运行f1
and f2
按照中描述的顺序collectUsingLoopV1
(f1
之前评估过f2
)或如中所述collectUsingLoopV2
(f2
之前评估过f1
)?
这个顺序在 Java 的未来版本中会改变吗?或者有一个官方文档可以保证我们的顺序f1
and f2
calls?
Edit
感谢您的所有答案和评论,但不幸的是,我仍然没有看到有关处理元素的顺序的良好解释。文档确实说将为列表保留遇到顺序,但他们没有指定如何处理这些元素。例如,如果findFirst
该文档保证map1
首先会看到 1 然后是 2 但它并没有说map1
4 和 5 不会被执行。这是否意味着我们不能保证我们的处理顺序将与我们期望的 Java 未来版本一样?可能是。