Приведение экземпляра к типу пахнет плохим дизайном. Тем не менее, бывают ситуации, когда другого выбора нет. Возможность сделать это, следовательно, была частью Java с самого первого дня.
Я думаю, что в Java 8 возникла необходимость немного улучшить эту древнюю технику.
Статическое литье
Наиболее распространенный способ приведения в Java следующий:
Статическое литье
1
2
3
4
5
|
Object obj; // may be an integer if (obj instanceof Integer) { Integer objAsInt = (Integer) obj; // do something with 'objAsInt' } |
При этом используются операторы instanceof
и cast, которые запекаются в языке. Тип, к которому приведен экземпляр, в данном случае Integer
, должен быть статически известен во время компиляции, поэтому давайте назовем это статическим приведением.
Если obj
является Integer
, вышеуказанный тест не пройден. Если мы все ClassCastException
его, мы получим ClassCastException
. Если obj
имеет значение null
, он не проходит тест instanceof
но может быть приведен, потому что null
может быть ссылкой любого типа.
Динамическое Кастинг
Техника, с которой я сталкиваюсь реже, использует методы Class
которые соответствуют операторам:
Динамическое приведение к известному типу
1
2
3
4
5
|
Object obj; // may be an integer if (Integer. class .isInstance(obj)) { Integer objAsInt = Integer. class .cast(obj); // do something with 'objAsInt' } |
Обратите внимание, что хотя в этом примере класс для приведения также известен во время компиляции, это не обязательно так:
Динамическое Кастинг
1
2
3
4
5
6
|
Object obj; // may be an integer Class<T> type = // may be Integer.class if (type.isInstance(obj)) { T objAsType = type.cast(obj); // do something with 'objAsType' } |
Поскольку тип неизвестен при типе компиляции, мы будем называть это динамическим приведением.
Результаты тестов и приведений для экземпляров неправильного типа и нулевых ссылок в точности соответствуют статическому приведению.
Кастинг в потоках и опциях
Настоящее
Преобразование значения Optional
или элементов Stream
является двухэтапным процессом: сначала мы должны отфильтровать экземпляры неправильного типа, затем мы можем привести к желаемому.
С помощью методов Class
мы делаем это с помощью ссылок на методы. Используя пример Optional
:
Кастинг в опционально
1
2
3
4
|
Optional<?> obj; // may contain an Integer Optional<Integer> objAsInt = obj .filter(Integer. class ::isInstance) .map(Integer. class ::cast); |
То, что нам нужно сделать два шага, это не страшно, но я чувствую, что это несколько неловко и более многословно, чем необходимо.
Будущее (возможно)
Я предлагаю реализовать методы приведения к Class
которые возвращают Optional
или Stream
. Если переданный экземпляр имеет правильный тип, будет возвращен Optional
или одиночный Stream
содержащий экземпляр приведения. В противном случае оба будут пустыми.
Реализация этих методов тривиальна:
Новые методы в классе
01
02
03
04
05
06
07
08
09
10
11
12
13
|
public Optional<T> castIntoOptional(Object obj) { if (isInstance(obj)) return Optional.of((T) obj); else Optional.empty(); } public Stream<T> castIntoStream(Object obj) { if (isInstance(obj)) return Stream.of((T) obj); else Stream.empty(); } |
Это позволяет нам использовать flatMap для фильтрации и приведения за один шаг:
FlatMap Это дерьмо
1
2
3
|
Stream<?> stream; // may contain integers Stream<Integer> streamOfInts = stream. flatMap(Integer. class ::castIntoStream); |
Экземпляры неправильного типа или нулевые ссылки не пройдут тест экземпляра и приведут к пустому Optional
или Stream
. Там никогда не будет ClassCastException
.
Затраты и преимущества
Осталось определить, будут ли эти методы иметь собственный вес:
- Сколько кода на самом деле может их использовать?
- Будут ли они улучшить читаемость для среднего разработчика?
- Стоит ли экономить одну строку?
- Каковы затраты на их внедрение и обслуживание?
Я бы ответил на эти вопросы не очень , немного , да , низко . Так что это близко к игре с нулевой суммой, но я убежден, что есть небольшое, но немаловажное преимущество.
Что вы думаете? Вы видите себя, используя эти методы?
Ссылка: | Приведение в Java 8 (и далее?) От нашего партнера JCG Николая Парлога из блога CodeFx . |