我试图重构旧代码以使用流,我的第一个方法是:
public void run() throws IOException {
Files.list(this.source)
.filter(Images::isImage)
.map(Image::new)
.filter(image -> image.isProportional(this.height, this.width))
.map(image -> image.resize(this.height, this.width))
.forEach(image -> Images.write(image, this.destination));
}
这不是编译,因为new Image()和Images.write()抛出IOExceptions。
用UncheckedIOException包装这些异常不会起作用,因为如果其中一个图像失败,我不想停止处理其他图像。
所以我结束了写2个私人方法:
private Optional<Image> createImage(Path imagePath) {
try {
return Optional.of(new Image(imagePath));
} catch (IOException e) {
return Optional.empty();
}
}
private void write(Image image) {
try {
Images.write(image, this.destination);
} catch (IOException e) {
// log error
}
}
createImage()返回一个可选值,因为这看起来很明智。然而在此之后,我的代码变得非常丑陋:
public void run() throws IOException {
Files.list(source)
.filter(Images::isImage)
.map(this::createImage)
.filter(image -> image.isPresent() && image.get().isProportional(this.height, this.width))
.map(image -> image.get().resize(this.height, this.width))
.forEach(this::write);
}
有没有办法避免在该代码上使用get()和isPresent()?
谢谢
在Java9中,您可以使用flatMap和Optional::stream过滤空选项:
public void run() throws IOException {
Files.list(source)
.filter(Images::isImage)
.map(this::createImage)
.flatMap(Optional::stream)
.filter(image -> image.isProportional(this.height, this.width))
.map(image -> image.resize(this.height, this.width))
.forEach(this::write);
}
Optionals的一个优点是,仅当Optional::isPresent为true时,才对其应用过滤、映射和平面映射函数,因此:
public void run() throws IOException {
Files.list(source)
.filter(Images::isImage)
.map(this::createImage)
// turns every non-proportional Optional<Image> into empty optionals
.map(image -> image.filter(i -> i.isProportional(this.height, this.width)))
// resizes every proportional Optional<Image>, while doing nothing on the empties
.map(image -> image.map(i -> i.resize(this.height, this.width)))
// applies the writing consumer for each non-empty Optional<Image>
.forEach(image -> image.ifPresent(this::write));
}
另一种方法是在单独的流转换中仅调用Optional::isPresent和Optional::get:
public void run() throws IOException {
Files.list(source)
.filter(Images::isImage)
.map(this::createImage)
// filter out the empty optionals
.filter(Optional::isPresent)
// replace every optional with its contained value
.map(Optional::get)
.filter(image -> image.isProportional(this.height, this.width))
.map(image -> image.resize(this.height, this.width))
.forEach(this::write);
}
还有另一种方法(由于其相对奇怪,我拒绝推荐作为主要解决方案)是将静态图像创建方法更改为Stream生成器,而不是可选生成器,以利用平面图:
private Stream<Image> createImage(Path imagePath) {
try {
return Stream.of(new Image(imagePath));
} catch (IOException e) {
return Stream.empty();
}
}
public void run() throws IOException {
Files.list(source)
.filter(Images::isImage)
// inserts into the stream the resulting image (empty streams are handled seamlessly)
.flatMap(this::createImage)
.filter(image -> image.isProportional(this.height, this.width))
.map(image -> image.resize(this.height, this.width))
.forEach(this::write);
}
再想一想,采用这个解决方案;这似乎更简单,而且由于静态方法无论如何都是私有的,因此最终用户、其他开发人员以及能够访问体面的Java 8反编译器的随机人员的尖叫声会更少(http://www.benf.org/other/cfr/).
问题内容: 我一直在使用JSONObject和JSONReader,但理想情况下,我正在寻找一种混合动力:) 特别是,给定JSON对象流(任意长的JSON数组的一部分),是否有一个帮助程序/库,它一次生成迭代器样式的“ JSONObject”,而无需读取其中的所有内容或不必解析单个原始字段(JsonReader )? 假设API的示例: 上面,调用readObject解析一些复杂的JSON子树,并
问题内容: 您如何先分组然后使用Java流应用过滤? 示例 :考虑此类:我想按部门分组,列出薪水大于2000的雇员。 这就是我可以做到的 输出量 由于B部门中没有雇员的薪水高于2000。因此B部门没有密钥: 但是实际上,我想使用空列表作为密钥– 预期产量 我们应该怎么做? 问题答案: nullpointer的答案显示了直接的方法。如果您不能更新到Java 9,没问题,那么这个收集器就没有魔力。这是
我想利用一个简单的流从http服务收集一些额外的数据,并用这些结果来增强我的数据对象。下面说明了这一想法: 我有一个问题,要理解流的本质和流内部的物化/未来之间的机制和区别。 以下想法并没有向我解释: null
我有以下课程 我正在尝试按贡献者名称和角色名称对ResourceContributor列表进行排序。到目前为止,我得到的是: 我试过使用thenComparing,但还不知道如何使用它。
我是Java的新手,我已经开发了一个程序,允许用户输入他的in-and结果,还可以看到这两个结果的摘要(第二个代码示例)。 我使用文本文件存储数据(第一个示例)。我为每个用户使用两个文本文件,一个用于收入,一个用于结果。 下面的代码示例总结了用户的in-和结果(注意:opnEsoda是一个扫描器): 这会显示:你得到67欧元 我的目标是把这周和这个月花的钱拿出来。我还想知道每一个类别(可选)的花费
假设我们有一个三维的物体列表。 假设我想过滤“l5”,这样如果最里面的列表中的任何元素是奇数,那么整个列表都应该被删除,如果这使得第二级列表为空,那么作为回报应该被删除。 因此,对于给定的示例,在过滤之前,如果: 过滤后,它应该是: 如何使用Java中的流来实现这一点?