¿Puede un lambda java tener más de 1 parámetro?

158

En Java, ¿es posible que una lambda acepte múltiples tipos diferentes?

Es decir: la variable única funciona:

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

Varargs también funciona:

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

Pero quiero algo que pueda aceptar muchos tipos diferentes de argumentos, por ejemplo:

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

El uso principal es tener pequeñas funciones en línea dentro de las funciones para mayor comodidad.

Revisé google e inspeccioné el paquete de funciones de Java, pero no pude encontrarlo. es posible?

Leo Ufimtsev
fuente

Respuestas:

178

Es posible si define una interfaz tan funcional con múltiples parámetros de tipo. No existe tal tipo incorporado. (Hay algunos tipos limitados con múltiples parámetros).

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

Lo he llamado Function6aquí. El nombre es a su discreción, solo trate de no chocar con los nombres existentes en las bibliotecas de Java.


Tampoco hay forma de definir un número variable de parámetros de tipo, si eso es lo que estaba preguntando.


Algunos idiomas, como Scala, definen una serie de tipos incorporados, con 1, 2, 3, 4, 5, 6, etc. parámetros de tipo.

Sotirios Delimanolis
fuente
58
Siempre puedes usar Curry:Function<One, Function<Two, Function<Three, Function<Four, Function<Five, Six>>>>> func = a -> b -> c -> d -> e -> 'z';
Holger
@SotiriosDelimanolis: Prefiero elegir un nombre diferente del Functioncual los choques con java.util.function.Function<T,R>eso podrían no estar claros para los principiantes.
Nikolas
@ Nikolas Eso es razonable. Editado
Sotirios Delimanolis
39

Para algo con 2 parámetros, podría usar BiFunction. Si necesita más, puede definir su propia interfaz de función, así:

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

Si hay más de un parámetro, debe poner paréntesis alrededor de la lista de argumentos, así:

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

Para este caso, podría usar interfaces de la biblioteca predeterminada (java 1.8):

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

Hay un pequeño (no el mejor) ejemplo de método predeterminado en la interfaz:

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
fuente
55
Obtendrá más votos positivos de los fanáticos de Java8 si modifica su pregunta para ilustrar cómo se pueden usar esas interfaces para satisfacer el requisito.
Martin Cowie
3
BiFunction le permite definir solo funciones de dos argumentos, la pregunta es sobre funciones con cualquier número de argumentos
Dmitry Klochkov
8

Para hacer uso de lambda: Hay tres tipos de operaciones:
1. Aceptar parámetro -> Consumidor
2. Probar parámetro retorno booleano -> Predicar
3. Manipular parámetro y valor de retorno -> Función

Interfaz funcional Java hasta dos parámetros:
interfaz de un solo parámetro Función de predicado del
consumidor Interfaz de dos parámetros BiConsumer BiPredicate BiFunction







Para más de dos , debe crear una interfaz funcional de la siguiente manera (tipo de consumidor):

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

Otra alternativa, no estoy seguro si esto se aplica a su problema particular, pero para algunos puede ser aplicable es usarlo UnaryOperatoren la biblioteca java.util.function. donde devuelve el mismo tipo que especifique, por lo que coloca todas sus variables en una clase y es como un parámetro:

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

Entonces, la clase que tiene, en este caso Person, puede tener numerosas variables de instancia y no tendrá que cambiar el parámetro de su expresión lambda.

Para aquellos interesados, he escrito notas sobre cómo usar la biblioteca java.util.function: http://sysdotoutdotprint.com/index.php/2017/04/28/java-util-function-library/

mel3kings
fuente
1

También puede usar la biblioteca jOOL: https://github.com/jOOQ/jOOL

Ya ha preparado interfaces de funciones con diferentes números de parámetros. Por ejemplo, puede usar org.jooq.lambda.function.Function3, etc. de Function0hasta Function16.

PetroCliff
fuente