Один из способов ответить на ваш вопрос - ответить «когда в твердой библиотеке Java используется instanceof
?» Если мы предположим, что Guava является примером хорошо спроектированной библиотеки Java, мы можем посмотреть, где она использует instanceof
, чтобы решить, когда это допустимо.
Если мы извлечем jav-файл с исходным кодом Guava и выполним grep, мы увидим, что instanceof
упоминается 439 раз в 122 файлах:
$ pwd
/tmp/guava-13.0.1-sources
$ grep -R 'instanceof' | wc -l
439
$ grep -Rl 'instanceof' | wc -l
122
И, глядя на некоторые из этих случаев, мы можем видеть появление нескольких паттернов:
Для проверки на равенство
Это наиболее распространенное использование. Это в некоторой степени зависит от реализации, но если вы действительно хотите измерить равенство на основе класса / интерфейса, который он расширяет / реализует, вы можете использовать instanceof
, чтобы убедиться, что объект, с которым вы работаете. Однако это может вызвать странные проблемы, если дочерний класс переопределяет equals()
и не соответствует тем же требованиям instanceof
, что и родительский. Примеры везде, но простой - это Lists.equalsImpl()
, который используется ImmutableList
.
Для короткого замыкания ненужного строительства объекта
Вы можете использовать instanceof
, чтобы проверить, можно ли безопасно использовать передаваемый аргумент или вернуть его без дальнейшего преобразования, например, если это уже экземпляр нужного класса или мы знаем, что он неизменный. См. Примеры в CharMatcher.forPredicate()
, Suppliers.memoize()
, ImmutableList.copyOf()
и т. Д.
Доступ к деталям реализации без раскрытия другого поведения
Это можно увидеть повсюду в Гуаве, но особенно в статических служебных классах в пакете com.google.common.collect
, например, в Iterables.size()
, где он вызывает Collection.size()
, если это возможно, и в противном случае подсчитывает количество элементов в итераторе за O(n)
раз.
Чтобы не звонить toString()
Я скептически отношусь к тому, что это делается более чем в нескольких отдельных случаях, но, если вы уверены, что делаете все правильно, вы можете избежать ненужной конвертации CharSequence
объектов в String
с помощью instanceof
, как в Joiner.toString(Object)
.
Выполнить сложную обработку исключений
Очевидно, что «правильное» решение - использовать блок try/catch
(хотя на самом деле он уже делает instanceof
проверок), но иногда у вас есть более сложная логика обработки, которая заслуживает использования условных блоков или передачи обработки на отдельный метод, например, устранение причин или обработка, зависящая от реализации. Пример можно найти в SimpleTimeLimiter.throwCause()
.
Одна вещь, которая обращает на себя внимание при таком поведении, это то, что почти все они решают проблемы Я не должен решать . Они полезны в коде библиотеки, например в Iterables
, но если я реализую это поведение, я, вероятно, должен спросить себя, нет ли библиотек или утилит, которые решают эту проблему для меня.
Во всех случаях я бы сказал, что instanceof
проверки должны когда-либо использоваться только внутренне в качестве детали реализации - то есть вызывающий объект любого метода, который опирается на instanceof
проверку, не должен быть в состоянии (легко ) расскажи что ты сделал. Например, ImmutableList.copyOf()
всегда возвращает ImmutableList
. В качестве детали реализации он использует instanceof
, чтобы избежать создания новых ImmutableList
s, но это необязательно для приемлемого обеспечения ожидаемого поведения.
Кроме того, было забавно встретить ваше имя, Луи, когда я копался в исходном коде Гуавы. Клянусь, я понятия не имел!