如何实现Java流?

问题描述 投票:0回答:6

我想实施一个

Stream<T>

我不想只使用

implements Stream<T>
,因为我必须实现大量方法。

这可以避免吗?

更具体地说,我如何流式传输

t1
t2
t3
,例如:

class Foo<T> {
    T t1, t2, t3;

    Foo(T t1, T t2, T t3) {
        this.t1 = t1;
        this.t2 = t2;
        this.t3 = t3;
    }
}
java java-8 java-stream
6个回答
56
投票

JDK对

Stream
的标准实现是内部类
java.util.stream.ReferencePipeline
,你不能直接实例化它。

您可以使用

java.util.stream.Stream.builder()
java.util.stream.StreamSupport.stream(Spliterator<T>, boolean)
和各种 12 其他静态工厂方法来创建默认实现的实例。

使用 spliterator 可能是最强大的方法,因为它允许您惰性地提供对象,同时如果您的源可以分为多个块,还可以实现高效的并行化。

此外,如果您需要实现自己的有状态中间操作,您还可以将流转换回拆分器,将它们包装在自定义拆分器中,然后将它们转换回流 - 例如由于标准 API 的缺陷 - 因为大多数可用的中间操作不允许有状态
请参阅这个 SO 答案作为示例。

原则上你可以编写自己的流接口实现,但这会非常乏味。


23
投票

如果您因为需要自定义

close()
逻辑而想要创建自己的 Stream,最简单的解决方案是从迭代器创建 Stream,并调用
onClose(Runnable)
。例如,通过 Jackson 从 Reader 进行流式传输:

MappingIterator<?> values = objectMapper.reader(type).readValues(reader);
return StreamSupport
        .stream(Spliterators.spliteratorUnknownSize(values, Spliterator.ORDERED), false)
        .onClose(() -> {
            try {
                reader.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });

18
投票

您通常不需要编写自己的流类。相反,您可以通过现有方法创建流。例如,以下是如何创建值 1, 100 的流:

  AtomicInteger n = new AtomicInteger(0);
  Stream<Integer> stream = Stream.generate(() -> n.incrementAndGet()).limit(100);

所以在这里我们创建了一个无限的整数流:1, 2, 3, ....然后我们在该无限流上使用

limit(100)
来获取 100 个元素的流。

为了清楚起见,如果您想要整数流(以固定间隔),您应该使用

IntStream.range()
。这只是一个示例,展示如何使用
Stream.generate()
定义流,这为您提供了更大的灵活性,因为它允许您使用任意逻辑来确定蒸汽的元素。


11
投票

其他人已经回答了如何提供通用的

Stream
实现。关于您的具体要求,只需执行以下操作:

class Foo<T> {

    T t1, t2, t3;

    Foo(T t1, T t2, T t3) {
        this.t1 = t1;
        this.t2 = t2;
        this.t3 = t3;
    }

    Stream<T> stream() {
        return Stream.of(t1, t2, t3);
    }
}

11
投票

为了完整起见,因为我没有直接在此处的答案中找到这一点: 如果您想将现有的迭代器转换为流(例如,因为您想连续生成元素),请使用:

StreamSupport.stream(
    Spliterators.spliterator(myIterator, /* initial size*/ 0L, Spliterator.NONNULL), 
    /* not parallel */ false);

我发现这个有点难找,因为你需要了解 StreamSupport、Spliterators 和 Spliterator


0
投票

虽然这对于具有有限多个值的示例来说不是一个好的解决方案,因为这个问题是在搜索如何实现流时出现的,但也许值得一提的是实现无限流的简单方法,

Stream.generate(Supplier)
,例如:

    return Stream.generate(() -> Math.random());
© www.soinside.com 2019 - 2024. All rights reserved.