2014-12-02 64 views
0

我有以下代码在一个流中做不同的事情。IllegalStateException与StreamSupplier

private void getBuildInformation(Stream<String> lines) 
    { 
    Supplier<Stream<String>> streamSupplier =() -> lines; 

    String buildNumber = null; 
    String scmRevision = null; 
    String timestamp = null; 
    String buildTag = null; 

     Optional<String> hasBuildNumber = streamSupplier.get().filter(s -> s.contains(LogProps.PLM_BUILD)).findFirst(); 
     if (hasBuildNumber.isPresent()) 
     { 
     buildNumber = hasBuildNumber.get(); 
     String[] temp = buildNumber.split("="); 
     if (temp.length >= 2) 
      buildNumber = temp[1].trim(); 
     } 

     Optional<String> hasSCMRevision = streamSupplier.get().filter(s -> s.contains(LogProps.SCM_REVISION_50)).findFirst(); 
     if (hasSCMRevision.isPresent()) 
     { 
     scmRevision = hasSCMRevision.get(); 
     String[] temp = scmRevision.split(":"); 
     if (temp.length >= 4) 
      scmRevision = temp[3].trim(); 
     } 

     Optional<String> hasBuildTag = streamSupplier.get().filter(s -> s.contains(LogProps.BUILD_TAG_50)).findFirst(); 
     if (hasBuildTag.isPresent()) 
     { 
     buildTag = hasBuildTag.get(); 
     String[] temp = buildTag.split(":"); 
     if (temp.length >= 4) 
      buildTag = temp[3].trim(); 
     } 

     Optional<String> hasTimestamp = streamSupplier.get().filter(s -> s.contains(LogProps.BUILD_TIMESTAMP_50)).findFirst(); 
     if (hasTimestamp.isPresent()) 
     { 
     timestamp = hasTimestamp.get(); 
     String[] temp = timestamp.split(":"); 
     if (temp.length >= 4) 
      timestamp = temp[3].trim(); 
     } 
} 

现在的问题是,如果我第一时间致电

Optional<String> hasBuildNumber = streamSupplier.get().filter(s -> s.contains(LogProps.PLM_BUILD)).findFirst();

它工作正常,但如果我叫下一个

Optional<String> hasSCMRevision = streamSupplier.get().filter(s -> s.contains(LogProps.SCM_REVISION_50)).findFirst();

我得到的以下例外:

Exception in thread "Thread-21" java.lang.IllegalStateException: stream has already been operated upon or closed 
    at java.util.stream.AbstractPipeline.<init>(AbstractPipeline.java:203) 
    at java.util.stream.ReferencePipeline.<init>(ReferencePipeline.java:94) 
    at java.util.stream.ReferencePipeline$StatelessOp.<init>(ReferencePipeline.java:618) 
    at java.util.stream.ReferencePipeline$2.<init>(ReferencePipeline.java:163) 
    at java.util.stream.ReferencePipeline.filter(ReferencePipeline.java:162) 
    at com.dscsag.dscxps.model.analysis.Analysis.getECTRBuildInformation(Analysis.java:205) 
    at com.dscsag.dscxps.model.analysis.Analysis.parseLogFile(Analysis.java:153) 
    at com.dscsag.dscxps.model.analysis.Analysis.analyze(Analysis.java:135) 
    at com.dscsag.dscxps.model.XPSModel.lambda$startAnalysis$0(XPSModel.java:467) 
    at com.dscsag.dscxps.model.XPSModel$$Lambda$1/12538894.run(Unknown Source) 
    at java.lang.Thread.run(Thread.java:745) 

因为我读了这个页面http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/我认为它应该工作,导致供应商提供新的流get()

回答

4

如果您将供应商重新编写为匿名的pre-java 8类。这将相当于:

Supplier<Stream<String>> streamSupplier = new Supplier<Stream<String>>() { 
    @Override 
    public Stream<String> get() { 
     return lines; 
    } 
}; 

也许在这里变得更加明显,你的每一个你对你的供应商叫get时间返回相同的流实例(因而扔在了第二个电话,因为findFirst的例外是一个short-circuiting terminal operation )。你没有返回一个全新的Stream。

在您给出的网页示例中,作者使用Stream.of,每调用一次get就会创建一个全新的Stream,这就是它工作的原因。

AFAIK无法从现有流复制流。因此,一种解决方法是传递Stream所来的对象,然后在供应商处获取Stream。

public class Test { 
    public static void main(String[] args) {  
     getBuildInformation(Arrays.asList("TEST", "test")); 
    } 
    private static void getBuildInformation(List<String> lines) { 
     Supplier<Stream<String>> streamSupplier =() -> lines.stream(); 

     Optional<String> hasBuildNumber = streamSupplier.get().filter(s -> s.contains("t")).findFirst(); 
     System.out.println(hasBuildNumber); 

     Optional<String> hasSCMRevision = streamSupplier.get().filter(s -> s.contains("T")).findFirst(); 
     System.out.println(hasSCMRevision); 

    } 
} 

哪个输出:

Optional[test] 
Optional[TEST] 

既然你从一个Path对象的线条,处理的供应商除外本身可以来相当难看,你可以这样做,什么是创建一个辅助方法将处理异常捕捉,那么它会是这样的:

private static void getBuildInformation(Path path) { 
    Supplier<Stream<String>> streamSupplier =() -> lines(path); 
    //do your stuff 
} 
private static Stream<String> lines(Path path) { 
    try { 
     return Files.lines(path); 
    } 
    catch (IOException e) { 
     throw new UncheckedIOException(e); 
    } 
} 
+0

另一个问题是,该行填充Files.lines(...)。那么如何用这个来实现呢? – 2014-12-02 11:24:47

+1

@MarcelHöll您可以将'Path'对象传递给您的方法并执行'() - > Files.lines(path);' – 2014-12-02 11:30:34

+1

@MarcelHöll请参阅我的编辑。 – 2014-12-02 11:45:20