2015-03-03 12 views
6

Piszę mały program do generowania liczb losowych i chciał uzyskać informacje statystyczne na ich temat. Mam List<AtomicInteger>, który chcę użyć do wysyłania niektórych informacji.Błąd kompilatora Java 8 ze strumieniem i redukcja

Próbowałem za pomocą następującego kodu, aby ograniczyć listę do jej łącznej liczby (np sumę wartości wszystkich AtomicIntegers):

// not my real initialization code, just for illustration purposes 
List<AtomicInteger> values = new ArrayList<>(); 
for(int i = 0; i < 10; i++) { 
    values.add(new AtomicInteger()); 
} 

// this is the problematic reduce 
int total = values 
    .parallelStream() 
    .reduce(0, 
     (currentValue, currentAtomic) 
      -> currentValue + currentAtomic.get(), 
     (combiner1, combiner2) -> combiner1 + combiner2); 

Mój IDE (IntelliJ) nie ma problemów z tej linii w ogóle, ale z mojego obecnego javac wersji (1.8.0_31) linia ta skutkuje NullPointerException w kompilatora:

An exception has occurred in the compiler (1.8.0_31). Please file a bug at the Java Developer Connection (http://java.sun.com/webapps/bugreport) after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report. Thank you. 
java.lang.NullPointerException 
    at com.sun.tools.javac.code.Types.isConvertible(Types.java:290) 
    at com.sun.tools.javac.comp.Check.assertConvertible(Check.java:922) 
    at com.sun.tools.javac.comp.Check.checkMethod(Check.java:876) 
    at com.sun.tools.javac.comp.Attr.checkMethod(Attr.java:3838) 
    at com.sun.tools.javac.comp.Attr.checkIdInternal(Attr.java:3615) 
    at com.sun.tools.javac.comp.Attr.checkMethodIdInternal(Attr.java:3522) 
    at com.sun.tools.javac.comp.Attr.checkMethodId(Attr.java:3501) 
    at com.sun.tools.javac.comp.Attr.checkId(Attr.java:3488) 
    at com.sun.tools.javac.comp.Attr.visitSelect(Attr.java:3370) 
    at com.sun.tools.javac.tree.JCTree$JCFieldAccess.accept(JCTree.java:1897) 
    at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:607) 
    at com.sun.tools.javac.comp.Attr.visitApply(Attr.java:1843) 
    at com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1465) 
    at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:607) 
    at com.sun.tools.javac.comp.Attr.attribExpr(Attr.java:649) 
    at com.sun.tools.javac.comp.Attr.visitVarDef(Attr.java:1093) 
    at com.sun.tools.javac.tree.JCTree$JCVariableDecl.accept(JCTree.java:852) 
    at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:607) 
    at com.sun.tools.javac.comp.Attr.attribStat(Attr.java:676) 
    at com.sun.tools.javac.comp.Attr.attribStats(Attr.java:692) 
    at com.sun.tools.javac.comp.Attr.visitBlock(Attr.java:1142) 
    at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:909) 
    at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:607) 
    at com.sun.tools.javac.comp.Attr.attribStat(Attr.java:676) 
    at com.sun.tools.javac.comp.Attr.visitMethodDef(Attr.java:1035) 
    at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:778) 
    at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:607) 
    at com.sun.tools.javac.comp.Attr.attribStat(Attr.java:676) 
    at com.sun.tools.javac.comp.Attr.attribClassBody(Attr.java:4342) 
    at com.sun.tools.javac.comp.Attr.attribClass(Attr.java:4252) 
    at com.sun.tools.javac.comp.Attr.attribClass(Attr.java:4181) 
    at com.sun.tools.javac.comp.Attr.attrib(Attr.java:4156) 
    at com.sun.tools.javac.main.JavaCompiler.attribute(JavaCompiler.java:1248) 
    at com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:901) 
    at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:860) 
    at com.sun.tools.javac.main.Main.compile(Main.java:523) 
    at com.sun.tools.javac.main.Main.compile(Main.java:381) 
    at com.sun.tools.javac.main.Main.compile(Main.java:370) 
    at com.sun.tools.javac.main.Main.compile(Main.java:361) 
    at com.sun.tools.javac.Main.compile(Main.java:56) 
    at com.sun.tools.javac.Main.main(Main.java:42) 

wiem, że prawdopodobnie istnieją inne sposoby, aby osiągnąć ten sam zmniejszyć, ale naprawdę chciałbym zachować równolegle charakter strumienia (sinc Mój oryginalny kod ma wiele wartości). Czy ktoś może zaproponować mi inną opcję równoległego zmniejszenia, która nie spowoduje awarii mojego kompilatora i może osiągnąć ten sam wynik?

Chciałbym również wiedzieć, czy jest to problem, który napotykam, lub czy inne osoby mogą odtworzyć ten błąd kompilatora.

+0

potwierdzone javac 1.8.0_31. –

+4

Tak, również potwierdziłem javac 1.8.0_31, Znalazłeś błąd i powinieneś go zgłosić. – shazin

+1

Mimo to może być duplikatem https://bugs.openjdk.java.net/browse/JDK-8068398 lub https://bugs.openjdk.java.net/browse/JDK-8046357 lub https: //bugs.openjdk .java.net/browse/JDK-8072751 – Marco13

Odpowiedz

3

Alternatywnie, zamiast korzystania reduce, można użyć mapToInt i sum:

int total = values.stream().mapToInt(AtomicInteger::get).sum(); 
1

wersji, która nie psuje kompilatora:

// not my real initialization code, just for illustration purposes 
     List<AtomicInteger> values = new ArrayList<>(); 
     for(int i = 0; i < 10; i++) { 
      values.add(new AtomicInteger()); 
     } 

// this is the problematic reduce 
     BiFunction<Integer, AtomicInteger, Integer> accumulator = 
       (currentValue, currentAtomic) -> currentValue + currentAtomic.get(); 
     BinaryOperator<Integer> combiner = (combiner1, combiner2) -> combiner1 + combiner2; 
     int total = values 
       .parallelStream() 
       .reduce(0, accumulator, combiner); 
+2

Możesz usunąć kombinator i zastąpić go 'Integer.sum' przy pomocy odwołania do metody:' .reduce (0, akumulator, Integer :: sum); ' –

+0

Z jakiegoś powodu dzielenie go w ten sposób nie przyszło mi do głowy w ogóle. Dzięki! – mhlz

+3

@mhlz Dzielenie go nie jest konieczne, wystarczy, aby określić typy parametrów: '.reduce (0, \t \t (Integer CurrentValue, AtomicInteger currentAtomic) \t \t -> CurrentValue + currentAtomic.get(), \t \t Integer :: sum) 'działa również. –

Powiązane problemy