2017-12-15 9 views
1

次のコードが与えられたら、それをどのように単一の機能行に簡略化できますか?スプリットストリームを機能的に処理する方法

// DELETE CSV TEMP FILES 
    final Map<Boolean, List<File>> deleteResults = Stream.of(tmpDir.listFiles()) 
      .filter(tempFile -> tempFile.getName().endsWith(".csv")) 
      .collect(Collectors.partitioningBy(File::delete)); 

    // LOG SUCCESSES AND FAILURES 
    deleteResults.entrySet().forEach(entry -> { 
     if (entry.getKey() && !entry.getValue().isEmpty()) { 
      LOGGER.debug("deleted temporary files, {}", 
        entry.getValue().stream().map(File::getAbsolutePath).collect(Collectors.joining(","))); 
     } else if (!entry.getValue().isEmpty()) { 
      LOGGER.debug("failed to delete temporary files, {}", 
        entry.getValue().stream().map(File::getAbsolutePath).collect(Collectors.joining(","))); 
     } 
    }); 

これは私が物事の流れを持っている私はに実行する一般的なパターンであり、そして私は、私はその後、Aをストリーミングするために一つのことを行うことができ、フィルタ、オフに基づいて2つのストリームを作成し、このストリームをフィルタリングしますストリームBへのもう1つのことは反パターンですか、それとも何とかサポートされていますか?

+2

'map'を使用してください。あるいは、本当に必要なら 'partition'を使います。 –

+1

[ストリームを2つのストリームに分割できますか?](https://stackoverflow.com/questions/19940319/can-you-split-a-stream-into-two-streams) –

+0

ストリームを2つ作成しています*はフィルタリングではなく、あなたの場合はパーティショニングによってグループ化します。実際にストリームを2つに分割することはできません.2つの部分で収集する必要があります。これは反パターンではなく、ここに示された答えはまさにその通りです – Eugene

答えて

5

あなたが特に暫定マップを参照し、明示的な変数を使用しない場合は、あなただけの操作をチェーンすることができます

.collect(Collectors.partitioningBy(File::delete)) 
.forEach((del, files) -> { 
    if (del) { 
     LOGGER.debug(... files.stream()...); 
    } else { 
     LOGGER.debug(... files.stream()...); 
    }); 
2

あなたが一緒にどちらかのカテゴリのすべてのファイルを記録したい場合は、方法はありませんすべての要素が分かるまで、それらを保持するデータ構造に集めてください。これはListになく、最初の場所で、その後のログアクションの意図Stringにファイルを収集しません

Stream.of(tmpDir.listFiles()) 
     .filter(tempFile -> tempFile.getName().endsWith(".csv")) 
     .collect(Collectors.partitioningBy(File::delete, 
      Collectors.mapping(File::getAbsolutePath, Collectors.joining(",")))) 
.forEach((success, files) -> { 
    if (!files.isEmpty()) { 
     LOGGER.debug(success? "deleted temporary files, {}": 
           "failed to delete temporary files, {}", 
        files); 
    } 
}); 

:それでも、あなたはあなたのコードを簡素化することができます。ロギングアクションも両方のケースで同じですが、メッセージ内でのみ異なります。

でも、最も興味深いのはです。なぜファイルの削除に失敗しましたか?booleanは通知しません。 Javaの7以来、nioパッケージは、より良い代替提供:

作成するヘルパーメソッド

public static String deleteWithReason(Path p) { 
    String problem; 
    IOException ioEx; 

    try { 
     Files.delete(p); 
     return ""; 
    } 
    catch(FileSystemException ex) { 
     problem = ex.getReason(); 
     ioEx = ex; 
    } 
    catch(IOException ex) { 
     ioEx = ex; 
     problem = null; 
    } 
    return problem!=null? problem.replaceAll("\\.?\\R", ""): ioEx.getClass().getName(); 
} 

を、あなたがそのように呼びたい場合は、

Files.list(tmpDir.toPath()) 
     .filter(tempFile -> tempFile.getFileName().toString().endsWith(".csv")) 
     .collect(Collectors.groupingBy(YourClass::deleteWithReason, 
      Collectors.mapping(p -> p.toAbsolutePath().toString(), Collectors.joining(",")))) 
.forEach((failure, files) -> 
    LOGGER.debug(failure.isEmpty()? "deleted temporary files, {}": 
          "failed to delete temporary files, "+failure+ ", {}", 
       files) 
); 

欠点のようにそれを使用して、あります障害の原因が異なる場合、すべての失敗したファイルについて単一のエントリを生成しません。しかし、削除できなかった理由をログに記録する場合は、避けられないことは明らかです。

「他の誰かが同時に削除した」ことを失敗から除外したい場合は、Files.delete(p)の代わりに​​を単に使用して、すでに削除されているものは成功として処理されます。

関連する問題