web-dev-qa-db-fra.com

Un lambda Java peut-il avoir plus d'un paramètre?

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?

113
Leo Ufimtsev

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.

128

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";
};
21
tbodt

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 "";
    };
}}
20
ayurchuk

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/

1
mel3kings

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.

0
PetroCliff

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.

0
Leon

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);
}
0
amoljdv06