it-swarm.com.ru

Может ли лямбда Java иметь более 1 параметра?

Возможно ли в Java лямбда-выражение принимать несколько разных типов?

I.e: Отдельная переменная работает:

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

Varargs также работают:

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

Но я хочу что-то, что может принимать много разных типов аргументов, например:

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

Основное использование - иметь небольшие встроенные функции внутри функций для удобства. 

Я посмотрел вокруг Google и проверил функциональный пакет Java, но не смог найти. Это возможно?

113
Leo Ufimtsev

Это возможно, если вы определите такой функциональный интерфейс с несколькими параметрами типа. Нет такого встроенного типа. (Есть несколько ограниченных типов с несколькими параметрами.)

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

Также нет способа определить переменное число параметров типа, если это то, о чем вы спрашивали.


Некоторые языки, такие как Scala, определяют ряд встроенных таких типов с параметрами типов 1, 2, 3, 4, 5, 6 и т.д.

128
Sotirios Delimanolis

Для чего-то с 2 параметрами, вы можете использовать BiFunction. Если вам нужно больше, вы можете определить свой собственный интерфейс функции, например так:

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

Если имеется более одного параметра, вам нужно поместить скобки вокруг списка аргументов, например так:

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

Для этого случая вы можете использовать интерфейсы из библиотеки по умолчанию (Java 1.8):

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

Вот небольшой (не лучший) пример метода по умолчанию в интерфейсе:

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

Другая альтернатива, не уверенная, применима ли она к вашей конкретной проблеме, но к некоторым она может быть применима, заключается в использовании UnaryOperator в библиотеке Java.util.function ., Где она возвращает тот же тип, который вы указали, поэтому вы помещаете все свои переменные в один класс и это как параметр:

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

Таким образом, у вашего класса, в данном случае Person, может быть множество переменных экземпляра, и вам не нужно будет изменять параметр вашего лямбда-выражения.

Для тех, кто заинтересован, я написал заметки о том, как использовать библиотеку Java.util.function: http://sysdotoutdotprint.com/index.php/2017/04/28/Java-util-function-library/

1
mel3kings

Вы также можете использовать библиотеку jOOL - https://github.com/jOOQ/jOOL

Уже подготовлены функциональные интерфейсы с разным количеством параметров. Например, вы можете использовать org.jooq.lambda.function.Function3 и т.д. От Function0 до Function16.

0
PetroCliff

Решение OOTB состоит в импорте package kotlin.jvm.functions, который определяет Function0, Function1, Function2 ... Function22

например.,

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 имеет аналогичные функции.

0
Leon

Чтобы использовать лямбду: Есть три типа операций:
1. Принять параметр -> Потребитель
2. Тестовый параметр возвращает логическое значение -> Предикат
3. Управление параметром и возвращаемым значением -> Функция

Функциональный интерфейс Java до двух параметров:
Интерфейс с одним параметром
Потребитель
Predicate
Функция

Двухпараметрический интерфейс
BiConsumer
BiPredicate
BiFunction

Для более чем двух , вы должны создать функциональный интерфейс следующим образом (тип потребителя):

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