如何使流管道更简单

我认为我的代码需要改进。 我在流的filter()map()阶段使用对象allSummaryTSTLog ,所以我必须调用File.listFiles两次:

 public static List ParserPath(List allLogPath) { FilenameFilter filter = new MyFilter("Summary_TSTLog"); return allLogPath.parallelStream().filter(path -> { File testPath = new File(path); if (!testPath.isDirectory()) { MyLog.log.info("test path : [" + path + "] is not exist, continue"); return false; } File[] allSummaryTSTLog = testPath.listFiles(filter); if (allSummaryTSTLog == null || allSummaryTSTLog.length == 0) { MyLog.log.info("test path : [" + path + "] has no Summary_TSTLog files"); return false; } return true; }).map(path -> { String[] nameTempStr = path.split("\\\\"); String testName = nameTempStr[nameTempStr.length - 1]; File[] allSummaryTSTLog = new File(path).listFiles(filter); return new Test(testName, Arrays.asList(allSummaryTSTLog)); }).collect(Collectors.toList()); } 

如何调用allSummaryTSTLog File.listFiles()只创建一次allSummaryTSTLog

希望基于某些计算过滤流元素,然后在稍后的流水线阶段重用该计算的结果并不罕见。 你当然可以在后面的管道阶段重新计算这个结果,但如果你不想这样做,这是非常合理的。 如果流元素本身不能存储那些计算结果,并且您不想重新计算它们,则必须创建一个辅助类来承载原始元素并在流中计算结果。

我查看了管道中使用的数据,这是我提出的帮助类:

 static class FileInfo { final String fullName; final String lastName; final File[] allSummaryTSTLog; FileInfo(String n, FilenameFilter fnf) { fullName = n; String[] tmp = n.split("\\\\"); lastName = tmp[tmp.length - 1]; allSummaryTSTLog = new File(n).listFiles(fnf); } } 

请注意,为简洁起见,我在这里作了一些欺骗。 首先,我没有显式检查isDirectory ,而是利用File.listFiles如果File不是目录则返回null的事实。 我也没有打算区分给定文件名不是目录的情况与它是目录但不包含匹配文件的情况。 (但这对你来说可能很重要;我不确定。)

最后,我在构造函数中执行文件名路径拆分,以便在必要时可以使用名称的最后一个组件。 拆分需要一个局部变量。 如果拆分是在稍后的管道阶段完成的,那么局部变量将强制使用语句lambda而不是表达式lambda,这会使事情变得更加繁琐。 权衡的是,我们可能最终会对最终被过滤掉的文件进行路径名拆分,但这看起来并不是过多的费用。

有了这个辅助类,管道可以重写如下:

  static List parserPath(List allLogPath) { FilenameFilter filter = new MyFilter("Summary_TSTLog"); return allLogPath.parallelStream() .map(str -> new FileInfo(str, filter)) .filter(fi -> fi.allSummaryTSTLog != null && fi.allSummaryTSTLog.length > 0) .map(fi -> new Test(fi.lastName, Arrays.asList(fi.allSummaryTSTLog))) .collect(toList()); } 

在第一个管道阶段,我们将传入的流元素映射到我们的辅助类的实例中。 后续阶段可以使用辅助类中的数据,而无需重新计算它。

这是2015年。请勿使用File

此外,根本不知道你想做什么(你MyFilter做什么?什么是Test ?)。

使用这样的东西:

 final BiPredicate predicate = (path, attrs) -> { return attrs.isRegularFile() && path.getFileName().toString().equals(something); }; try ( final Stream stream = Files.find(baseDir, filter); ) { // work with the stream } 

由于您的post中没有关于您想要做什么的线索,因此这是最好的方法。

有关如何获取Path ,请参阅Paths.get() 。 和java.nio.file的doc一般。