универсальные типы в сочетании со ссылками на методы - PullRequest
0 голосов
/ 21 декабря 2018

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

enum Letters {
    A("a"),
    Z("z");

    private String value;

    Letters(String value) {
        this.value = value;
    }

    private static final Map<String, Letters> MAP;

    public String getValue() {
        return value;
    }

    static {
        MAP = Arrays.stream(values())
                    .collect(Collectors.collectingAndThen(
                        Collectors.toMap(
                            Letters::getValue,
                            Function.identity()
                        ),
                        ImmutableMap::copyOf
                    ));
    }

    public static Optional<Letters> fromValue(String value) {
        return Optional.ofNullable(MAP.get(value));
    }
}

Это шаблон буквально для десятков Enums, и нет, это не может 'не может быть изменено.Я думал об изменении этого дублирования кода, так как его много .

Моя идея состояла в том, чтобы начать с интерфейса enum, который все будут реализовывать:

interface GetValueInterface {
    String getValue();
}

И некоторый общий код, который будет обрабатывать это создание MAP (fromValue также будет обрабатываться там,но давайте отложим это в сторону).Итак, что-то вроде этого:

 static class EnumsCommon {

    public static <T extends Enum<T> & GetValueInterface> Map<String, T> getAsMap(Class<T> clazz) {
        T[] values = clazz.getEnumConstants();

        return Arrays.stream(values)
                     .collect(Collectors.collectingAndThen(
                         Collectors.toMap(
                             T::getValue,
                             Function.identity()
                         ),
                         ImmutableMap::copyOf
                     ));
    }
}

Итак, код выглядит следующим образом:

enum Letters implements GetValueInterface {

    // everything else stays the same
    static {
        MAP = EnumsCommon.getAsMap(Letters.class);
    }
}

Это прекрасно компилируется, но когда я запускаю его под java-8, появляетсявыброшено исключение:

Причина: java.lang.invoke.LambdaConversionException: недопустимый тип получателя class java.lang.Enum;не подтип интерфейса реализации типа GetValueInterface

Запуск того же кода в java-11 работает просто отлично ...

1 Ответ

0 голосов
/ 21 декабря 2018

После подготовки этого вопроса в течение 20 минут я выполнил поиск в Google и сразу обнаружил проблему: | этот

Исправить несложно, просто используйте лямбда-выражение:

(T t) -> t.getValue() // instead of T::getValue
...