Java如何在现有接口之上构建流

时间:2018-11-24 21:30:51

标签: java java-stream

我有一个现有的界面,该界面使我可以访问如下所示的理论上无限的集合:

List<Element> retrieve(int start, int end);

//example
retrieve(5, 10); // retrieves the elements 5 through 10.

现在,我想在此现有接口之上构建Java流,这样我就可以流式传输所需数量的元素,而无需立即请求大列表。

我将如何去做?

我查看了Java流的示例,发现的所有示例都是如何从完全在内存中的集合创建流的示例。我目前一次加载30个元素,并进行必要的处理,但是如果我可以抽象出该逻辑并返回一个流,那会更干净。

2 个答案:

答案 0 :(得分:2)

class Chunk implements Supplier<Element> {
    private final Generator generator;
    private final int chunkSize;
    private List<Element> list = Collections.emptyList();
    private int index = 0;

    public Chunk(Generator generator, int chunkSize) {
        assert chunkSize > 0;
        this.generator = generator;
        this.chunkSize = chunkSize;
    }

    @Override
    public Element get() {
        if (list.isEmpty()) {
            list = generator.retrieve(index, index + chunkSize);
            index += chunkSize;
        }
        return list.remove(0);
    }
}

在这里,我假设retrieve返回一个可变列表。如果没有,那么此时您需要创建一个新的ArrayList或等效的文件。

这可以用作Stream.generate(new Chuck(generator, 30))。它会生成一个从索引0开始的无限流。您可以添加一个构造函数,以便在有用的情况下设置起始索引。

答案 1 :(得分:1)

我认为您无法编辑retrieve方法。

您可以这样做:

IntStream.iterate(1, x -> x + 1).mapToObj(x -> retrieve(x, x).get(0))

如果序列中的一项取决于上一项,那么这意味着您需要重新计算第n条,直到第n条为止。

这可以通过以100为块的方式稍微解决该问题:

IntStream.iterate(1, x -> x + 1).mapToObj(x -> retrieve(1 + (x - 1) * 100, x * 100)).flatMap(List::stream)

如果您可以编辑该界面后面的内容,则可以使用上述Stream<Element>使其返回IntStream.iterate