Чи може в лямбі Java більше 1 параметра?


157

Чи в Java можливо лямбда приймати кілька різних типів?

Тобто: Одинична змінна працює:

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

Вараги також працюють:

    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, але не зміг його знайти. Чи можливо це?

Відповіді:


178

Це можливо, якщо ви визначите такий функціональний інтерфейс з декількома параметрами типу. Такого вбудованого типу немає. (Є кілька обмежених типів з кількома параметрами.)

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

Я Function6тут його назвав . Ім'я на ваш розсуд, просто намагайтеся не стикатися з існуючими іменами в бібліотеках Java.


Також немає можливості визначити змінну кількість параметрів типу, якщо саме про це ви питали.


Деякі мови, як-от Scala, визначають кількість вбудованих таких типів з параметрами типу 1, 2, 3, 4, 5, 6 тощо.


58
Ви завжди можете використовувати Currying:Function<One, Function<Two, Function<Three, Function<Four, Function<Five, Six>>>>> func = a -> b -> c -> d -> e -> 'z';
Holger

@SotiriosDelimanolis: Я б краще обрав іншу назву, з Functionякої сутички з java.util.function.Function<T,R>цим можуть бути незрозумілими для початківців.
Ніколас

@Nikolas Це розумно. Відредаговано.
Сотіріос Деліманоліс

39

Щось із двома параметрами ви можете використовувати 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";
};

34

У цьому випадку ви можете використовувати інтерфейси з бібліотеки за замовчуванням (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 "";
    };
}}

5
Ви отримаєте більше голосів від шанувальників Java8, якщо ви внесете зміни до свого питання, щоб проілюструвати, як ці інтерфейси можна використовувати для задоволення вимоги.
Martin Cowie

3
BiFunction дозволяє визначити лише двоаргументні функції, питання про функції з будь-якою кількістю аргументів
Дмитро Клочков

8

Для використання лямбда: Існує три типи операцій:
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);
}

1

Інша альтернатива, не впевнена, чи це стосується вашої конкретної проблеми, але до якоїсь проблеми вона може бути застосована, - це використовувати 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

Ви також можете використовувати бібліотеку jOOL - https://github.com/jOOQ/jOOL

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.