it-swarm.com.de

Kann ein Java-Lambda mehr als 1 Parameter haben?

Ist es in Java möglich, dass ein Lambda mehrere verschiedene Typen akzeptiert?

I.e: Einzelvariable funktioniert:

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

Varargs funktionieren auch:

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

Ich möchte jedoch etwas, das viele verschiedene Arten von Argumenten akzeptieren kann, z.

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

Die Hauptanwendung besteht darin, kleine Inline-Funktionen in den Funktionen zu haben. 

Ich habe mich in Google umgesehen und Javas Funktionspaket angesehen, konnte es aber nicht finden. Ist das möglich?

113
Leo Ufimtsev

Dies ist möglich, wenn Sie eine solche funktionale Schnittstelle mit mehreren Typparametern definieren. Es gibt keinen solchen eingebauten Typ. (Es gibt einige begrenzte Typen mit mehreren Parametern.)

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

Es gibt auch keine Möglichkeit, eine variable Anzahl von Typparametern zu definieren, wenn Sie danach gefragt wurden.


Einige Sprachen, wie zum Beispiel Scala, definieren eine Reihe von eingebauten Typen mit den Parametern 1, 2, 3, 4, 5, 6 usw..

128

Für etwas mit 2 Parametern können Sie BiFunction verwenden. Wenn Sie mehr benötigen, können Sie wie folgt Ihre eigene Funktionsschnittstelle definieren:

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

Wenn mehrere Parameter vorhanden sind, müssen Sie die Argumentliste wie folgt mit Klammern versehen:

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

In diesem Fall können Sie Schnittstellen aus der Standardbibliothek (Java 1.8) verwenden:

Java.util.function.BiConsumer
Java.util.function.BiFunction

Es gibt ein kleines (nicht das beste) Beispiel für eine Standardmethode in der Schnittstelle:

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

Eine andere Alternative, die nicht sicher ist, ob dies auf Ihr spezielles Problem zutrifft, für einige jedoch möglicherweise die Verwendung von UnaryOperator in der Java.util.function-Bibliothek . Dort wird derselbe Typ zurückgegeben, den Sie angeben, sodass Sie alle Ihre Variablen in einen einzigen eingeben Klasse und ist es als Parameter:

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

Die Klasse, die Sie haben, in diesem Fall Person, kann über zahlreiche Instanzvariablen verfügen und muss den Parameter Ihres Lambda-Ausdrucks nicht ändern.

Für Interessierte habe ich Anmerkungen zur Verwendung der Java.util.function-Bibliothek geschrieben: http://sysdotoutdotprint.com/index.php/2017/04/28/Java-util-function-library/

1
mel3kings

Sie können auch die jOOL-Bibliothek verwenden - https://github.com/jOOQ/jOOL

Es wurden bereits Funktionsschnittstellen mit unterschiedlicher Anzahl von Parametern vorbereitet. Sie können beispielsweise org.jooq.lambda.function.Function3 usw. von Function0 bis Function16 verwenden.

0
PetroCliff

Eine OOTB -Lösung ist der Import von package kotlin.jvm.functions, der Function0, Function1, Function2 ... Function22 definiert, 

z.B.,

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 hat ähnliche Funktionen.

0
Leon

Um Lambda zu verwenden: Es gibt drei Arten von Operationen:
1. Parameter akzeptieren -> Consumer
2. Testparameter return boolean -> Prädikat
3. Parameter ändern und Rückgabewert -> Funktion

Java Functional Interface bis zu zwei Parametern:
Einzelparameter-Schnittstelle
Verbraucher
Prädikat
Funktion

Zwei-Parameter-Schnittstelle
BiConsumer
BiPredicate
BiFunction

Für mehr als zwei müssen Sie die Funktionsschnittstelle folgendermaßen erstellen (Consumer-Typ):

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