Java8 带有 try catch 的谓词
Java8 predicate with try catch
我是 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
我认为您需要更换过滤器。检查文件 isRegular
并不意味着您不会获得 AccessException
.
确保过滤掉文件夹。
private static Predicate<Path> fillAccessDenied() {
return p -> {
try {
if(Files.isReadable(p) && !Files.isDirectory(p)) {
return true;
} else {
return false;
}
} catch (UncheckedIOException e) {
e.printStackTrace();
return false;
}
};
}
当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)
和 [=22] 之间不发生变化=].
我是 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
我认为您需要更换过滤器。检查文件 isRegular
并不意味着您不会获得 AccessException
.
确保过滤掉文件夹。
private static Predicate<Path> fillAccessDenied() {
return p -> {
try {
if(Files.isReadable(p) && !Files.isDirectory(p)) {
return true;
} else {
return false;
}
} catch (UncheckedIOException e) {
e.printStackTrace();
return false;
}
};
}
当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)
和 [=22] 之间不发生变化=].