如何在继续流式传输时获取第一个元素?

我有一系列通用项目。我想打印第一个项目的类名+toString()所有项目的类名。


如果我有一个 Iterable,它看起来像这样:


Iterable<E> itemIter = ...;

boolean first = true;

for (E e : itemIter) {

    if (first) {

        first = false;

        System.out.println(e.getClass().getSimpleName());

    }

    System.out.println(e);

}

我可以Stream<T>使用流 API 在流 ( ) 上执行此操作吗?


* 请注意,这是一个关于流的问题,而不是关于迭代器的问题。我有一个流 - 不是迭代器。


慕桂英4014372
浏览 186回答 5
5回答

红糖糍粑

如果你的出发点是 aStream并且你想保留它的所有属性和惰性,那么下面的解决方案就可以了:public static <E> Stream<E> forFirst(Stream<E> stream, Consumer<? super E> c) {&nbsp; &nbsp; boolean parallel = stream.isParallel();&nbsp; &nbsp; Spliterator<E> sp = stream.spliterator();&nbsp; &nbsp; return StreamSupport.stream(() -> {&nbsp; &nbsp; &nbsp; &nbsp; if(sp.getExactSizeIfKnown() == 0) return sp;&nbsp; &nbsp; &nbsp; &nbsp; Stream.Builder<E> b = Stream.builder();&nbsp; &nbsp; &nbsp; &nbsp; if(!sp.tryAdvance(b.andThen(c))) return sp;&nbsp; &nbsp; &nbsp; &nbsp; return Stream.concat(b.build(), StreamSupport.stream(sp, parallel)).spliterator();&nbsp; &nbsp; }, sp.characteristics(), parallel);}例如,当你使用它时List<String> list = new ArrayList<>(List.of("foo", "bar", "baz"));Stream<String> stream = forFirst(&nbsp; &nbsp; &nbsp; &nbsp; list.stream().filter(s -> s.startsWith("b")),&nbsp; &nbsp; &nbsp; &nbsp; s -> System.out.println(s+" ("+s.getClass().getSimpleName()+')')&nbsp; &nbsp; ).map(String::toUpperCase);list.add(1, "blah");System.out.println(stream.collect(Collectors.joining(" | ")));它会打印blah (String)BLAH | BAR | BAZ证明在开始终端操作 () 之前处理不会开始collect,因此反映了对源的先前更新List。

桃花长相依

您可以滥用减少:Stream<E>&nbsp;stream&nbsp;=&nbsp;...;System.out.println(stream &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.reduce("",(out,e)&nbsp;->&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out&nbsp;+&nbsp;(out.isEmpty()&nbsp;?&nbsp;e.getClass().getSimpleName()+"\n"&nbsp;:&nbsp;"") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;e));

暮色呼如

您还可以使用布尔原子引用:AtomicReference<Boolean> first = new AtomicReference<Boolean>(Boolean.TRUE);stream.forEach(e ->&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.out.println("First == " + first.getAndUpdate(b -> false)));

qq_遁去的一_1

有StreamEx扩展标准 Java 的 Stream API 的库。使用StreamEx.of(Iterator)和peekFirst:StreamEx.of(itemIter.iterator()) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.peekFirst(e&nbsp;->&nbsp;System.out.println(e.getClass().getSimpleName())) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.forEach(System.out::println);

萧十郎

本机解决方案: Stream在 Java 中不可重用。这意味着,消费流只能完成一次。如果您从流中获取第一个元素,则可以再对其进行一次迭代。解决方法是创建另一个与第一个相同的流或获取第一个项目,然后创建一个流,如下所示:Stream<E> stream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(sourceIterator, Spliterator.ORDERED), false);E firstElement = itemIter.next();stream.foreach(...);编辑实际上没有任何方法可以“复制”流,您需要保留一个迭代器/集合。更多关于它的信息。当流用完后涉及内存时,它可以被垃圾收集器收集,因为它没有用处。Stream 本身所占用的空间并不比它所源自的迭代器多。请记住,流可能是无限的。当前操作的元素存储在内存中。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java