2017-07-25 10 views
6

Poniższy kod:Argument Niezgodność przy użyciu metody gromadzący Stream

names = Arrays.asList("A","B","C").stream(); 
List<String> namesAsList = names.collect(() -> new ArrayList<String>(),List::add,List::add); 
System.out.println("Individual Strings put into a list: " + namesAsList); 

generuje następujący błąd podczas kompilacji:

Lista namesAsList = names.collect (() -> new ArrayList ( ), Lista :: dodaj, Lista :: dodaj); ^ (niedopasowanie argumentu, nieprawidłowe odwołanie do metody niekompatybilne typy: ArrayList nie może być konwertowane na int) gdzie R, T są zmiennymi typu: R extends Obiekt zadeklarowany w metodzie collect (Dostawca, biConsumer, BiConsumer) T extends Obiekt zadeklarowany w interfejsie strumień 1 błąd

Kiedy zmienić kod, aby usunąć rodzajowy kod kompiluje z niesprawdzony ostrzeżenie wyrażenie:

Stream<String> names = Arrays.asList("A","B","C").stream(); 
List<String> namesAsList = names.collect(() -> new ArrayList(),List::add,List::add); 
System.out.println("Individual Strings put into a list: " + namesAsList); 

Dlaczego miałbym być ten błąd? Nie oczekuję, że problem będzie dotyczył int.

Jeśli odpowiedź może obejmować sposób ustalenia problemu, będzie to docenione, więc mogę się nauczyć sam rozwiązywać te problemy.

+3

Nawiasem mówiąc, możesz użyć 'Stream.of (" A "," B "," C ")' do utworzenia strumienia adrech trzech elementów. – Holger

+0

Dzięki za komentarz. Ćwiczę do egzaminu Java 8, więc używam różnych sposobów tworzenia obiektu strumienia w moim kodzie ćwiczebnym. –

Odpowiedz

7

Numer referencyjny metody przekazany dla combiner nie pasuje. Spróbuj:

List<String> namesAsList = names 
    .collect(ArrayList::new, List::add, List::addAll); 

Zdałeś List::add kompilator i dokłada wszelkich starań, aby spróbować zinterpretować go jako przykład łączącego z BiConsumer typu. W związku z tym dziwny błąd niedopasowania argumentu.


Zakładam również, że wdrażasz to tylko w celach badawczych. Jeśli chcesz zbierać Stream do List, można po prostu użyć:

.collect(Collectors.toList()); 

Jeśli chcesz zbierać Stream do ArrayList konkretnie, można przejść do:

.collect(Collectors.toCollection(ArrayList::new)); 
+0

Dlaczego nie po prostu zbierać za pomocą 'Collectors.toList()'? – xenteros

+0

@xenteros Zakładam, że OP stara się nauczyć, jak wdrażać własnych kolekcjonerów. Pytanie dotyczyło problemu kompilacji, a nie wyprowadzania listy ze strumienia. –

+3

Nadal można użyć 'List :: add' i' List :: addAll', a następnie instrukcja nadal pasuje do pojedynczej linii ;-) – Holger

6

Problem jest w combiner, konkretnie: List::add powinien naprawdę być List::addAll.

Albo bardziej czytelne tak:

List<String> namesAsList = names.collect(
      () -> new ArrayList<>(), 
      List::add, 
      List::addAll); 

Można ponownie napisać, że z wyrażenia lambda, gdy jesteś un pewien btw:

List<String> namesAsList = names.collect(
      () -> new ArrayList<>(), 
      List::add, 
      (List<String> left, List<String> right) -> { 
       left.addAll(right); 
      }); 

zauważyć, że istnieją inne problemy jak-dobrze , jak () -> new ArrayList<String>(), typ zostanie wywnioskowany przez kompilator tutaj, więc nie ma potrzeby dla <String>, jak to: () -> new ArrayList<>().Również może to być przekształcone do odniesienia metoda też: ArrayList::new, więc ostatecznie będzie to jeszcze prostsze:

List<String> namesAsList = names.collect(
      ArrayList::new, 
      List::add, 
      List::addAll); 

Ten btw to samo, że Collectors.toList robi wewnętrznie, więc jeszcze to można uprościć do:

List<String> namesAsList = names.collect(Collectors.toList()); 

jedynym problemem jest to, że specyfikacja może zmieniać że (przesyła wszystkie inneList oprócz ArrayList), a więc może być napisane:

List<String> namesAsList = names.collect(Collectors.toCollection(ArrayList::new)); 
+0

ArrayList :: new jeśli używasz metody refrenów – LazerBanana

+0

@LazerBanana obie opcje są w porządku –

+2

@pivovarit są one ale nie są spójne;) – LazerBanana

Powiązane problemy