Java лямбда не работает с полным определением - PullRequest
3 голосов
/ 15 мая 2019

Я пытаюсь обернуть методы, которые выдают проверенные исключения. Я выполняю следующие шаги, указанные в этом URL: https://www.rainerhahnekamp.com/en/ignoring-exceptions-in-java/

Интересно, когда я пишу код, подобный этому:

IntStream.range(1, locales.length)
            .mapToObj(i -> locales[i].toString())
            .forEach(wrap(this::testLocale));

работает нормально, но когда я пишу так:

IntStream.range(1, locales.length)
            .mapToObj(i -> locales[i].toString())
            .forEach(s -> wrap(testLocale(s)));

Intellij жалуется на "необработанное исключение: java.lang.Exception"

здесь testLocale выглядит так:

void testLocale(String s) throws Exception

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

public static <T> Consumer<T> wrap(WrapConsumer<T> wrapper) {
    return t -> {
        try {
            wrapper.accept(t);
        } catch(Exception exception) {
            throw new RuntimeException(exception);
        }
    };
}

, а WrapConsumer - это функциональный интерфейс с сигнатурой Consumer:

@FunctionalInterface
public interface WrapConsumer<T> {
   void accept(T t) throws Exception;
}

Я бьюсь головой, пытаясь понять, почему Intellijжалуется на основании того, как я пишу лямбда

Ответы [ 3 ]

3 голосов
/ 15 мая 2019

Вы должны предоставить forEach упакованного потребителя через:

.forEach(wrap(this::testLocale));

то, что вы делаете через s -> wrap(testLocale(s)), это предоставить нового потребителя, который все еще не можетобработать проверенное исключение.

Возможно, проще будет понять, что forEach принимает Consumer, который имеет определение метода:

void accept(T t); // does not define to throw the checked Exception

Когда вы делаете forEach(s -> ...), этоэто Consumer::accept, который вы используете.

С другой стороны, forEach(wrap(this::testLocale)); будет возвращать Consumer все еще, но принимая в качестве ввода WrapConsumer<T> wrapper, что действительно объявляетбросить это Exception через:

void accept(T t) throws Exception;
2 голосов
/ 15 мая 2019

В дополнение к тому, что ответил Евгений, вы ожидаете, что метод wrap () будет являться потребителем в качестве параметра, а не методом вызова, возвращающим void.

Это можно доказать, удалив исключение throws из метода testLocale.

IDE выдаст вам ошибку:

"reason: no instance(s) of type variable(s) T exist so that void conforms to WrapConsumer<T>"

Аналогичный код для того, что вы написали (правый потребитель):

IntStream.range(1, locales.length)
        .mapToObj(i -> locales[i].toString())
        .forEach(wrap(this::testLocale));

будет:

IntStream.range(1, locales.length)
        .mapToObj(i -> locales[i].toString())
        .forEach(wrap(l-> testLocale(l)));
2 голосов
/ 15 мая 2019

Вам просто не хватает правильного синтаксиса лямбды.Ваш текущий код вызывает wrap с аргументом void: wrap(testLocale(s)) - (testLocale(s) имеет тип возврата void)

Нужное правильное лямбда-выражение:

.forEach(wrap(s -> testLocale(s)));

wrap возвращает функцию, поэтому вам не нужно откладывать ее выполнение (т. Е. Не нужна функция, которая вызывает wrap).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...