为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

慕桂英4014372 2022-07-20 21:05:20
我有一系列通用项目。我想打印第一个项目的类名+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 在流 ( ) 上执行此操作吗?* 请注意,这是一个关于流的问题,而不是关于迭代器的问题。我有一个流 - 不是迭代器。
查看完整描述

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。


查看完整回答
反对 回复 2022-07-20
?
桃花长相依

TA贡献1860条经验 获得超8个赞

您可以滥用减少:

Stream<E> stream = ...;System.out.println(stream
                   .reduce("",(out,e) -> 
                   out + (out.isEmpty() ? e.getClass().getSimpleName()+"\n" : "")
                   + e));


查看完整回答
反对 回复 2022-07-20
?
暮色呼如

TA贡献1853条经验 获得超9个赞

您还可以使用布尔原子引用:


AtomicReference<Boolean> first = new AtomicReference<Boolean>(Boolean.TRUE);

stream.forEach(e -> 

         System.out.println("First == " + first.getAndUpdate(b -> false)));


查看完整回答
反对 回复 2022-07-20
?
qq_遁去的一_1

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);


查看完整回答
反对 回复 2022-07-20
?
萧十郎

TA贡献1815条经验 获得超13个赞

本机解决方案: Stream在 Java 中不可重用。这意味着,消费流只能完成一次。如果您从流中获取第一个元素,则可以再对其进行一次迭代。


解决方法是创建另一个与第一个相同的流或获取第一个项目,然后创建一个流,如下所示:


Stream<E> stream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(sourceIterator, Spliterator.ORDERED), false);

E firstElement = itemIter.next();

stream.foreach(...);

编辑


实际上没有任何方法可以“复制”流,您需要保留一个迭代器/集合。更多关于它的信息。当流用完后涉及内存时,它可以被垃圾收集器收集,因为它没有用处。Stream 本身所占用的空间并不比它所源自的迭代器多。请记住,流可能是无限的。当前操作的元素存储在内存中。


查看完整回答
反对 回复 2022-07-20
  • 5 回答
  • 0 关注
  • 185 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信