Статьи

Кастинг в Java 8 (и дальше?)

Приведение экземпляра к типу пахнет плохим дизайном. Тем не менее, бывают ситуации, когда другого выбора нет. Возможность сделать это, следовательно, была частью 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'
}

Поскольку тип неизвестен при типе компиляции, мы будем называть это динамическим приведением.

Результаты тестов и приведений для экземпляров неправильного типа и нулевых ссылок в точности соответствуют статическому приведению.

Опубликовано vankarsten в соответствии с CC-BY-NC 2.0.

Опубликовано vankarsten в соответствии с CC-BY-NC 2.0 .

Кастинг в потоках и опциях

Настоящее

Преобразование значения 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 .