java-8 - Java8 谓词与 try catch

标签 java-8 exception java-stream

我是java8流词的新手,但我想了解这一点。 在做了一些简单的事情之后,我变得更深入,所以我喜欢列出一个文件夹中的所有文件。我的想法来自here .

    Files.walk(start)
        .filter(Files::isRegularFile)
        .forEach(System.out::println);

它运行良好,但我运行了一个包含某些规范文件的文件夹,并抛出AccessDeniedException。我查了一下,我知道这不是一个简单的问题。我尝试像这样处理异常:

private static Predicate<Path> fillAccessDenied() {
    return p -> {
        try {
            if(Files.isRegularFile(p)) {                    
                return true;                
            } else {
                return false;
            }
        } catch (UncheckedIOException e) {
            e.printStackTrace();
            return false;
        }
    };
}
  //....
    Files.walk(start)
        .filter(Utils.fillAccessDenied())
        .forEach(System.out::println);

但问题仍然存在,我不明白为什么。有人可以告诉我这里有什么问题吗?

提前致谢!

编辑:

我在 try catch 之间取出了系统,但问题仍然存在。

public static void println(Object x) {

    try {
        String s = String.valueOf(x);
        System.out.println(s);
    } catch (UncheckedIOException e) {
        e.printStackTrace();
    }
}

//...

    Files.walk(start)
        .filter(Utils.fillAccessDenied())
        .forEach(Utils::println);

我的输入路径“/”,我在linux上运行它。会导致这个问题吗?

堆栈跟踪:

java.io.UncheckedIOException: java.nio.file.AccessDeniedException: /etc/sysconfig/network/providers
    at java.nio.file.FileTreeIterator.fetchNextIfNeeded(FileTreeIterator.java:88)
    at java.nio.file.FileTreeIterator.hasNext(FileTreeIterator.java:104)
    at java.util.Iterator.forEachRemaining(Iterator.java:115)
    at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
    at hu.gergelylakatos.jbackupper.JBackupper.main(JBackupper.java:45)
Caused by: java.nio.file.AccessDeniedException: /etc/sysconfig/network/providers
    at sun.nio.fs.UnixException.translateToIOException(UnixException.java:84)
    at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
    at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)
    at sun.nio.fs.UnixFileSystemProvider.newDirectoryStream(UnixFileSystemProvider.java:427)
    at java.nio.file.Files.newDirectoryStream(Files.java:457)
    at java.nio.file.FileTreeWalker.visit(FileTreeWalker.java:300)
    at java.nio.file.FileTreeWalker.next(FileTreeWalker.java:372)
    at java.nio.file.FileTreeIterator.fetchNextIfNeeded(FileTreeIterator.java:95)
    ... 10 more

最佳答案

当异常不是在这个地方抛出时,你无法在 Files.isRegularFile 处捕获异常。由于异常是在实现 Files.walk 的迭代逻辑的代码内部抛出的,因此您只能在 forEach 方法中捕获它,此时它已经终止了整个操作。

您可以自己实现迭代逻辑以获得更多控制。例如

public static Stream<Path> traverse(Path p, BiConsumer<Path,IOException> handler) {
    if(Files.isDirectory(p)) try {
        return Stream.concat(Stream.of(p),
            Files.list(p).flatMap(sub -> traverse(sub, handler)));
    } catch(IOException ex) {
        handler.accept(p,ex);
    }
    return Stream.of(p);
}

你可以这样使用

traverse(start, (p,ex) -> System.err.println(p+": "+ex))
    .filter(Files::isRegularFile)
    .forEach(System.out::println);

打印异常并继续,或者

traverse(start, (p,ex) -> { throw new UncheckedIOException(ex); })
    .filter(Files::isRegularFile)
    .forEach(System.out::println);

Files.walk一样摆脱困境。


当您知道您只对常规文件感兴趣时,您可以创建一个专门的方法,例如

public static Stream<Path> traverseLeafs(Path p, BiConsumer<Path,IOException> handler) {
    if(Files.isDirectory(p)) try {
        return Files.list(p).flatMap(sub -> traverseLeafs(sub, handler));
    } catch(IOException ex) {
        handler.accept(p,ex);
        return Stream.empty();
    }
    return Stream.of(p);
}

排除源目录。不过,您仍然可以使用 filter(Files::isRegularFile) 来排除既不是目录也不是常规文件的特殊文件。

您还可以在此处使用 Files.isDirectory(p) && Files.isReadable(p) 作为条件,以防止 AccessDeniedException 发生,至少只要访问标志在 Files.isReadable(p)Files.list(p) 之间不会更改。

关于java-8 - Java8 谓词与 try catch,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52782500/

相关文章:

python - 我可以从 pdb 中引发异常吗? (用于调试)

c++ - 抛出导致调用析构函数的异常会使程序崩溃

java - SCJP 考试 : Handle Exceptions

Java 8 : change type of entries return Map

Java groupingBy : sum multiple fields

java - Java 8 中的类型不匹配错误

java - 遍历集合,对每个项目执行操作并作为列表返回

Java 8 Streams - 如何比较元素?

java - Vararg 谓词与 Java 8 流

java - 按属性对对象列表进行分组并将其他剩余属性设置为不同的对象列表 : Java 8 stream and Lambdas