Ссылки метода на типы raw вредны?

приведенный ниже код содержит ссылку на 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 сообщает предупреждение во время компиляции:

[предупреждение] найдено тип raw: java.ленг.Enum отсутствуют аргументы типа для универсальный класс java.ленг.Перечислимые

изменение выражения для Enum<T>::name заставляет предупреждение уйти.

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

явный аргументы типа можно вывести

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

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

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

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

среда:

  • Java 8u91
  • идея 15.0.3 сообщество
  • ECJ 4.5.2

1 ответов


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

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

ссылочные выражения метода всегда являются Поли-выражениями

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

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

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

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

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

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

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

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


видимо, 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);
}

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