Метод ссылок на необработанные типы вреден?

Код ниже содержит ссылку на Enum::name (обратите внимание, нет параметра типа).

public static <T extends Enum<T>> ColumnType<T, String> enumColumn(Class<T> klazz) {
    return simpleColumn((row, label) -> valueOf(klazz, row.getString(label)), Enum::name);
}

public static <T, R> ColumnType<T, R> simpleColumn(BiFunction<JsonObject, String, T> readFromJson,
        Function<T, R> writeToDb) {
 // ...
}

Javac сообщает о предупреждении во время компиляции:

[ПРЕДУПРЕЖДЕНИЕ] обнаружил необработанный тип: java.lang.Enum пропущенные аргументы типа для универсального класса java.lang.Enum

Изменение выражения на Enum<T>::name вызывает предупреждение, чтобы уйти.

Однако идея помечает Enum<T>::name версия с предупреждением, что:

Явные аргументы типа могут быть выведены

В свою очередь, Eclipse (ECJ) не сообщает о проблемах ни с одной из формул.

Какой из трех подходов является правильным?

С одной стороны, сырые виды довольно противны. Если вы попытаетесь ввести другой аргумент типа, например Enum<Clause>::name приведет к сбою компиляции, так что это дополнительная защита.

С другой стороны, приведенная выше ссылка эквивалентна e -> e.name() лямбда, и эта формулировка не требует аргументов типа.

Enviorment:

  • Java 8u91
  • Сообщество IDEA 15.0.3
  • ECJ 4.5.2

1 ответ

Решение

Не существует такой вещи, как "ссылка на сырой метод". Несмотря на то, что существуют необработанные типы, помогающие переносу кода, предшествующего Generics, не может быть никакого использования ссылок на методы до Generics, поэтому нет "режима совместимости", и вывод типа является нормой. Спецификация языка Java §15.13. Выражения ссылок на методы:

Если метод или конструктор являются универсальными, соответствующие аргументы типа могут быть либо выведены, либо предоставлены явно. Точно так же аргументы типа универсального типа, упомянутые в выражении ссылки на метод, могут быть предоставлены явно или выведены.

Выражения ссылки на метод всегда являются выражениями поли

Так что пока вы можете вызывать тип до::"необработанный тип", когда он ссылается на универсальный класс без указания аргументов типа, компилятор все равно выведет сигнатуру универсального типа в соответствии с типом целевой функции. Вот почему выдавать предупреждение о "использовании необработанных типов" здесь не имеет смысла.

Обратите внимание, что, например,

BiFunction<List<String>,Integer,String> f1 = List::get;
Function<Enum<Thread.State>,String> f2 = Enum::name;

может быть скомпилировано сjavacбез каких-либо предупреждений (в спецификации указаны аналогичные примеры, в которых тип должен быть выведен), тогда как

Function<Thread.State,String> f3 = Enum::name;

генерирует предупреждение. В спецификации сказано об этом случае:

Во втором поиске, если P1,..., Pnне пусто иP1является подтипом ReferenceType, тогда выражение ссылки на метод обрабатывается так, как если бы оно было выражением вызова метода с выражениями аргументов типов P2,...,Pn, Если ReferenceType является необработанным типом, и существует параметризация этого типа, G<...>это супертип P1тип для поиска является результатом преобразования захвата (§5.1.10), примененного кG<...>;...

Таким образом, в приведенном выше примере, компилятор должен выводить Enum<Thread.State> в качестве параметризации Enum это супертип Thread.Stateискать подходящий метод и прийти к тому же результату, что и дляf2 пример. Это как-то работает, хотя и генерирует бессмысленные необработанные предупреждения типа.


Поскольку, по-видимому, javac Это предупреждение генерируется только тогда, когда необходимо найти подходящий супертип, для вашего случая есть простое решение. Просто используйте точный тип для поиска:

public static <T extends Enum<T>> ColumnType<T, String> enumColumn(Class<T> klazz) {
    return simpleColumn((row, label) -> valueOf(klazz, row.getString(label)), T::name);
}

Это компилируется без предупреждения.

Другие вопросы по тегам