鉴于以下代码,我如何将其简化为单一的功能线?
// 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.这是一种反模式,还是以某种方式支持?
答案 0 :(得分:5)
如果您特别不希望显式变量引用临时地图,那么您可以将操作链接起来:
.collect(Collectors.partitioningBy(File::delete))
.forEach((del, files) -> {
if (del) {
LOGGER.debug(... files.stream()...);
} else {
LOGGER.debug(... files.stream()...);
});
答案 1 :(得分:2)
如果要将这两个类别的所有文件一起记录,则无法将它们收集到包含它们的数据结构中,直到所有元素都已知。不过,您可以简化代码:
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);
}
});
这不会将文件收集到List
中,而是收集到预期的String
中以用于后续的日志记录操作。对于这两种情况,日志记录操作也是相同的,但仅在消息中有所不同。
然而,最有趣的是为什么删除文件失败,而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.deleteIfExists(p)
代替Files.delete(p)
,并且已被删除将被视为成功。