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

158

En Java, est-il possible qu'un lambda accepte plusieurs types différents?

Ie: Fonctionne à une seule variable:

    Function <Integer, Integer> adder = i -> i + 1;
    System.out.println (adder.apply (10));

Varargs fonctionnent également:

    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?

Leo Ufimtsev
la source

Réponses:

178

C'est possible si vous définissez une telle interface fonctionnelle avec plusieurs paramètres de type. Il n'y a pas de tel type intégré. (Il existe quelques types limités avec plusieurs paramètres.)

@FunctionalInterface
interface Function6<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 {
    Function6<String, Integer, Double, Void, List<Float>, Character> func = (a, b, c, d, e) -> 'z';
}

Je l'ai appelé Function6ici. Le nom est à votre discrétion, essayez simplement de ne pas entrer en conflit avec les noms existants dans les bibliothèques Java.


Il n'y a pas non plus moyen de définir un nombre variable de paramètres de type, si c'est ce que vous vouliez.


Certains langages, 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.

Sotirios Delimanolis
la source
58
Vous pouvez toujours utiliser Currying:Function<One, Function<Two, Function<Three, Function<Four, Function<Five, Six>>>>> func = a -> b -> c -> d -> e -> 'z';
Holger
@SotiriosDelimanolis: Je préfère choisir un nom différent à partir Functionduquel des conflits avec java.util.function.Function<T,R>qui pourraient ne pas être clairs pour les débutants.
Nikolas le
@Nikolas C'est raisonnable. Édité.
Sotirios Delimanolis le
39

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 ceci:

@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 mettre des parenthèses autour de la liste d'arguments, comme ceci:

FourParameterFunction<String, Integer, Double, Person, String> myLambda = (a, b, c, d) -> {
    // do something
    return "done something";
};
tbodt
la source
35

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 "";
    };
}}
Ayurchuk
la source
5
Vous obtiendrez plus de votes positifs de la part des fans de Java8 si vous modifiez votre question pour illustrer comment ces interfaces peuvent être utilisées pour satisfaire l'exigence.
Martin Cowie
3
BiFunction vous permet de définir uniquement des fonctions à deux arguments, la question concerne les fonctions avec un nombre quelconque d'arguments
Dmitry Klochkov
8

Pour utiliser lambda: Il existe trois types d'opérations:
1. Accepter le paramètre -> Consommateur
2. Test du paramètre return boolean -> Predicate
3. Manipuler le paramètre et renvoyer la valeur -> Fonction

Interface fonctionnelle Java jusqu'à deux paramètres:
Interface à paramètre unique Fonction de prédicat
consommateur Interface à deux paramètres BiConsumer BiPredicate BiFunction







Pour plus de deux , vous devez créer une interface fonctionnelle comme suit (type consommateur):

@FunctionalInterface
public interface FiveParameterConsumer<T, U, V, W, X> {
    public void accept(T t, U u, V v, W w, X x);
}
amoljdv06
la source
1

Une autre alternative, vous ne savez pas si cela s'applique à votre problème particulier, mais à certains, cela peut être applicable est de l'utiliser UnaryOperatordans la bibliothèque java.util.function. où il retourne le même type que vous spécifiez, donc vous mettez toutes vos variables dans une classe et est-ce en tant que 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 n'aura 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/

mel3kings
la source
1

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 Function0jusqu'à Function16.

PetroCliff
la source