在Java中对流使用可选的

在Java中对流使用可选的,java,java-8,optional,java-stream,Java,Java 8,Optional,Java Stream,我试图重构旧代码以使用流,我的第一种方法是: 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 -> ima

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

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()引发IOException

用UncheckedIOException包装这些异常不会起作用,因为如果其中一个异常失败,我不想停止处理其他图像

因此,我结束了两个私有方法的编写:

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
    }
}
有没有办法避免在代码中使用get()和isPresent()


谢谢

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));
}
另一种方法(我拒绝推荐作为主要解决方案,因为它比较奇怪)是将静态图像创建方法更改为流生成器,而不是可选的生成器,以利用flatMap:

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);
}
私有流createImage(路径imagePath){
试一试{
返回流(新图像(imagePath));
}捕获(IOE异常){
返回Stream.empty();
}
}
public void run()引发IOException{
文件列表(源)
.filter(图像::isImage)
//将结果图像插入到流中(空流可无缝处理)
.flatMap(此::createImage)
.filter(image->image.isProportional(this.height,this.width))
.map(image->image.resize(this.height,this.width))
.forEach(this::write);
}

再想一想,采用这个解决方案;它似乎更简单,而且由于静态方法无论如何都是私有的,最终用户、其他开发人员和能够访问体面的Java 8反编译器()的随机人员会发出更少的尖叫声。

从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);
}
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);
}
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);
}