2016-09-18 81 views
2

編輯:這似乎不可能,請參閱https://bugs.openjdk.java.net/browse/JDK-8039910在Java 8流中捕獲UncheckedIOException

我有一個幫助類,它提供了一個Stream<Path>。此代碼只是包裝Files.walk和排序輸出:

public Stream<Path> getPaths(Path path) { 
    return Files.walk(path, FOLLOW_LINKS).sorted(); 
} 

作爲符號鏈接,接着,在文件系統(例如一個符號鏈接x -> .)在Files.walk使用的代碼循環的情況下,將引發UncheckedIOException包裹的FileSystemLoopException一個實例。

在我的代碼中,我想捕獲這些異常,例如,只記錄一條有用的消息。生成的流可能/應該只是在發生這種情況時立即停止提供條目。

我試着將.map(this::catchException).peek(this::catchException)添加到我的代碼中,但是在這個階段沒有發現異常。

Path checkException(Path path) { 
    try { 
     logger.info("path.toString() {}", path.toString()); 
     return path; 
    } catch (UncheckedIOException exception) { 
     logger.error("YEAH"); 
     return null; 
    } 
} 

如何,如果在所有我能趕上在我的代碼的UncheckedIOException釋放出Stream<Path>,使路徑的消費者並沒有遇到這個異常?

作爲一個例子,下面的代碼不應該遇到異常:

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 ... 

List<Path> paths = getPaths().collect(toList()); 

眼下,異常是由代碼調用collect(我能趕上有例外)觸發


編輯:我提供了一個簡單的JUnit測試類。在這個問題中,我要求你通過修改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(); 
     } 
    } 
} 
+2

貌似重複,以http://stackoverflow.com/q/22867286/4856258。簡而言之:你無法使用'Files.walk'工作,你必須爲此編寫完全獨立的方法或使用第三方庫。 –

+0

我把這個方法放在completablefuture.suppltasync上,並添加excepcetionaly來捕獲異常? – gaston

+0

我不明白你在說什麼,@ gaston。 –

回答

1

你可以使自己的步行流工廠:

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; 
    } 
}