簡體   English   中英

在Java中使用可選的Streams

[英]Using Optional with Streams in Java

我試圖重構舊代碼以使用流,我的第一個方法是這樣的:

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

這不是編譯,因為新的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()返回一個Optional,因為這看似合理。 但是在此之后我的代碼變得非常難看:

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

謝謝!

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進行單獨的Stream轉換:

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生成器而不是可選生成器,以利用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);
}

第二個想法,繼續這個解決方案; 它似乎更簡單,而且由於靜態方法無論如何都是私有的,最終用戶,其他開發人員以及可以訪問體面的Java 8反編譯器的隨機人員都不會尖叫( http://www.benf.org/other/ cfr / )。

從Java9開始,您可以使用flatMapOptional::stream來過濾空的Optionals:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM