我正在尝试使用一个很好的toString方法将一个自定义对象流写入一个文件,逐行。到目前为止我所拥有的是:
private static void writeToFile(Set<Article> articles, Charset cs, Path path) throws IOException {
try(Writer w =
new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(path.toFile()), cs))) {
articles.stream().map(Article::toString).forEach(w::write);
} catch(IOException e) {}
我在w :: write上收到错误未处理的IOException ,这很奇怪,因为我正在捕获此异常?
其他方面,是否可以逐行编写这些对象?
答案 0 :(得分:3)
PrintWriter
对于此类案例很有用,因为它的方法不会抛出IOException
。它还有print(Object)
个重载,它通过toString
方法将对象转换为字符串。 (实际上它会在委托给String.valueOf
之前调用toString
来处理空值。)
不幸的是PrintWriter
是一种过时的API,因为它需要File
而不是Path
和charset名称而不是实际的Charset
对象。但转换并不是一件大事。
由于不需要中间map
调用来将对象转换为字符串,因此直接在集合上调用forEach
就足够了。
以下是生成的代码:
static void writeToFile(Set<Article> articles, Charset cs, Path path) throws IOException {
try (PrintWriter pw = new PrintWriter(path.toFile(), cs.name())) {
articles.forEach(pw::println);
}
}
答案 1 :(得分:2)
foreach
需要Consumer<? super E>
,其中E
是Stream
元素的类型。 Consumer<T>::accept
的签名是
void accept(T t)
请注意它不会抛出任何已检查的异常。
现在,Writer::write
会抛出一个已检查的IOException
,因此当您执行.foreach(w::write)
时,编译器会抱怨,因为您尝试使用抛出的方法例外(Writer::write
),不是(Consumer<T>::accept
)。为了解决这个问题,您必须在foreach
本身处理异常:
articles.stream().map(Article::toString).forEach(str -> {
try {
w.write(str + System.lineSeparator()); // Add a newline to each string.
} catch(IOException e) {
...
}
});
请注意,您可以在内存中构建整个String
,而不是从流中写入,然后一次性写入。
String data = articles.stream().map(Article::toString).map(str -> str + System.lineSeparator()).reduce("", (acc, str) -> str + acc)
w.write(data.substring(0, data.length()-1)); // Drop last newline