如何表示一个空的InputStream

时间:2018-03-13 19:35:18

标签: java java-stream inputstream

我正在减少InputStreams的流,如此:

InputStream total = input.collect(
    Collectors.reducing(
        empty,
        Item::getInputStream, 
        (is1, is2) -> new SequenceInputStream(is1, is2)));

对于身份InputStream,我正在使用:

InputStream empty = new ByteArrayInputStream(new byte[0]);

这样可行,但是有更好的方法来表示空的InputStream吗?

4 个答案:

答案 0 :(得分:12)

由于InputStream只有一个抽象方法,read()

  

public abstract int read() throws IOException

     

<强>返回:
  数据的下一个字节,如果到达流的末尾,则为-1

anonymous subclass很容易创建一个空流。 像这样:

InputStream empty = new InputStream() {
    @Override
    public int read() {
        return -1;  // end of stream
    }
};

但不可否认,它的代码多于空ByteArrayInputStream

答案 1 :(得分:3)

我会走另一条路。

通过InputStream减少大量(is1, is2) -> new SequenceInputStream(is1, is2)个实例可能会造成SequenceInputStream个实例的深度不平衡树,这可能会变得非常低效。

线性数据结构更合适:

InputStream total = new SequenceInputStream(
    Collections.enumeration(input.map(Item::getInputStream).collect(Collectors.toList())));

这会创建一个SequenceInputStream处理所有收集的输入流。由于这本身也处理空列表情况,因此不再需要特殊的空InputStream实现。

但是当你看the source code of SequenceInputStream时,你会发现这个课程毫无魔力,事实上,我们甚至可以通过不使用VectorEnumeration之类的古老课程来做得更好:

public class StreamInputStream extends InputStream {
    final Spliterator<? extends InputStream> source;
    final Consumer<InputStream> c = is -> in = Objects.requireNonNull(is);
    InputStream in;

    public StreamInputStream(Stream<? extends InputStream> sourceStream) {
        (source = sourceStream.spliterator()).tryAdvance(c);
    }
    public StreamInputStream(InputStream first, InputStream second) {
        this(Stream.of(first, second));
    }
    public int available() throws IOException {
        return in == null? 0: in.available();
    }
    public int read() throws IOException {
        if(in == null) return -1;
        int b; do b = in.read(); while(b<0 && next());
        return b;
    }
    public int read(byte b[], int off, int len) throws IOException {
        if((off|len) < 0 || len > b.length - off) throw new IndexOutOfBoundsException();
        if(in == null) return -1; else if(len == 0) return 0;
        int n; do n = in.read(b, off, len); while(n<0 && next());
        return n;
    }
    public void close() throws IOException {
        closeCurrent();
    }
    private boolean next() throws IOException {
        closeCurrent();
        return source.tryAdvance(c);
    }
    private void closeCurrent() throws IOException {
        if(in != null) try { in.close(); } finally { in = null; }
    }
}

除了更简单和更清晰(它不需要catch (IOException ex) { throw new Error("panic"); }之类的语句)之外,它还考虑了流的惰性:当在遍历所有元素之前关闭它时,它不会遍历剩余的流来关闭InputStream元素,因为它们通常甚至不会在此时创建,因此不需要关闭。

现在,流的创建就像

一样简单
InputStream total = new StreamInputStream(input.map(Item::getInputStream));

答案 2 :(得分:3)

从Java 11开始,您可以使用静态方法InputStream.nullInputStream()

  

返回不读取字节的新InputStream。返回的流最初是打开的。通过调用close()方法关闭流。随后对close()的调用无效。

答案 3 :(得分:0)

如果您的项目中有 Apache commons-io

import org.apache.commons.io.IOUtils

IOUtils.toInputStream("")