Dans Java 8, les méthodes peuvent être créées en tant qu'expressions Lambda et peuvent être transmises par référence (avec un peu de travail sous le capot). Il existe de nombreux exemples en ligne avec lambdas créés et utilisés avec des méthodes, mais aucun exemple ne permet de créer une méthode prenant un lambda en tant que paramètre. Quelle est la syntaxe pour cela?
MyClass.method((a, b) -> a+b);
class MyClass{
//How do I define this method?
static int method(Lambda l){
return l(5, 10);
}
}
Les Lambda sont purement une construction de site d’appel: le destinataire du lambda n’a pas besoin de savoir qu’un Lambda est impliqué, mais accepte une interface avec la méthode appropriée.
En d'autres termes, vous définissez ou utilisez une interface fonctionnelle (c'est-à-dire une interface avec une seule méthode) qui accepte et retourne exactement ce que vous voulez.
Pour cela, Java 8 est livré avec un ensemble de types d'interface couramment utilisés dans Java.util.function
(grâce à Maurice Naftalin pour le conseil concernant le JavaDoc).
Pour ce cas d'utilisation spécifique, il y a Java.util.function.IntBinaryOperator
avec ne seule méthode int applyAsInt(int left, int right)
, de sorte que vous puissiez écrire votre method
comme ceci:
_static int method(IntBinaryOperator op){
return op.applyAsInt(5, 10);
}
_
Mais vous pouvez tout aussi bien définir votre propre interface et l'utiliser comme ceci:
_public interface TwoArgIntOperator {
public int op(int a, int b);
}
//elsewhere:
static int method(TwoArgIntOperator operator) {
return operator.op(5, 10);
}
_
L’utilisation de votre propre interface présente l’avantage de pouvoir donner des noms qui indiquent plus clairement l’intention.
Pour utiliser l'expression Lambda, vous devez créer votre propre interface fonctionnelle ou utiliser l'interface fonctionnelle Java pour les opérations nécessitant deux nombres entiers et renvoyées sous forme de valeur. IntBinaryOperator
Utilisation d'une interface fonctionnelle définie par l'utilisateur
interface TwoArgInterface {
public int operation(int a, int b);
}
public class MyClass {
public static void main(String javalatte[]) {
// this is lambda expression
TwoArgInterface plusOperation = (a, b) -> a + b;
System.out.println("Sum of 10,34 : " + plusOperation.operation(10, 34));
}
}
Utilisation de Java interface fonctionnelle
import Java.util.function.IntBinaryOperator;
public class MyClass1 {
static void main(String javalatte[]) {
// this is lambda expression
IntBinaryOperator plusOperation = (a, b) -> a + b;
System.out.println("Sum of 10,34 : " + plusOperation.applyAsInt(10, 34));
}
}
Autre exemple que j'ai créé est ici
Pour les fonctions qui n'ont pas plus de 2 paramètres, vous pouvez les transmettre sans définir votre propre interface. Par exemple,
_class Klass {
static List<String> foo(Integer a, String b) { ... }
}
class MyClass{
static List<String> method(BiFunction<Integer, String, List<String>> fn){
return fn.apply(5, "FooBar");
}
}
List<String> lStr = MyClass.method((a, b) -> Klass.foo((Integer) a, (String) b));
_
Dans BiFunction<Integer, String, List<String>>
, Integer
et String
sont ses paramètres et _List<String>
_ est son type de retour.
Pour une fonction avec un seul paramètre, vous pouvez utiliser Function<T, R>
, où T
est son type de paramètre et R
est son type de valeur de retour. Reportez-vous à ceci page pour toutes les interfaces déjà mises à disposition par Java.
Il existe une version publique accessible au Web de JavaDocs Java 8 compatible Lambda _, liée à partir de http://lambdafaq.org/lambda-resources . (Cela devrait évidemment être un commentaire sur la réponse de Joachim Sauer, mais je ne peux pas entrer dans mon compte SO avec les points de réputation dont j'ai besoin pour ajouter un commentaire.) Le site lambdafaq (je le maintiens) répond à cette question et beaucoup d'autres questions Java-lambda.
NB Cette réponse a été écrite avant la documentation de Java 8 GA _ disponible au public . Je suis toutefois resté en place, car Lambda FAQ pourrait toujours être utile aux personnes qui se familiarisent avec les fonctionnalités introduites dans Java 8.
Pour ceux qui recherchent cela sur Google, une bonne méthode serait d'utiliser Java.util.function.BiConsumer
. ex:
Import Java.util.function.Consumer
public Class Main {
public static void runLambda(BiConsumer<Integer, Integer> lambda) {
lambda.accept(102, 54)
}
public static void main(String[] args) {
runLambda((int1, int2) -> System.out.println(int1 + " + " + int2 + " = " + (int1 + int2)));
}
L'empreinte serait: 166
Pour moi, la solution la plus logique est de définir une interface Callback
:
interface Callback {
void call();
}
et ensuite l'utiliser comme paramètre dans la fonction que vous voulez appeler:
void somewhereInYourCode() {
method(() -> {
// You've passed a lambda!
// method() is done, do whatever you want here.
});
}
void method(Callback callback) {
// Do what you have to do
// ...
// Don't forget to notify the caller once you're done
callback.call();
}
Un lambda n'est pas une interface spéciale, une classe ou quoi que ce soit que vous pourriez déclarer par vous-même. Lambda
n'est que le nom donné à la syntaxe spéciale () -> {}
, qui permet une meilleure lisibilité lors du passage d'interfaces à une méthode en tant que paramètre. Il a été conçu pour remplacer ceci:
method(new Callback() {
@Override
public void call() {
// Classic interface implementation, lot of useless boilerplate code.
// method() is done, do whatever you want here.
}
});
Ainsi, dans l'exemple ci-dessus, Callback
est pas un lambda, c'est simplement une interface régulière; lambda
est le nom de la syntaxe de raccourci que vous pouvez utiliser pour l'implémenter.
L'expression lambda peut être transmise en tant qu'argument. Pour transmettre une expression lambda en tant qu'argument, le type du paramètre (qui reçoit l'expression lambda en tant qu'argument) doit être de type à interface fonctionnelle.
S'il y a une interface fonctionnelle -
interface IMyFunc {
boolean test(int num);
}
Et il existe une méthode de filtrage qui ajoute l'int dans la liste uniquement si elle est supérieure à 5. Notez ici que cette méthode de filtrage utilise l'interface fonctionnelle IMyFunc comme l'un des paramètres. Dans ce cas, l'expression lambda peut être passée en tant qu'argument pour le paramètre method.
public class LambdaDemo {
public static List<Integer> filter(IMyFunc testNum, List<Integer> listItems) {
List<Integer> result = new ArrayList<Integer>();
for(Integer item: listItems) {
if(testNum.test(item)) {
result.add(item);
}
}
return result;
}
public static void main(String[] args) {
List<Integer> myList = new ArrayList<Integer>();
myList.add(1);
myList.add(4);
myList.add(6);
myList.add(7);
// calling filter method with a lambda expression
// as one of the param
Collection<Integer> values = filter(n -> n > 5, myList);
System.out.println("Filtered values " + values);
}
}
Fondamentalement, pour passer une expression lamda en tant que paramètre, nous avons besoin d’un type dans lequel nous pouvons le contenir. Tout comme une valeur entière, nous avons la primitive int ou la classe Integer. Java n'a pas de type séparé pour l'expression lamda, mais utilise une interface comme type pour contenir l'argument. Mais cette interface devrait être un interface fonctionnelle.
Lambda n'est pas un objet mais une interface fonctionnelle. On peut définir autant d'interfaces fonctionnelles que possible en utilisant @FuntionalInterface comme annotation.
@FuntionalInterface
public interface SumLambdaExpression {
public int do(int a, int b);
}
public class MyClass {
public static void main(String [] args) {
SumLambdaExpression s = (a,b)->a+b;
lambdaArgFunction(s);
}
public static void lambdaArgFunction(SumLambdaExpression s) {
System.out.println("Output : "+s.do(2,5));
}
}
La sortie sera comme suit
Output : 7
Le concept de base d'une expression Lambda est de définir votre propre logique, mais des arguments déjà définis. Ainsi, dans le code ci-dessus, vous pouvez modifier la définition de la fonction do en ajoutant d'autres définitions, mais vos arguments sont limités à 2.
Eh bien, c'est facile. Le but de l'expression lambda est d'implémenter l'interface fonctionnelle. C'est l'interface avec une seule méthode. Voici un article sur les interfaces fonctionnelles prédéfinies et héritées.
En tout cas, si vous voulez implémenter votre propre interface fonctionnelle, fabriquez-la. Juste pour exemple simple:
public interface MyFunctionalInterface {
String makeIt(String s);
}
Faisons donc une classe, où nous allons créer une méthode, qui accepte le type de MyFunctionalInterface :
public class Main {
static void printIt(String s, MyFunctionalInterface f) {
System.out.println(f.makeIt(s));
}
public static void main(String[] args) {
}
}
La dernière chose à faire est de passer l’implémentation de MyFunctionalInterface à la méthode que nous avons définie:
public class Main {
static void printIt(String s, MyFunctionalInterface f) {
System.out.println(f.makeIt(s));
}
public static void main(String[] args) {
printIt("Java", s -> s + " is Awesome");
}
}
C'est ça!
Faites ce qui suit ..
Vous avez déclaré method(lambda l)
Tout ce que vous voulez faire est de créer une interface avec le nom lambda
et de déclarer une méthode abstraite.
public int add(int a,int b);
le nom de la méthode n'a pas d'importance ici.
Ainsi, lorsque vous appelez MyClass.method( (a,b)->a+b)
cette implémentation (a,b)->a+b
sera injectée à votre méthode d’ajout d’interface. Ainsi, chaque fois que vous appelerez l.add
, elle prendra cette implémentation et ajoutera a
et b
et return l.add(2,3)
renverront 5
. - En gros, c'est ce que fait lambda.