Jednym ze sposobów, aby odpowiedzieć na to pytanie byłoby odpowiedzieć „kiedy robi stałych stosować biblioteki Java instanceof
?"Jeśli przyjmiemy, że Guava jest przykładem dobrze zaprojektowanej biblioteki Java, możemy sprawdzić, gdzie jest używana instanceof
, aby zdecydować, kiedy jest to do przyjęcia.
Jeśli wyodrębnimy słoik kodu źródłowego Guawy i wyskoczymy, zobaczymy instanceof
jest wymieniony 439 razy, przez 122 plików:
$ pwd
/tmp/guava-13.0.1-sources
$ grep -R 'instanceof' | wc -l
439
$ grep -Rl 'instanceof' | wc -l
122
I patrząc na niektóre z tych przypadków możemy zobaczyć kilka wzorów wyłaniają:
Aby sprawdzić równość
Jest to najczęściej używane. Jest to w pewnym stopniu zależne od implementacji, ale zakładając, że faktycznie chcesz zmierzyć równość w oparciu o klasę/interfejs, który rozszerza/implementuje, możesz użyć instanceof
, aby zapewnić obiekt, z którym pracujesz. Jednak może to potencjalnie powodować nieparzyste problemy, jeśli klasa podrzędna jest nadrzędna względem equals()
i nie respektuje tych samych wymagań jako rodziców. Przykłady wszędzie, ale łatwym jest Lists.equalsImpl()
, który jest używany przez ImmutableList
.
do zwarcia niepotrzebnej budowy obiektu
Można użyć instanceof
aby sprawdzić, czy przekazany argument może być bezpiecznie stosowany lub zwrócone bez dalszego przekształcania go, na przykład, czy to już instancją pożądany klasy, lub jeśli wiemy, że jest niezmienna. Zobacz przykłady w CharMatcher.forPredicate()
, Suppliers.memoize()
, ImmutableList.copyOf()
itp
Aby uzyskać dostęp do szczegółów implementacji bez narażania różne zachowanie
Widać to w każdym miejscu w guawy, ale zwłaszcza w klasach użytkowych w statycznych pakiet com.google.common.collect
, na przykład w Iterables.size()
, gdzie wywołuje on Collection.size()
, jeśli to możliwe, i w inny sposób zlicza liczbę elementów w iteratorze w czasie O(n)
.
Aby uniknąć wywoływania toString()
jestem sceptyczny to zasługuje wykonywana w więcej niż bardzo kilku wybranych przypadków, ale zakładając, że jesteś pewien, że robisz to, co trzeba, można uniknąć niepotrzebnie przekształcając obiekty CharSequence
w z instanceof
, podobnie jak w przypadku Joiner.toString(Object)
.
Aby wykonać kompleksową obsługę
Oczywiście „prawo” zrobić to użyć try/catch
bloku (choć tak naprawdę, że robi instanceof
kontrole już) wyjątku, ale czasami trzeba bardziej złożonej logiki manipulacyjną, która zasługuje używanie bloków warunkowych lub przekazywanie przetwarzania do osobnej metody, na przykład wyciąganie przyczyn lub przetwarzanie specyficzne dla implementacji. Przykład można znaleźć w SimpleTimeLimiter.throwCause()
.
Jedną rzeczą, która wyróżnia się patrząc na to zachowanie jest prawie wszystkie z nich są rozwiązywaniu problemów I nie powinno być rozwiązywanie. Są przydatne w kodzie biblioteki, np. w Iterables
, ale jeśli implementuję to zachowanie, prawdopodobnie powinienem zadać sobie pytanie, czy nie ma tam bibliotek ani narzędzi, które rozwiązałyby to dla mnie.
We wszystkich przypadkach chciałbym powiedzieć, że kontrole instanceof
powinny być używane wewnętrznie jako szczegół implementacji - oznacza to, że osoba dzwoniąca jakiejkolwiek metody, która opiera się na sprawdzeniu instanceof
, nie powinna (łatwo) stwierdzić, że jest co zrobiłeś. Na przykład ImmutableList.copyOf()
zawsze zwraca wartość ImmutableList
. Jako szczegół implementacji używa on instanceof
, aby uniknąć konstruowania nowych ImmutableList
s, ale nie jest to konieczne, aby akceptowalnie zapewnić oczekiwane zachowanie.
Na marginesie, zabawne było natknięcie się na twoje imię, Louis, kiedy drążyłem kod źródłowy Guawy. Przysięgam, że nie miałem pojęcia!
Hmmmmm. Czy masz jakieś przykłady? Nie spotkałem się z taką potrzebą z żadnymi interfejsami API, w które grałem. –
@LouisWasserman Coś napisanego w sposób inny niż OO, na przykład, mieliśmy API innej firmy, w którym różne klasy FTP nie rozszerzały wspólnej klasy bazowej ani nie implementowały interfejsu. Aby traktować je jako "takie same", naszym szybkim obejściem było kilka banalnych sprawdzeń instancji. Ostatecznie nakładamy warstwę na wierzch. Na świecie jest mnóstwo złych API. –
Ew. Sądzę, że powinienem być wdzięczny za to, że nie musiałem zajmować się żadną z tych bestii. –