当前位置: 首页 > 知识库问答 >
问题:

在Java中对流使用Optional

师建德
2023-03-14

我试图重构旧代码以使用流,我的第一个方法是:

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()?

谢谢

共有2个答案

谢和颂
2023-03-14

在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);
}
柳经纶
2023-03-14

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中的流来实现这一点?