Jak zrozumieć tę metodę Collect () Java 8 Stream?

12

Próbowałem przekonwertować tablicę int na List i wybrałem nieznaną drogę korzystania z Java 8 Stream i wymyśliłem to

Arrays.stream(arr).boxed().collect(Collectors.toList());

Nadal mam trudności z pełnym zrozumieniem tej linii, głównie

  1. Dlaczego Collectors.toList()w tym przypadku zwraca interfejs ArrayList<Integer>implementujący List? Dlaczego nie LinkedList<Integer>lub inna ogólna klasa zgodna z Listinterfejsem? Nie mogę nic na ten temat znaleźć, oprócz krótkiej wzmianki o ArrayList tutaj , w sekcji Notatki API.

  2. Co oznacza lewy panel ? Oczywiście jest to ogólny typ zwrotu ( w moim kodzie tutaj). I myślę, że jest argumentem typu ogólnego w metodzie, ale jak są one określone? Przejrzałem dokument interfejsu Collectora i nie byłem w stanie go wchłonąć.wprowadź opis zdjęcia tutaj Stream.collect()RArrayList<Integer><R, A>

użytkownik3207158
źródło
2
1. Oczywiście używa prawdziwej listy pod maską. Jednak nierozsądne byłoby, gdyby interfejs API ujawniał rzeczywisty typ listy. Od tego czasu nigdy nie będą mogli zmienić wdrożenia w przyszłości. Zasadniczo często dobrym pomysłem jest ujawnianie tylko interfejsów, a nigdy rzeczywistego typu bazowego. 2. Rjest ogólnym typem typu wynikowego. Aogólny rodzaj pośredniego typu akumulacji kolektora. Jest to szczegół implementacji działania kolektora. Dzieląc i podbijając, również w przypadku przetwarzania równoległego, najpierw zbiera się w typy pośrednie.
Zabuzard
10
Prawie nigdy tak naprawdę nie chcesz LinkedList. Jest tweet Josha Blocha , który mówi: „Napisałem to i nigdy go nie używam”.
Andy Turner,
4
„Dlaczego Collectors.toList()w tym przypadku zwraca ArrayList<Integer> To może nie zwrócić ArrayList. ListRealizacja jest niezdefiniowane , więc nie można polegać na tym, co implementacja zwróci. Jak mówi javadoc : „Nie ma żadnych gwarancji co do typu , zmienności, możliwości serializacji lub bezpieczeństwa wątków zwróconej listy;”
Andreas,
3
i toList()nie zwraca ArrayListlub List- zwraca a Collector, który ostatecznie utworzy i zwróci a List- również dokumentacja stwierdza: „... Nie ma gwarancji co do typu , zmienności, możliwości serializacji lub bezpieczeństwa wątków zwróconej listy; jeśli wymagana jest większa kontrola nad zwróconą listą, użyj toCollection (dostawca) .... ”
user85421-Zbanowany
3
Zdecydowanie polecam dokumentację pakietu
Holger

Odpowiedzi:

18
  1. Jest to domyślna implementacja. ArrayListjest używany, ponieważ najlepiej sprawdza się w większości przypadków użycia, ale jeśli nie jest on odpowiedni dla Ciebie, zawsze możesz zdefiniować własny kolektor i dostarczyć fabrykę według własnego Collectionuznania:

    Arrays.stream(arr).boxed().collect(toCollection(LinkedList::new));
  2. Tak, Ai Rsą ogólnymi parametrami tej metody, Rjest to typ zwracany, Tjest typem wejściowym i Ajest typem pośrednim, który pojawia się w całym procesie gromadzenia elementów (może nie być widoczny i nie dotyczy tej funkcji). Początek Collectorjavadoc definiuje te typy (są one spójne w całym dokumencie):

    T - rodzaj elementów wejściowych do operacji redukcji
    A - zmienny typ akumulacji operacji redukcji (często ukryty jako szczegół implementacji)
    R - typ wyniku operacji redukcji

Andronikus
źródło
Dobra, widzę. Chyba powinienem naprawdę trzymać się List<Integer> myList = Arrays.stream(arr).boxed().collect(Collectors.toList());i wywoływać tylko metody zadeklarowane w interfejsie List na myList. W przeciwnym razie potencjalnie naraziłbym się na ryzyko, jeśli Oracle zdecyduje się zmienić domyślną implementację w Javie8u1024 lub 15?
user3207158,
2
@ user3207158 metoda zwraca a List, więc niezależnie od zastosowanej implementacji zachowanie jest takie samo. Jest mało prawdopodobne, że interfejs zostanie zmieniony w nowszych wersjach Java.
Andronicus,
1
  1. Dlaczego Collectors.toList () w tym przypadku zwraca ArrayList implementujący interfejs List?

Jak sugeruje definicja metody, zwraca implementację Collectora z dostawcą collector as ArrayList. Dlatego bardzo wyraźnie wynika z poniższej definicji metody, która Collectors.toListzawsze zwraca ArrayList collector ( While it's arguable why toList not toArrayList word is used in method name).

public static <T>
    Collector<T, ?, List<T>> toList() {
        return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                                   (left, right) -> { left.addAll(right); return left; },
                                   CH_ID);
    }
  1. Co robi lewy panel <R, A> R collect(Collector<? super T, A, R> collector) środków

Jeśli odwołujesz się do komentarzy do dokumentacji, dokładnie wspomina, jakie są te typy ogólne:

/*
      @param <R> the type of the result
      @param <A> the intermediate accumulation type of the {@code Collector}
      @param collector the {@code Collector} describing the reduction
      @return the result of the reduction
*/
 <R, A> R collect(Collector<? super T, A, R> collector);
Vinay Prajapati
źródło
Dziękuję Panu. Skąd masz kod źródłowy Collectors.toList()(pierwszy fragment)? Czy to jest openjdk?
user3207158
1
Nie! Pobrałem kod źródłowy z mojego intelli j
Vinay Prajapati