2015-07-29 2 views
4

В .NET существует простой способ объединения двух делегатов (версия .NET лямбда).Java-утилита для объединения двух лямбдов?

В принципе, у вас есть:

LambdaType f1 = (a, b) => doSomething(a, b); 
LambdaType f2 = (a, b) => doSomethingElse(a, b); 
LambdaType combined = System.Delegate.Combine(f1, f2); 
// combined is equiv to: (a, b) => { f1.invoke(a, b); f2.invoke(a, b);}; 

Есть ли что-то подобное в Java, чтобы объединить два лямбды? Ничто не приходит на ум. Это была бы неплохая утилита, хотя честно не слишком сложно определить вторую лямбду, которая просто вызывает два (или более).

+2

Что делает 'Combine'? Это 'AND', или' OR'? –

+1

@kocko Это 'andThen', по внешнему виду. –

+0

@MarkoTopolnik правильно –

ответ

11

Вы говорите о Java 8 lambdas? Поскольку такие утилиты существуют, например:

Predicate<Foo> pred1 = f -> true; 
Predicate<Foo> pred2 = pred1.and(f -> false); 

или

Function<Int,Int> func1 = x -> x + 1; 
Function<Int,Int> func2 = func1.andThen(x -> x*2); 

Вы должны смотреть на java.util.function пакет, потому что вы, вероятно, найдете функция уже доступна.

В вашем конкретном примере вы не составляете две функции, фактически, функционально говоря, вы не можете составить две функции, которые принимают два аргумента и возвращают один аргумент (или void).

Это потому, что вам не хватает требования: codomain первой функции должен соответствовать domain второй функции, иначе композиция не может быть выполнена.

Что вы на самом деле делаете здесь, последовательно вызывает две несвязанные функции с одинаковыми аргументами. Эта проблема может быть решена путем делать точно то же самое:

BiConsumer<Foo,Bar> combination = (f,b) -> { doSomething(f,b); doSomethingElse(f,b); }; 
+0

Можете ли вы показать, как это работает для функций, принимающих два аргумента (и которые возвращают результат или, может быть, «void»)? – Marco13

+0

@ Marco13: Вы не можете составить две функции, которые имеют разные коды и домен. Это просто не имеет смысла, проверьте мои изменения, но вы уже указали это в своем ответе. – Jack

+0

Вы не обязательно составляете их в строгом смысле слова. 'BiConsumer' не является функцией, но определяет' andThen'. –

0

Функция композиция (также при применении к предикатам), вероятно, не то, что вы хотите: Это означает, что применение одного лямбды к типу возвращаемого другого. Это имеет несколько последствий. В частности, вы не можете составить doSomething(a,b) и doSomethingElse(a,b) таким образом, потому что просто нет возможного типа возврата любой из функций для вызова другого.

Как и в Java (к сожалению) нет LambdaType, вам нужно будет выбрать конкретный тип функции. Написанный в общем, вы будете иметь две функцию, как это:

BiFunction<A,B,T> f0 = (a, b) -> doSomething(a, b); 
BiFunction<A,B,S> f1 = (a, b) -> doSomethingElse(a, b); 

где T и S являются типами возвращаемых doSomething и doSomethingElse соответственно. Для того, чтобы объединить их и создать функцию, которая выполняет одновременно, вы можете просто написать

BiFunction<A,B,Void> f = (a,b) -> { 
    doSomething(a,b); doSomethingElse(a,b); return null; 
}; 

(или любой другой тип возвращаемого значения вы хотели бы ...)

3

Поскольку ваш запрос, кажется, включает функции, которые делают не возвращать ничего, соответствующий тип Java 8 будет BiConsumer.Это позволяет сделать, как вы хотите:

BiConsumer<A,B> f1=(a,b) -> doSomething(a,b); 
BiConsumer<A,B> f2=(a,b) -> doSomethingElse(a,b); 
BiConsumer<A,B> combined = f1.andThen(f2); 

Это зависит от типа функции предоставления фабричных методов для комбинированных функций, а не позволяя произвольные комбинации, с другой стороны, это позволяет иметь значимые комбинации, как and/or для Predicate s, которые делают что-то полезное и понятное, вместо того, чтобы просто вызвать код обеих функций и вернуть произвольный результат.

Смежные вопросы