2014-12-02 7 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, которые создают новый Stream каждый раз, когда вызывается get, поэтому он работает.

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 (...). Итак, как добиться этого с этим? –

+1

@ MarcelHöll Вы можете передать объект 'Path' вашему методу и сделать'() -> Files.lines (path); ' –

+1

@ MarcelHöll См. Мое редактирование. –

Смежные вопросы