是否有一种直接的方式将java.io.ObjectInputStream
与java.util.stream.Stream
一起使用?
似乎提供了java.io.BufferedReader.lines
来将缓冲的阅读器转换为Stream,但似乎没有Object的等价物。
有没有人有这个转换的好解决方案?
答案 0 :(得分:4)
ObjectInputStream可以读取比Objects更多的内容。该类实现了DataInput,因此它可以读取各种数据。然后是readUnshared
之类的特殊方法。因此,Stream将是ObjectInputStream功能的一个非常有限的子集。
但是如果你只想逐个阅读对象,你可以编写自己的方法:
public Stream<Object> toStream(final ObjectInputStream stream) {
return Stream.generate(() -> readObject(stream)).onClose(
() -> close(stream));
}
private static Object readObject(ObjectInputStream stream) {
try {
return stream.readObject();
} catch (IOException e) {
throw new UncheckedIOException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
private static void close(Closeable c) {
try {
c.close();
} catch (IOException e) {
logger.log(Level.WARNING, "Couldn't close " + c, e);
}
}
你甚至可以有一个打字的流:
public <T> Stream<T> toStream(final ObjectInputStream stream,
final Class<T> cls) {
return Stream.generate(() -> cls.cast(readObject(stream))).onClose(
() -> close(stream));
}
答案 1 :(得分:0)
此解决方案生成有限流而不会在末尾抛出EOFException
。它还会在最后优雅地关闭流。我必须实现一个Spliterator,它尝试读取hasNext()
并返回next()
上读取的元素。
public static <T> Stream<T> toStream(final ObjectInputStream stream,
final Class<T> cls) {
Spliterator<T> spliterator = Spliterators.spliteratorUnknownSize(new Iterator<T>() {
private T next;
private boolean read = false;
@Override
public boolean hasNext() {
if (!read) {
try {
next = cls.cast(stream.readUnshared());
} catch (EOFException e) {
next = null;
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
read = true;
}
return next != null;
}
@Override
public T next() {
read = false;
return next;
}
}, Spliterator.DISTINCT | Spliterator.IMMUTABLE |
Spliterator.ORDERED | Spliterator.NONNULL);
return StreamSupport.stream(spliterator, false).onClose(() -> {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
});
}