在Java 8流中捕获UncheckedIOException [英] Catch UncheckedIOException in Java 8 stream

查看:1203
本文介绍了在Java 8流中捕获UncheckedIOException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑:这似乎不可能,请参阅 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆