En Java, est-il possible qu’un lambda accepte plusieurs types différents?
I.e: Une seule variable fonctionne:
Function <Integer, Integer> adder = i -> i + 1;
System.out.println (adder.apply (10));
Varargs fonctionne aussi:
Function <Integer [], Integer> multiAdder = ints -> {
int sum = 0;
for (Integer i : ints) {
sum += i;
}
return sum;
};
//....
System.out.println ((multiAdder.apply (new Integer [] { 1, 2, 3, 4 })));
Mais je veux quelque chose qui puisse accepter de nombreux types d'arguments différents, par exemple:
Function <String, Integer, Double, Person, String> myLambda = a , b, c, d-> {
[DO STUFF]
return "done stuff"
};
L'utilisation principale est d'avoir de petites fonctions en ligne à l'intérieur des fonctions pour plus de commodité.
J'ai regardé autour de Google et inspecté le package de fonctions de Java, mais je n'ai pas trouvé. Est-ce possible?
C'est possible si vous définissez une telle interface fonctionnelle avec plusieurs paramètres de type. Il n'y a pas un tel type intégré. (Il existe quelques types limités avec plusieurs paramètres.)
@FunctionalInterface
interface Function<One, Two, Three, Four, Five, Six> {
public Six apply(One one, Two two, Three three, Four four, Five five);
}
public static void main(String[] args) throws Exception {
Function<String, Integer, Double, Void, List<Float>, Character> func = (a, b, c, d, e) -> 'z';
}
Il n’existe également aucun moyen de définir un nombre variable de paramètres de type, si c’est ce que vous demandiez.
Certaines langues, comme Scala, définissent un certain nombre de types intégrés, avec des paramètres de type 1, 2, 3, 4, 5, 6, etc.
Pour quelque chose avec 2 paramètres, vous pouvez utiliser BiFunction
. Si vous avez besoin de plus, vous pouvez définir votre propre interface de fonction, comme suit:
@FunctionalInterface
public interface FourParameterFunction<T, U, V, W, R> {
public R apply(T t, U u, V v, W w);
}
S'il y a plus d'un paramètre, vous devez placer des parenthèses autour de la liste des arguments, comme suit:
FourParameterFunction<String, Integer, Double, Person, String> myLambda = (a, b, c, d) -> {
// do something
return "done something";
};
Dans ce cas, vous pouvez utiliser les interfaces de la bibliothèque par défaut (Java 1.8):
Java.util.function.BiConsumer
Java.util.function.BiFunction
Il existe un petit (pas le meilleur) exemple de méthode par défaut dans l'interface:
default BiFunction<File, String, String> getFolderFileReader() {
return (directory, fileName) -> {
try {
return FileUtils.readFile(directory, fileName);
} catch (IOException e) {
LOG.error("Unable to read file {} in {}.", fileName, directory.getAbsolutePath(), e);
}
return "";
};
}}
Une autre solution consiste à utiliser UnaryOperator
dans la bibliothèque Java.util.function . Si elle s'applique à votre problème particulier, mais à certains cas, elle peut être appliquée. classe et est-ce comme paramètre:
public class FunctionsLibraryUse {
public static void main(String[] args){
UnaryOperator<People> personsBirthday = (p) ->{
System.out.println("it's " + p.getName() + " birthday!");
p.setAge(p.getAge() + 1);
return p;
};
People mel = new People();
mel.setName("mel");
mel.setAge(27);
mel = personsBirthday.apply(mel);
System.out.println("he is now : " + mel.getAge());
}
}
class People{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Ainsi, la classe que vous avez, dans ce cas Person
, peut avoir de nombreuses variables d'instance et ne devra pas changer le paramètre de votre expression lambda.
Pour les personnes intéressées, j'ai écrit des notes sur l'utilisation de la bibliothèque Java.util.function: http://sysdotoutdotprint.com/index.php/2017/04/28/Java-util-function-library/
Vous pouvez également utiliser la bibliothèque jOOL - https://github.com/jOOQ/jOOL
Il a déjà préparé des interfaces de fonction avec un nombre différent de paramètres. Par exemple, vous pouvez utiliser org.jooq.lambda.function.Function3
, etc. de Function0
à Function16
.
Une solution OOTB consiste à importer package kotlin.jvm.functions
qui définit Function0
, Function1
, Function2
... Function22
,
par exemple.,
import kotlin.jvm.functions.*;
public void testFunction() {
Function3<Integer, Integer, Integer, Integer> f3 = (x, y, z) -> x + y + z;
System.out.println(f3.invoke(1, 2, 3));
Function4<Integer, Integer, Integer, Integer, Integer> f4 = (a, b, c, d) -> a + b + c + d;
System.out.println(f4.invoke(1, 2, 3, 4));
}
scala
a des fonctions similaires.
Pour utiliser lambda: Il existe trois types d’opérations:
1. Accepter le paramètre -> Consommateur
2. Paramètre de test retour booléen -> prédicat
3. Manipuler le paramètre et renvoyer la valeur -> Fonction
Interface fonctionnelle Java jusqu'à deux paramètres:
Interface à paramètre unique
Consommateur
Prédicat
Une fonction
Interface à deux paramètres
BiConsumer
BiPredicate
BiFunction
Pour plus de deux , vous devez créer une interface fonctionnelle comme suit (type de consommateur):
@FunctionalInterface
public interface FiveParameterConsumer<T, U, V, W, X> {
public void accept(T t, U u, V v, W w, X x);
}