5 回答
TA贡献1815条经验 获得超6个赞
如果你的出发点是 aStream并且你想保留它的所有属性和惰性,那么下面的解决方案就可以了:
public static <E> Stream<E> forFirst(Stream<E> stream, Consumer<? super E> c) {
boolean parallel = stream.isParallel();
Spliterator<E> sp = stream.spliterator();
return StreamSupport.stream(() -> {
if(sp.getExactSizeIfKnown() == 0) return sp;
Stream.Builder<E> b = Stream.builder();
if(!sp.tryAdvance(b.andThen(c))) return sp;
return Stream.concat(b.build(), StreamSupport.stream(sp, parallel)).spliterator();
}, sp.characteristics(), parallel);
}
例如,当你使用它时
List<String> list = new ArrayList<>(List.of("foo", "bar", "baz"));
Stream<String> stream = forFirst(
list.stream().filter(s -> s.startsWith("b")),
s -> System.out.println(s+" ("+s.getClass().getSimpleName()+')')
).map(String::toUpperCase);
list.add(1, "blah");
System.out.println(stream.collect(Collectors.joining(" | ")));
它会打印
blah (String)
BLAH | BAR | BAZ
证明在开始终端操作 () 之前处理不会开始collect,因此反映了对源的先前更新List。
TA贡献1860条经验 获得超8个赞
您可以滥用减少:
Stream<E> stream = ...;System.out.println(stream .reduce("",(out,e) -> out + (out.isEmpty() ? e.getClass().getSimpleName()+"\n" : "") + e));
TA贡献1853条经验 获得超9个赞
您还可以使用布尔原子引用:
AtomicReference<Boolean> first = new AtomicReference<Boolean>(Boolean.TRUE);
stream.forEach(e ->
System.out.println("First == " + first.getAndUpdate(b -> false)));
TA贡献1725条经验 获得超7个赞
有StreamEx
扩展标准 Java 的 Stream API 的库。使用StreamEx.of(Iterator)
和peekFirst
:
StreamEx.of(itemIter.iterator()) .peekFirst(e -> System.out.println(e.getClass().getSimpleName())) .forEach(System.out::println);
TA贡献1815条经验 获得超13个赞
本机解决方案: Stream在 Java 中不可重用。这意味着,消费流只能完成一次。如果您从流中获取第一个元素,则可以再对其进行一次迭代。
解决方法是创建另一个与第一个相同的流或获取第一个项目,然后创建一个流,如下所示:
Stream<E> stream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(sourceIterator, Spliterator.ORDERED), false);
E firstElement = itemIter.next();
stream.foreach(...);
编辑
实际上没有任何方法可以“复制”流,您需要保留一个迭代器/集合。更多关于它的信息。当流用完后涉及内存时,它可以被垃圾收集器收集,因为它没有用处。Stream 本身所占用的空间并不比它所源自的迭代器多。请记住,流可能是无限的。当前操作的元素存储在内存中。
添加回答
举报