2010-09-17 19 views
38

Właśnie patrzyłem na Guva ImmutableList i zauważyłem, że metoda of() została przeciążona 12 razy.Dlaczego ImmutableList Guava ma tak wiele przeciążonych metod()?

Wydaje mi się, że wszystko, co potrzebne było:

static <E> ImmutableList<E> of(); 
static <E> ImmutableList<E> of(E element); // not even necessary 
static <E> ImmutableList<E> of(E... elements); 

Co jest powodem, dla którego tak wiele podobnych odmian?

+5

Wszystkie one przekazują swoje parametry do wewnętrznej metody varargs tak czy inaczej ... huh. Będę musiał podnieść brew na tę. Hmm, źródło ma komentarz "Te idą do jedenastej, po czym dostajesz formę varargs i wszelkie ostrzeżenia mogą się z tym równać. :(" Nie jestem pewien, do czego odnoszą się ostrzeżenia. –

+0

@Tim, to pewnie by dobra odpowiedź, przynajmniej warta i przegłosowana, i prawdopodobnie zaakceptowana odpowiedź: – jjnguy

+7

+1 dla Google za przejście do jedenastu! – romacafe

Odpowiedz

39

Varargs i generics nie grają ładnie razem. Metody Varargs mogą generować ostrzeżenia z ogólnymi argumentami, a przeciążenia zapobiegają temu ostrzeżeniu, z wyjątkiem rzadkiego przypadku, gdy chcesz dodać więcej niż 11 elementów do niezmiennej listy przy użyciu of().

Komentarze w źródła mówią:

one wzrosnąć do jedenastej. Następnie otrzymujesz formularz varargs i wszelkie ostrzeżenia mogą się z nim wiązać. :(

Zauważ, że Java 7 jest @SafeVarargs adnotacja dodano specjalnie, aby wyeliminować potrzebę tego rodzaju rzeczy. Jeden of(E...) metoda opatrzone @SafeVarargs mogą być wykorzystane i nie dać ostrzeżenia o ogólnych argumentów.

+0

Hej, czy możesz potencjalnie zaktualizować swoją odpowiedź, aby odzwierciedlić część wydajności, do której odnosi się @Rinke? Myślę, że warto o tym wspomnieć. –

+2

@ JoãoRebelo: To nie jest prawda, ale ... metody natychmiast idą i wywołują samą metodę varargs. – ColinD

+0

Masz na myśli w tym konkretnym przypadku? Albo nie rozumiem, co miałeś na myśli? –

13

Istnieje również przyczyna wydajności Każda inwokacja metody varargs powoduje alokację tablicy i inicjalizację Jeśli w jakiś sposób ustalono, że np. 95% wywołań ma 3 lub mniej argumentów, a tylko 5% z 4 lub więcej, to przeciążanie w ten sposób

public static <E> ImmutableList<E> of(); 
public static <E> ImmutableList<E> of(E e); 
public static <E> ImmutableList<E> of(E e1, E e2); 
public static <E> ImmutableList<E> of(E e1, E e2, E e3); 
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E... es); 

prowadzi do miłego zwiększenia wydajności w 95% przypadków. Inaczej mówiąc, średnia wydajność przypadku wzrasta.

+6

Uwaga: Chociaż zasada obowiązuje, właśnie dowiedziałem się od ColinD, że to nie jest prawdą w przypadku Guava, ponieważ przeciążone metody powodują mimo to wywołanie varargs (w obecnej implementacji). – Rinke

4

Oprócz innych świetnych odpowiedzi, istnieje tutaj subtelna przewaga wydajności (oprócz unikania alokacji tablicy), co oznacza, że ​​przeciążenia zera-arg i pojedynczego-arg zwracają implementacje zoptymalizowane do reprezentowania pustych i listy pojedynczych instancji (odpowiednio).

Gdybyśmy nie mają oddzielne przeciążeń metoda te i obejmowała tylko jeden sposób na varargs oparte, to metoda będzie wyglądać mniej więcej tak:

public static <E> ImmutableList<E> of(E... es) { 
    switch (es.length) { 
     case 0: 
     return emptyImmutableList(); 
     case 1: 
     return singletonImmutableList(es[0]); 
     default: 
     return defaultImmutableList(es); 
    } 
} 

wykonywaniu przypadku przełącznika (lub jeśli -else checks) nie byłoby złe dla większości wywołań, ale wciąż jest niepotrzebne, ponieważ może mieć przeciążenie metody dla każdej optymalizacji, a kompilator zawsze wie, które przeciążenie wywołać. Nie ma żadnego obciążenia na kod klienta, więc łatwo wygrać.

Powiązane problemy