web-dev-qa-db-fra.com

Que signifie lambda avec 2 flèches dans Java 8?

J'ai lu plusieurs Java 8 tutoriels auparavant.

À l'heure actuelle, j'ai rencontré le sujet suivant: Est-ce que Java prend en charge le currying?

Ici, je vois le code suivant:

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

Je comprends que cet exemple additionne 2 éléments mais je ne comprends pas la construction:

a -> b -> a + b;

Selon la partie gauche de l'expression, cette ligne devrait implémenter la fonction suivante:

R apply(int value); 

Avant cela, je ne rencontrais que des lambdas avec une seule flèche.

117
gstackoverflow

Si vous exprimez cela en syntaxe non abrégée lambda ou pre-lambda Java), il est plus clair ce qui se passe ...

La question initiale. Pourquoi deux flèches? Simple, il y a deux fonctions en cours de définition ... La première fonction est une fonction définissant la fonction, la seconde le résultat de cette fonction, qui se trouve être également une fonction. Chacun nécessite un -> _ opérateur pour le définir.

Non-sténographie

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

Pré-Lambda avant 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;
    }
};
118
Adam

Un IntFunction<R> est une fonction int -> R. Un IntUnaryOperator est une fonction int -> int.

Ainsi un IntFunction<IntUnaryOperator> est une fonction qui prend un int en paramètre et renvoie une fonction qui prend un int en paramètre et un 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

Peut-être que c'est plus clair si vous utilisez des classes anonymes pour "décomposer" le lambda:

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

Ajouter des parenthèses peut rendre cela plus clair:

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

Ou probablement une variable intermédiaire peut aider:

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

Réécrivons cette expression lambda avec des parenthèses pour la rendre plus claire:

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

Nous déclarons donc une fonction prenant un int qui retourne un Function. Plus précisément, la fonction retournée prend un int et retourne un int (la somme des deux éléments): ceci peut être représenté par un IntUnaryOperator =.

Par conséquent, curriedAdd est une fonction prenant un int et retournant un IntUnaryOperator, afin qu'il puisse être représenté par IntFunction<IntUnaryOperator> .

23
Tunaki

Ce sont deux expressions lambda.

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
9
a better oliver

Si vous regardez IntFunction cela pourrait devenir plus clair: IntFunction<R> Est un FunctionalInterface. Il représente une fonction qui prend un int et renvoie une valeur de type R.

Dans ce cas, le type de retour R est également un FunctionalInterface, à savoir un IntUnaryOperator. Ainsi, la fonction première (externe) renvoie elle-même une fonction.

Dans ce cas: Lorsqu'il est appliqué à un int, curriedAdd est censé renvoyer une fonction qui prend à nouveau un int (et retourne encore int, car ce que IntUnaryOperator fait).

En programmation fonctionnelle, il est courant d'écrire le type d'une fonction sous la forme param -> return_value Et vous voyez exactement cela ici. Donc, le type de curriedAdd est int -> int -> int (Ou int -> (int -> int) si vous préférez).

La syntaxe lambda de Java 8 va dans ce sens. Pour définir une telle fonction, vous écrivez

a -> b -> a + b

ce qui ressemble beaucoup au lambda calcul réel:

λa λb a + b

λb a + b Est une fonction qui prend un paramètre unique b et renvoie une valeur (la somme). λa λb a + b Est une fonction qui accepte un seul paramètre a et renvoie une autre fonction d'un seul paramètre. λa λb a + b Renvoie λb a + b Avec a défini sur la valeur du paramètre.

8
dhke