【问题标题】:java 8 lambda recursion failingjava 8 lambda递归失败
【发布时间】:2018-01-17 14:59:53
【问题描述】:

我正在尝试使用 lambda 递归遍历目录和每个子目录,同时将每个子目录推送到新线程。

问题是它正在通过顶级目录和 所有第一轮子目录,但拒绝深入第一级子目录中的任何子目录。

我不明白为什么它适用于第一级递归但不适用于第二级。嵌套线程和/或 lambda 函数的次数是否有限制?

下面是我的代码的相关部分:

public class Main
{
    public static ExecutorService localExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    public static void getFileNames(final Path dir)
    {
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir))
        {
            for (Path path : stream) {
                System.out.println(path);

                if (path.toFile().isDirectory()) {
                    Runnable subDir = () -> getFileNames(path);

                    localExecutor.submit(subDir);
                }
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String... args)
    {
        getFileNames(
            FileSystems.getDefault().getPath("C:\\A")
        );
         //
     //I wait for it to finish all tasks in another method that contains the below

        functions.localExecutor.shutdown();
        try {
        functions.localExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            System.out.print("Exception: the following error occured: ");
            System.out.println(e.toString());
            MainLogic.log.add("Exception: the following error occured: " +     e.toString());
        }

    }

}

【问题讨论】:

  • 1) 变量应该是小写的 LocalExecutor -> localExecutor。 2)你不需要围绕你的 lambda 大括号。 Runnable subDir = () -&gt; getFileNames(path,i,directory); 很好 3) 不要混合数组和 Lists
  • 您是否尝试过实际调试它?像换行符,打印语句等?您的代码不完整。缺少捕获,没有返回并且没有足够的右大括号。
  • 您确定等待的时间够长吗?您可能希望在列表中捕获submit 返回的Future 并等待它们全部完成。或者,您可以在ExecutorService 上调用shutdown 以等待其完成处理。
  • @Michael - 缺少 catch 是因为 try(DirectoryStream&lt;Path&gt; stream = Files.newDirectoryStream(dir)) 这是一个 try-with-resources 子句,它将自动关闭资源。
  • @OldCurmudgeon 它是 try-with-resources 但 newDirectoryStream 抛出 IOException 这是一个需要 catch 块的检查异常(或者方法签名应该更改)。

标签: java recursion lambda subdirectory


【解决方案1】:

问题是你的程序没有等待那些子任务被执行。它只是立即返回。所以只打印出第一级目录,因为那些 println 不依赖于任何可运行的子目录来执行。

通常可以调用ExecutorServiceshutdownawaitTermination,等待任何挂起的任务运行。但是,这在您的情况下不起作用,因为直到稍后执行其父目录的任务时才会添加更深的目录级别的相应任务。

【讨论】:

  • 代码public static void main(String... args) { getFileNames( FileSystems.getDefault().getPath("C:\\A") ); } 永远不会等待异步线程的终止,如上所述,上面的主要方法在异步线程完成之前终止。
  • 抱歉,我修正了我的问题,以充分反映我的代码在这部分所做的工作。它正在等待修改后的问题中的演示,但仍然不适用于第二级子目录。它适用于第一级目录和第一级目录,但是一旦到达二级子目录,也就是文件夹/文件夹/文件夹,它就会停止工作。然而它适用于文件夹/文件夹和文件夹
  • @phalanx 如第二段所述,您等待的方式将永远无法工作,一旦您调用关闭,将不允许执行任何新任务,因此您只会获得顶层目录的 println 和第一级子目录名称。我自己从未编写过代码,所以我无法给出具体的建议……但您可能想尝试创建一个Spliterator,它会在所有子目录中生成一个可并行化的流。
  • 但我很困惑这是怎么回事,因为我没有受到任何执行程序终止错误的影响,如果将新任务推送到已关闭的执行程序,就会发生这种情况。
  • @phalanx 我明白你的意思。由于您只是打印异常堆栈跟踪,因此如果您以某种方式将输出重定向到某处,则这些跟踪可能会丢失(我的意思是它不会在输出中显示给您)。你可以试着不去捕捉它们,看看这是否会让你的程序更早停止。
猜你喜欢
  • 2013-10-26
  • 1970-01-01
  • 2015-05-29
  • 2011-07-08
  • 2019-03-01
  • 2017-11-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多