我很难找到一种方法,根据谓词在流的开头跳过一些元素。
这样的事情:
dropWhile( n -> n < 3, Stream.of( 0, 1, 2, 3, 0, 1, 2, 3, 4 ) )
.forEach( System.out::println );
3
0
1
2
3
4
这相当于Scala dropWhile
。
答案 0 :(得分:19)
这种操作不是Stream
的预期用例,因为它包含了元素之间的依赖关系。因此,解决方案看起来可能并不优雅,因为您必须为谓词引入一个state-full变量:
class MutableBoolean { boolean b; }
MutableBoolean inTail = new MutableBoolean();
IntStream.of(0, 1, 2, 3, 0, 1, 2, 3, 4)
.filter(i -> inTail.b || i >= 3 && (inTail.b = true))
.forEach(System.out::println);
请注意,与您的示例相比,条件必须颠倒。
当然,您可以在方法中隐藏讨厌的细节:
public static void main(String... arg) {
dropWhile(n -> n < 3, Stream.of(0, 1, 2, 3, 0, 1, 2, 3, 4))
.forEach(System.out::println);
}
static <T> Stream<T> dropWhile(Predicate<T> p, Stream<T> s) {
class MutableBoolean { boolean b; }
MutableBoolean inTail = new MutableBoolean();
return s.filter(i -> inTail.b || !p.test(i) && (inTail.b = true));
}
更复杂,但更清洁,可能更有效的方法是采用金属,即Spliterator
界面:
static <T> Stream<T> dropWhile(Predicate<T> p, Stream<T> s) {
Spliterator<T> sp = s.spliterator();
return StreamSupport.stream(new Spliterators.AbstractSpliterator<T>(
sp.estimateSize(), sp.characteristics() & ~Spliterator.SIZED) {
boolean dropped;
public boolean tryAdvance(Consumer<? super T> action) {
if(dropped) return sp.tryAdvance(action);
do {} while(!dropped && sp.tryAdvance(t -> {
if(!p.test(t)) {
dropped=true;
action.accept(t);
}
}));
return dropped;
}
public void forEachRemaining(Consumer<? super T> action) {
while(!dropped) if(!tryAdvance(action)) return;
sp.forEachRemaining(action);
}
}, s.isParallel());
}
此方法的使用方法与第一个dropWhile
方法的使用方法相同,但即使使用并行流也可以使用,但效率不如您想要的那么高。
答案 1 :(得分:10)
不幸的是,使用Java 8的唯一方法是使用Holger提供的解决方案。
然而,操作dropWhile(predicate)
已经added to Java 9所以从JDK 9开始,你可以简单地:{/ p>
Stream.of(0, 1, 2, 3, 0, 1, 2, 3, 4).dropWhile(n -> n < 3).forEach(System.out::println);