Un java lambda può avere più di 1 parametro?


158

In Java, è possibile che un lambda accetti più tipi diversi?

Vale a dire: singola variabile funziona:

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

Varargs funziona anche:

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

Ma voglio qualcosa che possa accettare molti diversi tipi di argomenti, ad esempio:

    Function <String, Integer, Double, Person, String> myLambda = a , b, c, d->  {
    [DO STUFF]
    return "done stuff"
    };

L'uso principale è avere piccole funzioni incorporate all'interno delle funzioni per comodità.

Mi sono guardato attorno a Google e ho ispezionato il pacchetto di funzioni Java, ma non sono riuscito a trovarlo. È possibile?

Risposte:


178

È possibile se si definisce un'interfaccia così funzionale con più parametri di tipo. Non esiste un tale tipo incorporato. (Esistono alcuni tipi limitati con più parametri.)

@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';
}

L'ho chiamato Function6qui. Il nome è a tua discrezione, prova solo a non scontrarti con i nomi esistenti nelle librerie Java.


Inoltre, non è possibile definire un numero variabile di parametri di tipo, se è quello che stavi chiedendo.


Alcune lingue, come Scala, definiscono un numero di tipi incorporati in tali tipi, con parametri di tipo 1, 2, 3, 4, 5, 6, ecc.


58
Puoi sempre usare Currying:Function<One, Function<Two, Function<Three, Function<Four, Function<Five, Six>>>>> func = a -> b -> c -> d -> e -> 'z';
Holger

@SotiriosDelimanolis: Preferirei scegliere un nome diverso da Functioncui gli scontri java.util.function.Function<T,R>potrebbero non essere chiari per i principianti.
Nikolas

@Nikolas È ragionevole. Modificato.
Sotirios Delimanolis,

39

Per qualcosa con 2 parametri, potresti usare BiFunction. Se hai bisogno di più, puoi definire la tua interfaccia di funzione, in questo modo:

@FunctionalInterface
public interface FourParameterFunction<T, U, V, W, R> {
    public R apply(T t, U u, V v, W w);
}

Se esiste più di un parametro, è necessario inserire parentesi attorno all'elenco degli argomenti, in questo modo:

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

35

In questo caso è possibile utilizzare le interfacce dalla libreria predefinita (java 1.8):

java.util.function.BiConsumer
java.util.function.BiFunction

C'è un piccolo (non il migliore) esempio di metodo predefinito nell'interfaccia:

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

5
Otterrai più voti positivi dai fan di Java8 se modifichi la tua domanda per illustrare come tali interfacce possono essere utilizzate per soddisfare il requisito.
Martin Cowie,

3
BiFunction ti consente di definire solo funzioni a due argomenti, la domanda riguarda le funzioni con un numero qualsiasi di argomenti
Dmitry Klochkov,

8

Per utilizzare lambda: Esistono tre tipi di operazioni:
1. Accetta parametro -> Consumatore
2. Prova parametro restituisce valore booleano -> Predicato
3. Manipola parametro e valore restituito -> Funzione

Interfaccia funzionale Java fino a due parametri:
Interfaccia a parametro singolo Funzione predicata
consumatore Interfaccia a due parametri BiConsumer BiPredicate BiFunction







Per più di due , devi creare un'interfaccia funzionale come segue (Tipo di consumatore):

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

1

Un'altra alternativa, non sono sicuro se questo si applica al tuo problema specifico, ma per alcuni potrebbe essere applicabile è quello di utilizzare UnaryOperatornella libreria java.util.function. dove restituisce lo stesso tipo specificato, quindi metti tutte le variabili in una classe ed è un parametro:

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;
    }
}

Quindi la classe che hai, in questo caso Person, può avere numerose variabili di istanza e non dovrà cambiare il parametro della tua espressione lambda.

Per coloro che sono interessati, ho scritto note su come utilizzare la libreria java.util.function: http://sysdotoutdotprint.com/index.php/2017/04/28/java-util-function-library/


1

Puoi anche utilizzare la libreria jOOL - https://github.com/jOOQ/jOOL

Ha già predisposto interfacce di funzioni con un numero diverso di parametri. Ad esempio, è possibile utilizzare org.jooq.lambda.function.Function3, ecc. Function0Fino a Function16.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.