Java 如何在功能上处理分割流

Java 如何在功能上处理分割流,java,java-8,functional-programming,java-stream,Java,Java 8,Functional Programming,Java Stream,给定以下代码,如何将其简化为单个功能行 // DELETE CSV TEMP FILES final Map<Boolean, List<File>> deleteResults = Stream.of(tmpDir.listFiles()) .filter(tempFile -> tempFile.getName().endsWith(".csv")) .collect(Collectors.part

给定以下代码,如何将其简化为单个功能行

    // 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做一件事,对流B做另一件事。这是反模式吗,或者它是以某种方式被支持的?

如果您特别不希望显式变量引用中间映射,那么您可以只链接操作:

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

如果您特别不希望显式变量引用中间映射,那么您可以只链接操作:

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

若要将任一类别的所有文件记录在一起,在所有元素都已知之前,无法将它们收集到保存它们的数据结构中。不过,您可以简化代码:

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);
    }
});
这不会将文件收集到列表中,而是首先收集到后续日志记录操作所需的字符串中。对于这两种情况,日志记录操作也是相同的,但只在消息中有所不同

不过,最有趣的是删除文件失败的原因,布尔值无法说明这一点。自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.deleteIfExistsp而不是Files.deletep,并且已被删除将被视为成功。

如果要将任一类别的所有文件记录在一起,在所有元素都已知之前,无法将它们收集到保存它们的数据结构中。不过,您可以简化代码:

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);
    }
});
这不会将文件收集到列表中,而是首先收集到后续日志记录操作所需的字符串中。对于这两种情况,日志记录操作也是相同的,但只在消息中有所不同

不过,最有趣的是删除文件失败的原因,布尔值无法说明这一点。自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.deleteIfExistsp而不是Files.deletep,并且已删除将被视为成功。

使用map。或者,如果你真的愿意,可以使用分区。你可能的重复不是通过过滤而是通过分组创建两个流,在你的例子中是通过分区;你不可能真的把一条河流一分为二——你必须把它分成两部分;这不是一个反模式,这里显示的答案正是使用map。或者,如果你真的愿意,可以使用分区。你可能的重复不是通过过滤而是通过分组创建两个流,在你的例子中是通过分区;你不可能真的把一条河流一分为二——你必须把它分成两部分;这不是一个反模式,这里给出的答案正是如此