2017-10-10 80 views
6

Następujący kodbłędu podczas zbierania IntStream mapowania

String[] values = ... 
.... 
Map<String, Object> map = new HashMap<>(); 
for (int i = 0; i < values.length; i++) { 
    map.put("X" + i, values[i]); 
} 

jest przekształcany przez IntelliJ do:

Map<String, Object> map = IntStream.range(0, values.length) 
     .collect(Collectors.toMap(
       i -> "X" + i, 
       i -> values[i], 
       (a, b) -> b)); 

, które mogą być skrócone, aby

Map<String, Object> map = IntStream.range(0, values.length) 
      .collect(Collectors.toMap(
        i -> "X" + i, 
        i -> values[i])); 

od 2 wersjach strumienia don” t skompilować.

IntelliJ, sugeruje, że istnieje problem z I w wartości [i]:

Incompatible types.
Required: int
Found: java.lang.Object

Kompilator skarży się:

Error:(35, 17) java: method collect in interface java.util.stream.IntStream cannot be applied to given types;
required: java.util.function.Supplier,java.util.function.ObjIntConsumer,java.util.function.BiConsumer
found: java.util.stream.Collector>
reason: cannot infer type-variable(s) R
(actual and formal argument lists differ in length)

może ktoś wyjaśnić dlaczego?

+0

co jest 'wartości ", czy mógłbyś dołączyć także swoją deklarację? Również na sugestię IntelliJ, wydaje się niespójne. Wystarczy wydrukować instrukcję 'map' między deklaracją a pętlą. To nie sugeruje już, abyś * zastąpił kolekcją *. – nullpointer

+1

String [] values ​​= ... – msayag

+0

Wyobrażam sobie, że 'Collector's nie obsługuje prymitywów, i to może być powodem, dla którego lambdy są konwertowane na' Object', ponieważ 'boxed()' naprawia to. –

Odpowiedz

2

Niezbyt pewna, w jaki sposób będzie działać sugestia intelliJ, wydaje się niespójna. Wystarczy umieścić

System.out.print(map); 

oświadczenie między deklaracją i pętli, a następnie nie będzie sugerować ty Wymień collect dalej.


Podczas korzystania z IntStream#collect, kompilacja nie powiedzie się z powodu, że realizacja collect metody oczekuje trzech podanych argumentów jak widoczne w błąd, a także gdy

Collectors.toMap(i -> "X" + i, i -> values[i]) 

spowodowałaby tylko jednego argumentu typu Collector.


lepszy sposób przekształcić wyrażenie byłoby choć

  • użyć forEach

    Map<String, Object> map; 
    IntStream.range(0, values.length).forEach(i -> map.put("X" + i, values[i])); 
    
  • Albo użyć boxed() do konwersji IntStream do Stream<Integer> jak: -

    Map<String, Object> map = IntStream.range(0, values.length).boxed() 
          .collect(Collectors.toMap(i -> "X" + i, i -> values[i], (a, b) -> b)); 
    
  • Albo jak sugeruje @Holger można uniknąć stosując foreach i boks napowietrznych i modyfikować konstrukt aby skorzystać z IntStream.collect trzy-Arg wariantu jak: -

    Map<String, Object> map = IntStream.range(0, values.length) 
          .collect(HashMap::new, (m,i) -> m.put("X"+i,values[i]), Map::putAll); 
    
+0

Używałbym pierwszego. Drugi, z tym "zapakowanym", doprowadzi do zbyt wielu skrzynek i unboxów pomiędzy 'Integer' i int. – Shirkam

+0

Podczas gdy twoje rozwiązania są ważne, nie odpowiadają na moje pytanie: dlaczego go nie kompiluje? – msayag

+0

@msayag Edytowano. Uważał jednak dziennik za jednoznaczny. Z drugiej strony, używając boxed, konwertuje 'IntStream' na' Stream', a 'collect' jest przeciążone w tej klasie, aby zaakceptować przekazany przez ciebie' Collector'. – nullpointer