不要玷污你的生产newList
具有完全无关的任务的任务。只需使用
boolean flag = list.stream().anyMatch(i -> condition(i));
后跟其他流代码。
有两种典型的反对
但这两次迭代。
是的,但是谁说,迭代两次ArrayList
是个问题?不要试图避免多个流操作,除非你知道你真的有一个昂贵的遍历流源,比如外部文件。如果您拥有如此昂贵的源代码,则首先将元素收集到集合中可能会更容易,您可以将它们遍历两次。
但它多次评估condition(…)
。
嗯,其实它是评估它低于你的原始代码
.filter(i -> {
if(condition(i)){
flag = true;
}
return condition(i);
})
如在第一场比赛anyMatch
停止,而你原来的谓词每个元素的计算结果condition(i)
两次,无条件地。
如果具备条件前述若干中间步骤,就可以收集到中间像List
List<Integer> intermediate = list.stream()
//many other filters, flatmaps, etc...
.filter(i -> condition(i))
.collect(Collectors.toList());
boolean flag = !intermediate.isEmpty();
List<Integer> newList = intermediate.stream()
//many other filters, flatmaps, etc...
.collect(Collectors.toList());
但比常多,中间步骤不处于它作为昂贵可能看起来乍一看。取决于实际的码头操作,类似的中间步骤的性能特征可能在不同的码流操作中变化。因此,它可能仍然工作充分做对即时下列步骤操作:
boolean flag = list.stream()
//many other filters, flatmaps, etc...
.anyMatch(i -> condition(i));
List<Integer> newList = list.stream()
//many other filters, flatmaps, etc...
.filter(i -> condition(i))
//many other filters, flatmaps, etc...
.collect(Collectors.toList());
如果你担心重复代码本身,你仍然可以把普通代码返回实用方法的流。
只有在非常罕见的情况下,它才有可能进入低级API,并像this answer一样窥视Stream。如果你这样做,你不应该去的Iterator
将失去对内容的元信息的途径,但使用一个Spliterator
:
Spliterator<Integer> sp = list.stream()
//many other filters, flatmaps, etc...
.filter(i -> condition(i))
.spliterator();
Stream.Builder<Integer> first = Stream.builder();
boolean flag = sp.tryAdvance(first);
List<Integer> newList = Stream.concat(first.build(), StreamSupport.stream(sp, false))
//many other filters, flatmaps, etc...
.collect(Collectors.toList());
注意,在所有这些情况下,您可以快捷如果flag
是false
,作为结果只能是一个空列表,则:
List<Integer> newList = !flag? Collections.emptyList():
/*
subsequent stream operation
*/;
这不是建议,它是一种语言限制。 – shmosel
*也可以将'flag'包装在'AtomicReference''或'AtomicBoolean'中? – shmosel
你的第一个解决方案看起来非常好:检查isEmpty看起来是正确的方法。 –