我正在为Java 8中的文件编写解析器。使用Files.lines
读取文件并返回序列Stream<String>
。
每一行都映射到数据对象Result
,如下所示:
Result parse(String _line) {
// ... code here
Result _result = new Result().
if (/* line is not needed */) {
return null;
} else {
/* parse line into result */
return _result;
}
}
现在我们可以将流中的每一行映射到相应的结果:
public Stream<Result> parseFile(Path _file) {
Stream<String> _stream = Files.lines(_file);
Stream<Result> _resultStream = _stream.map(this::parse);
}
但是,流现在包含我要删除的null
个值:
parseFile(_file).filter(v -> v != null);
我如何组合地图/过滤器操作,正如我在parseLine/_stream.map
中已经知道的那样,是否需要结果?
答案 0 :(得分:11)
正如评论中已经指出的那样,流将在一次通过中处理,因此实际上不需要改变任何东西。对于它的价值,你可以使用flatMap
并让parse
返回一个流:
Stream<Result> parse(String _line) {
.. code here
Result _result = new Result().
if (/* line is not needed */) {
return Stream.empty();
} else {
/** parse line into result */
return Stream.of(_result);
}
}
public Stream<Result> parseFile(Path _file) {
return Files.lines(_file)
.flatMap(this::parse);
}
这样一来,你就不会有null
个值。
答案 1 :(得分:3)
更新Java 9:
使用Stream<Result>
似乎是parse()
函数的错误返回类型。流可以包含许多很多值,因此parse()
的用户必须假设流中最多只有一个值,或者使用类似collect
的内容来提取和使用结果parse()
操作。如果函数及其用法仅由几行代码分隔,则可能没问题,但如果距离增加,例如在JUnit测试的完全不同的文件中,则返回值不清楚接口契约。
当不需要该行时,返回空Stream
将是一个更好的接口契约,而不是返回Optional
。
Optional<Result> parse(String _line) {
... code here
Result _result = null;
if (/* line needed */) {
/** parse line into result */
}
return Optional.ofNullable(_result);
}
不幸的是,现在_stream.map(this::parse)
会返回Optional
个值的流,因此对于Java 8,您需要再次使用.filter(Optional::isPresent).map(Optional::get)
进行过滤和映射,问题是寻找一个可以“一气呵成”做到这一点的解决方案。
这个问题是3年前发布的。使用Java 9,我们现在可以使用Optional::stream
方法选择(双关语),所以我们可以写:
public Stream<Result> parseFile(Path _file) {
return Files.lines(_file)
.map(this::parse)
.flatMap(Optional::stream)
}
将Optional
值流转换为Result
值流,而不包含任何空选项。