Состав BiFunctions

У меня есть поток BiFunctions, который я хочу свести к одному BiFunction.

Чтобы быть более конкретным, у меня есть поток BiFunctions

BiFunction<x,y,y>

Где x и y обозначают типы аргументов.

Предполагая, что у меня есть две функции

f (x, y) -> y
g (x, y) -> y

Я хочу скомпоновать их функции

h(x, y) -> f(x, g(x, y))

Возможно ли это, используя потоки Java 8, а если нет, то что было бы самым элегантным способом просто перебрать все доступные функции и составить их по-другому?

Ответ 1

Используя x=Integer и y=String, вы можете определить f и g как:

BiFunction<Integer, String, String> f = (i, s) -> i + "-f-" + s;
BiFunction<Integer, String, String> g = (i, s) -> i + "-g-" + s;

И функция h может быть построена с использованием сокращения:

BiFunction<Integer, String, String> h = Stream.of(f, g)
        .reduce((f_, g_) -> (i, s) -> f_.apply(i, g_.apply(i, s)))
        .get(); //we know the stream is not empty so we can call get directly

Если вы примените h к 1 и "s", он вернет 1-f-1-g-s.

Ответ 2

Как небольшая модификация ответа assylias: в зависимости от шаблона приложения вы также можете использовать Stream#reduce, который принимает идентификатор в качестве первого аргумента, который в этом случае является "идентификатором BiFunction" (фактически, проекцией на второй аргумент).

import java.util.function.BiFunction;
import java.util.stream.Stream;

public class BiFunctionsComposition
{
    public static void main(String[] args)
    {
        BiFunction<String, String, String> f = (x,y) -> "f("+x+","+y+")";
        BiFunction<String, String, String> g = (x,y) -> "g("+x+","+y+")";

        BiFunction<String, String, String> h = Stream.of(f, g)
            .reduce((x,y) -> y, (ff,gg) -> (x,y) -> ff.apply(x, gg.apply(x, y)));

        String result = h.apply("A", "B");
        System.out.println(result); // Prints f(A,g(A,B))
    }
}