Java ссылается на тип Enum в определении анонимного класса

Я пытаюсь определить следующий анонимный экземпляр функции Google Guava:

Function<E extends Enum<E>, String> ENUM_TO_STRING = new Function<E extends Enum<E>, String>() {
    @Override
    public String apply(E enumValue) {
        String result = null;
        if (enumValue != null) {
            result = enumValue.toString();
        }
        return result;
    }
};

Идея заключается в простом экземпляре функции преобразования с методом apply, который вызывает toString для любого значения перечисления, если оно не равно нулю, или возвращает ноль, если значение равно нулю.

К сожалению, компилятор жалуется на общую ссылку E, которая расширяет Enum. Я знаю, что это выражение может использоваться в неанонимных контекстах, например:

public static <E extends Enum<E>> String enumToString(E enumValue) {
    String result = null;
    if (enumValue != null) {
        result = enumValue.toString();
    }
    return result;      
}

Первое, анонимное определение класса не в порядке. Второе определение неанонимного метода - ОК.

Есть ли способ определить анонимный класс с помощью Enums?

Спасибо

3 ответа

Как указывает Сотириос, параметры универсального типа могут быть объявлены только для классов или методов, но не для полей. На самом деле, декларируя E вероятно, не нужно - а Function<Enum<?>, String> было бы хорошо:

Function<Enum<?>, String> ENUM_TO_STRING = new Function<Enum<?>, String>() {
    @Override
    public String apply(Enum<?> enumValue) {
        if (enumValue != null) {
            return enumValue.toString();
        }
        return null;
    }
};

Следуя этой мысли, toString объявлен Objectне Enumитак генерал Function<Object, String> имеет больше смысла:

Function<Object, String> NULLABLE_TO_STRING = new Function<Object, String>() {
    @Override
    public String apply(Object obj) {
        if (obj != null) {
            return obj.toString();
        }
        return null;
    }
};

В общем, лучше скрывать детали реализации за фабричными методами, облегчая будущие изменения, например:

private static final Function<Object, String> NULLABLE_TO_STRING = ...

public static Function<Object, String> nullableToString() {
    return NULLABLE_TO_STRING;
}

Обратите внимание, что Function<Object, String> все еще возвращается. Это должно быть хорошо, если ваши API используют PECS (например, принимают Function<? super Foo, ? extends Bar>), но мы также можем пойти дальше и предложить конкретный тип ввода, сделав метод универсальным:

private static final Function<Object, String> NULLABLE_TO_STRING = ...

public static <T> Function<T, String> nullableToString() {
    @SuppressWarnings("unchecked") // safe contravariant cast
    final Function<T, String> withNarrowedType =
            (Function<T, String>)(Function<?, String>)NULLABLE_TO_STRING;
    return withNarrowedType;
}

Обратите внимание, что это использует тот же Function экземпляр, с непроверенным приведением, чтобы сузить его тип ввода. Актерский состав безопасен, потому что NULLABLE_TO_STRING принимает любой объект и не имеет состояния. Этот паттерн демонстрируется в пункте 27 "Эффективного Java" Джошуа Блоха "Пользуйся универсальными методами".

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

Во втором примере они объявлены в сигнатуре метода.

В вашем первом примере это не похоже на E объявляется где угодно. Другими словами, вы не можете объявить переменную типа как часть объявления переменной. Вы можете сделать то, что вы пытаетесь, если метод или класс, в котором этот фрагмент кода появился в объявленной переменной типа E сам.

Вам, вероятно, здесь вообще не нужны универсальные шаблоны, поскольку вы фактически не используете информацию о типе, и она все равно теряется во время выполнения. Сначала начните с применения функции старой школы (Enum enumValue). Если вы действительно не хотите подавлять предупреждения и нуждаетесь в проверке типа, вы можете продолжить расследование.

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