在Java 8流中捕获UncheckedIOException [英] Catch UncheckedIOException in Java 8 stream
问题描述
编辑:这似乎不可能,请参阅 https://bugs.openjdk我有一个帮助类,它提供一个 Stream< Path> code>。该代码只包含
Files.walk
并对输出进行排序:
public流<路径> getPaths(Path path){
return Files.walk(path,FOLLOW_LINKS).sorted();
}
随着符号链接的跟踪,如果文件系统中有循环(例如符号链接 x - >。
) Files.walk中使用的代码
抛出一个 UncheckedIOException
包装一个
FileSystemLoopException的实例
。
在我的代码中,我想捕获这样的异常,例如,只需记录一个有用的消息。我们尝试添加 .map(this :: catchException)
code>和 .peek(this :: catchException)
到我的代码,但在这个阶段没有被捕获。
路径checkException(路径路径){
try {
logger.info(path.toString(){},path.toString( ));
返回路径;
} catch(UncheckedIOException exception){
logger.error(YEAH);
返回null;
}
}
如果我能抓住一个 UncheckedIOException
在我的代码中发出一个 Stream< Path>
,以便路径的消费者不会遇到这种异常? / p>
例如,以下代码永远不会遇到异常:
列表与LT;路径> paths = getPaths()。collect(toList());
现在,异常由代码调用收集
(我可以在那里捕获异常):
java.io.UncheckedIOException:java.nio.file.FileSystemLoopException :/ tmp / junit5844257414812733938 / selfloop
在java.nio.file.FileTreeIterator.fetchNextIfNeeded(FileTreeIterator.java:88)
在java.nio.file.FileTreeIterator.hasNext(FileTreeIterator.java :104)
在java.util.Iterator.forEachRemaining(Iterator.java:115)
在java.util.Spliterators $ IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
在java。 util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
在java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
在java.util.stream.ReduceOps $ ReduceOp。 evaluateSequential(ReduceOps.java:708)
在java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
在java.util.stream.ReferencePi peline.collect(ReferencePipeline.java:499)
at ...
编辑:我提供了一个简单的JUnit测试类。在这个问题中,我要求您通过修改 provideStream
中的代码来修复测试。
code> package某处;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.nio.file.FileVisitOption.FOLLOW_LINKS;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.fail;
public class StreamTest {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
public void test()throws异常{
Path rootPath = Paths.get(temporaryFolder.getRoot()。getPath());
createSelfloop();
流<路径> stream = provideStream(rootPath);
assertThat(stream.collect(Collectors.toList()),是(not(nullValue())));
}
私人流<路径> submitStream(Path rootPath)throws IOException {
return Files.walk(rootPath,FOLLOW_LINKS).sorted();
}
private void createSelfloop()throws IOException {
String root = temporaryFolder.getRoot()。getPath();
try {
Path symlink = Paths.get(root,selfloop);
Path target = Paths.get(root);
Files.createSymbolicLink(符号链接,目标);
} catch(UnsupportedOperationException x){
//某些文件系统不支持符号链接
fail();
}
}
}
您可以制作自己的步行流工厂:
public class FileTree {
public static Stream< Path> ; walk(Path p){
Stream< Path> S = Stream.of(P);
if(Files.isDirectory(p))try {
DirectoryStream< Path> ds = Files.newDirectoryStream(p);
s = Stream.concat(s,StreamSupport.stream(ds.spliterator(),false)
.flatMap(FileTree :: walk)
.onClose(() - > {try { ds.close();} catch(IOException ex){}}));
} catch(IOException ex){}
return s;
}
//如果您不想静默忽略excepr
public static Stream< Path> walk(Path p,BiConsumer< Path,IOException> handler){
Stream< Path> S = Stream.of(P);
if(Files.isDirectory(p))try {
DirectoryStream< Path> ds = Files.newDirectoryStream(p);
s = Stream.concat(s,StreamSupport.stream(ds.spliterator(),false)
.flatMap(sub - > walk(sub,handler))
.onClose(() - > {try {ds.close();}
catch(IOException ex){handler.accept(p,ex);}}));
} catch(IOException ex){handler.accept(p,ex); }
return s;
}
//和深度限制
public static Stream< Path> walk(
Path p,int maxDepth,BiConsumer< Path,IOException> handler){
Stream< Path> S = Stream.of(P);
if(maxDepth> 0&& Files.isDirectory(p))try {
DirectoryStream< Path> ds = Files.newDirectoryStream(p);
s = Stream.concat(s,StreamSupport.stream(ds.spliterator(),false)
.flatMap(sub - > walk(sub,maxDepth-1,handler))
。 onClose(() - > {try {ds.close();}
catch(IOException ex){handler.accept(p,ex);}}));
} catch(IOException ex){handler.accept(p,ex); }
return s;
}
}
EDIT: This does not seem to be possible, see https://bugs.openjdk.java.net/browse/JDK-8039910.
I have a helper class that provides a Stream<Path>
. This code just wraps Files.walk
and sorts the output:
public Stream<Path> getPaths(Path path) {
return Files.walk(path, FOLLOW_LINKS).sorted();
}
As symlinks are followed, in case of loops in the filesystem (e.g. a symlink x -> .
) the code used in Files.walk
throws an UncheckedIOException
wrapping an instance of FileSystemLoopException
.
In my code I would like to catch such exceptions and, for example, just log a helpful message. The resulting stream could/should just stop providing entries as soon as this happens.
I tried adding .map(this::catchException)
and .peek(this::catchException)
to my code, but the exception is not caught in this stage.
Path checkException(Path path) {
try {
logger.info("path.toString() {}", path.toString());
return path;
} catch (UncheckedIOException exception) {
logger.error("YEAH");
return null;
}
}
How, if at all, can I catch an UncheckedIOException
in my code giving out a Stream<Path>
, so that consumers of the path do not encounter this exception?
As an example, the following code should never encounter the exception:
List<Path> paths = getPaths().collect(toList());
Right now, the exception is triggered by code invoking collect
(and I could catch the exception there):
java.io.UncheckedIOException: java.nio.file.FileSystemLoopException: /tmp/junit5844257414812733938/selfloop
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.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at ...
EDIT: I provided a simple JUnit test class. In this question I ask you to fix the test by just modifying the code in provideStream
.
package somewhere;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.nio.file.FileVisitOption.FOLLOW_LINKS;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.fail;
public class StreamTest {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
public void test() throws Exception {
Path rootPath = Paths.get(temporaryFolder.getRoot().getPath());
createSelfloop();
Stream<Path> stream = provideStream(rootPath);
assertThat(stream.collect(Collectors.toList()), is(not(nullValue())));
}
private Stream<Path> provideStream(Path rootPath) throws IOException {
return Files.walk(rootPath, FOLLOW_LINKS).sorted();
}
private void createSelfloop() throws IOException {
String root = temporaryFolder.getRoot().getPath();
try {
Path symlink = Paths.get(root, "selfloop");
Path target = Paths.get(root);
Files.createSymbolicLink(symlink, target);
} catch (UnsupportedOperationException x) {
// Some file systems do not support symbolic links
fail();
}
}
}
You can make your own walking stream factory:
public class FileTree {
public static Stream<Path> walk(Path p) {
Stream<Path> s=Stream.of(p);
if(Files.isDirectory(p)) try {
DirectoryStream<Path> ds = Files.newDirectoryStream(p);
s=Stream.concat(s, StreamSupport.stream(ds.spliterator(), false)
.flatMap(FileTree::walk)
.onClose(()->{ try { ds.close(); } catch(IOException ex) {} }));
} catch(IOException ex) {}
return s;
}
// in case you don’t want to ignore exceprions silently
public static Stream<Path> walk(Path p, BiConsumer<Path,IOException> handler) {
Stream<Path> s=Stream.of(p);
if(Files.isDirectory(p)) try {
DirectoryStream<Path> ds = Files.newDirectoryStream(p);
s=Stream.concat(s, StreamSupport.stream(ds.spliterator(), false)
.flatMap(sub -> walk(sub, handler))
.onClose(()->{ try { ds.close(); }
catch(IOException ex) { handler.accept(p, ex); } }));
} catch(IOException ex) { handler.accept(p, ex); }
return s;
}
// and with depth limit
public static Stream<Path> walk(
Path p, int maxDepth, BiConsumer<Path,IOException> handler) {
Stream<Path> s=Stream.of(p);
if(maxDepth>0 && Files.isDirectory(p)) try {
DirectoryStream<Path> ds = Files.newDirectoryStream(p);
s=Stream.concat(s, StreamSupport.stream(ds.spliterator(), false)
.flatMap(sub -> walk(sub, maxDepth-1, handler))
.onClose(()->{ try { ds.close(); }
catch(IOException ex) { handler.accept(p, ex); } }));
} catch(IOException ex) { handler.accept(p, ex); }
return s;
}
}
这篇关于在Java 8流中捕获UncheckedIOException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!