2017-12-15 8 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(","))); 
     } 
    }); 

이 나는 ​​일의 흐름이 나에 운영하는 일반적인 패턴이며, 나는 다음 스트림 한 일을 할 수있는 필터를 기반으로 두 개의 스트림을 생성,이 스트림을 필터링 할 그리고 스트림 B에 또 다른 것은 안티 패턴인가, 아니면 어떻게 든 지원 되는가?

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

'map'을 사용하십시오. 또는 정말로 원하면'partition'을 사용하십시오. –

+1

[스트림을 두 스트림으로 분할 할 수 있습니까?] (https://stackoverflow.com/questions/19940319/can-you-split-a-stream-into-two-streams) –

+0

두 개의 스트림을 만듭니다. * 필터링하지 않고 분할하여 귀하의 경우 분할하여; 두 개의 스트림을 실제로 분리 할 수는 없습니다. 두 부분으로 수집해야합니다. 이것은 안티 패턴이 아니며 여기에 표시된 답변은 정확히 – Eugene

답변

5

다음은 작업을 체인 수 모든 요소가 알려질 때까지이를 유지하는 데이터 구조로 수집하는 것입니다. 이것은 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); 
    } 
}); 

: 아직도, 당신은 당신의 코드를 단순화 할 수 있습니다. 로깅 동작은 두 경우 모두 동일하지만 메시지에서만 다릅니다.

여전히 흥미로운 점은 입니다. 은 파일을 삭제하지 못했음을 나타냅니다. 왜은 말하지 않습니다. 자바 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) 대신 Files.deleteIfExists(p)을 사용하면 이미 삭제 된 것이 성공으로 처리됩니다.

2

당신이 함께 카테고리 중 하나의 모든 파일을 기록하려면이 방법이 없습니다 : 당신이 특히 명시 적 변수 중간지도를 참조하지 않으려면