5

Interfejs Stream ma dwa przeciążenia dla metody of(). Jednym z nich jest metoda zmiennej arytmetycznej, podczas gdy druga przyjmuje pojedynczy argument.Dlaczego przeładować metodę varargs() w interfejsie Java Stream?

Czy metoda pojedynczej argumentacji jest optymalizacją wydajności w porównaniu z przekazywaniem jednego argumentu do metody zmiennej-arytmu? Jeśli tak, w jaki sposób poprawia wydajność? Te same pytania można zadać w metodzie empty(), która wydaje się być cukrem składającym się z arii zmiennych of().

Widzę, że implementacja różni się między tymi metodami, z tą różnicą, że powstaje instancja Spliterator; ale co to za korzyść oferuje interfejs API Stream?

Odpowiedz

5

Tak, jest to optymalizacja, aby uniknąć narzutu tworzenia tablicy do przechowywania tylko jednego elementu, co można uzyskać, jeśli użyjesz wersji varargs.

te same pytania można zadać metody pustego(), która wydaje się być cukier składnia wokół zmiennej liczbę operandów() wersji

Co realizacji gapisz? Kiedy patrzę na implementację, nie widzę tego.

+0

Miałem na myśli tylko to, że sygnatury metody zdają się wskazywać na cukier składniowy (a dokumentacja nie wskazuje w ten czy w inny sposób). Widzę, że implementacje są różne. – jaco0646

+0

Unikanie pojedynczego elementu lub pustej tablicy wydaje się być mikro-optymalizacją. Czy jest to rzecz, o którą powinien się martwić przeciętny programista? Czy powinienem zapewnić tego rodzaju optymalizację wydajności dla wszystkich moich metod varargs? – jaco0646

+1

@ jaco0646, co jest nie tak z składni cukru? Zwłaszcza, jeśli oferuje również możliwości optymalizacji wydajności. –

5

Strumień pusty i strumień pojedynczego elementu są bardzo częstym przypadkiem użycia, szczególnie w przypadku korzystania z urządzenia .flatMap(). Na przykład, oto jak Optional.stream() jest implemented w Javie-9:

public Stream<T> stream() { 
    if (!isPresent()) { 
     return Stream.empty(); 
    } else { 
     return Stream.of(value); 
    } 
} 

Więc biorąc pod uwagę strumień opcjonalne można rozpakować je do płaskiego strumienia w ten sposób:

streamOfOptionals.flatMap(Optional::stream); 

Tutaj można stworzyć mnóstwo pusty zarówno strumieni, jak i strumieni pojedynczych elementów, więc optymalizacja takich przypadków wygląda bardzo rozsądnie. W szczególności, Stream.empty() w przeciwieństwie do Stream.of() nie tworzy pustej tablicy i nie tworzy spliteratora (ponownie używa tej samej instancji dzielnika). Stream.of(T) jest również szczególnie zoptymalizowany wewnątrz StreamBuilderImpl, więc żadna tablica nie jest przydzielona dla pojedynczego elementu.

1

Natknąłem się na oficjalny zasób, który potwierdza poprzednie odpowiedzi na to pytanie: JEP 269: Convenience Factory Methods for Collections. Opis tej propozycji jest,

Zapewnić statyczne metody fabryki na List, Set i Map interfejsów do tworzenia żadnych modyfikacji wystąpień tych zbiorów.

Obejmują one przeciążenia varargs, więc nie ma ustalonego limitu rozmiaru kolekcji ... Zostaną zapewnione interfejsy API dla specjalnych przypadków (stałe przeciążenia) dla maksymalnie dziesięciu elementów. Chociaż wprowadza to pewne zamieszanie w interfejsie API, unika alokacji tablicy, inicjalizacji i narzutów związanych ze zbieraniem pamięci, które są wywoływane przez wywołania varargs.

Optymalizacja wydajności polega więc po prostu na uniknięciu układu metody varargs.