Подтвердить что ты не робот

Что означает лямбда с 2 стрелками в Java 8?

Ранее я прочитал несколько руководств по Java 8.

Сейчас я столкнулся с следующей темой: Поддерживает ли java Currying?

Здесь я вижу следующий код:

IntFunction<IntUnaryOperator> curriedAdd = a -> b -> a + b;
System.out.println(curriedAdd.apply(1).applyAsInt(12));

Я понимаю, что этот пример суммирует 2 элемента, но я не могу понять конструкцию:

a -> b -> a + b;

В соответствии с левой частью выражения эта строка должна реализовать следующую функцию:

R apply(int value); 

До этого я встречался только с лямбдами только с одной стрелкой.

4b9b3361

Ответ 1

Если вы выражаете это как синтаксис коротких строк лямбда или пред-лямбда-синтаксис Java-анонимного класса, то ясно, что происходит...

Оригинальный вопрос. Почему две стрелки? Простой, определены две функции... Первая функция - функция-определяющая функция, вторая - результат этой функции, которая также оказывается функцией. Для этого требуется оператор ->.

Non-сокращенная

IntFunction<IntUnaryOperator> curriedAdd = (a) -> {
    return (b) -> {
        return a + b;
    };
};

Предварительная Lambda перед Java 8

IntFunction<IntUnaryOperator> curriedAdd = new IntFunction<IntUnaryOperator>() {
    @Override
    public IntUnaryOperator apply(final int value) {
        IntUnaryOperator op = new IntUnaryOperator() {
            @Override
            public int applyAsInt(int operand) {
                return operand + value;
            }
        };
        return op;
    }
};

Ответ 2

An IntFunction<R> - это функция int -> R. Функция IntUnaryOperator является функцией int -> int.

Таким образом, IntFunction<IntUnaryOperator> - это функция, которая принимает параметр int as и возвращает функцию, которая принимает параметр int as и возвращает int.

a -> b -> a + b;
^    |         |
|     ---------
|         ^
|         |
|         The IntUnaryOperator (that takes an int, b) and return an int (the sum of a and b)
|
The parameter you give to the IntFunction

Может быть, более понятно, если вы используете анонимные классы для "разложения" лямбда:

IntFunction<IntUnaryOperator> add = new IntFunction<IntUnaryOperator>() {
    @Override
    public IntUnaryOperator apply(int a) {
        return new IntUnaryOperator() {
            @Override
            public int applyAsInt(int b) {
                return a + b;
            }
        };
    }
};

Ответ 3

Добавление круглых скобок может сделать это более ясным:

IntFunction<IntUnaryOperator> curriedAdd = a -> (b -> (a + b));

Или, возможно, промежуточная переменная может помочь:

IntFunction<IntUnaryOperator> curriedAdd = a -> {
    IntUnaryOperator op = b -> a + b;
    return op;
};

Ответ 4

Перепишите это лямбда-выражение с круглыми скобками, чтобы сделать его более понятным:

IntFunction<IntUnaryOperator> curriedAdd = a -> (b -> (a + b));

Итак, мы объявляем функцию, принимающую int, которая возвращает Function. Более конкретно, возвращаемая функция принимает значение int и возвращает int (сумма двух элементов): это может быть представлено как IntUnaryOperator.

Следовательно, curriedAdd - это функция, принимающая int и возвращающая IntUnaryOperator, поэтому ее можно представить как IntFunction<IntUnaryOperator>.

Ответ 5

Это два лямбда-выражения.

IntFunction<IntUnaryOperator> curriedAdd = 
  a -> { //this is for the fixed value
    return b -> { //this is for the add operation
      return a + b;
    };
  }

IntUnaryOperator addTwo = curriedAdd.apply(2);
System.out.println(addTwo.applyAsInt(12)); //prints 14

Ответ 6

Если вы посмотрите IntFunction, это может стать яснее: IntFunction<R> - это FunctionalInterface. Он представляет функцию, которая принимает int и возвращает значение типа R.

В этом случае тип возврата R также является FunctionalInterface, а именно IntUnaryOperator. Таким образом, первая (внешняя) функция возвращает функцию.

В этом случае: При применении к int предполагается, что curriedAdd возвращает функцию, которая снова принимает int (и возвращает снова int, потому что это то, что делает IntUnaryOperator).

В функциональном программировании принято писать тип функции как param -> return_value, и вы точно видите это здесь. Таким образом, тип curriedAdd равен int -> int -> int (или int -> (int -> int), если вам это нравится).

Синтаксис Java 8 лямбда согласуется с этим. Чтобы определить такую ​​функцию, вы пишете

a -> b -> a + b

который очень похож на фактическое лямбда-исчисление:

λa λb a + b

λb a + b - это функция, которая принимает единственный параметр b и возвращает значение (сумму). λa λb a + b - это функция, которая принимает единственный параметр a и возвращает другую функцию одного параметра. λa λb a + b возвращает λb a + b с a, установленным на значение параметра.