简体   繁体   中英

Why can't I compose two different functions with identical parameter types?

I have the following code:

        Function<String,Integer> f1=s->Integer.valueOf(s)+1;
        Function<String,Integer> f2=s->Integer.valueOf(s)*2;
        Function<String,Integer> f3=f1.compose(f2);

And this is the error I am getting:

method compose in interface Function<T,R> cannot be applied to given types;

What is wrong with this code?

I then looked at the compose() in the documentation:

    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
    Objects.requireNonNull(before);
    return (V v) -> apply(before.apply(v));
    }

I could not fully understand it. Someone, to explain to me the relationship between the parameters of the functions that can be composed?

To compose two functions means that the result of one will be the input to the other. Therefore, if you have two functions that have the same input type as each other and the same output type as each other but the input and output types differ, then they are not composable in either order.

In your particular case, you are requesting a composed function that applies f1() to the result of f2() , but the result of f2() is an Integer , whereas f1() requires an input of type String . One way to approach the problem would be to modify f1() so that it operates on Integer s:

        Function<Integer, Integer> f1 = i -> i + 1;
        Function<String, Integer> f2 = s -> Integer.valueOf(s) * 2;
        Function<String, Integer> f3 = f1.compose(f2);

If you cannot modify f1() , then you could insert an intermediate conversion back to String into your composition chain:

        Function<String, Integer> f1=s->Integer.valueOf(s)+1;
        Function<String, Integer> f2 = s -> Integer.valueOf(s) * 2;
        Function<String, Integer> f3 = f1.compose(f2.andThen(Integer::toString));

But of course, all those conversion back and forth to String are expensive.

Someone, to explain to me the relationship between the parameters of the functions that can be composed?

The compose method returns a Function that is composed of Function<String,Integer> f1 then followed by Function<String,Integer> f2 . However, this composition is not valid because the result of f1 (an Integer ) is supposed to be the input of f2 (and the input of f2 is a String ). So what you're trying to compose would simply not compile.

If you intend to have both functions applied on a string, say for example you want to apply the first function, then the second and then add the results, you can do something like the following:

Function<String, Integer> f = s -> f1.apply(s) + f2.apply(s);

You can also generalize that so that the results of f1 and f2 are passed to a BiFunction :

Function<String, Integer> f = compose(f1, f2, (i1, i2) -> i1 + i2);

private static Function<String, Integer> compose(Function<String, Integer> f1, 
                                                 Function<String, Integer> f2,
                                                 BiFunction<Integer, Integer, Integer> bifunction) {
    return s -> bifunction.apply(f1.apply(s), f2.apply(s));
}

Function compose 'chains' functions, and function itself has a result type. Your function with a different input type and output type cannot be 'reused' in the same function of course. See compose as doing the function in order: first step: string in f2, output is integer. Then output of f2 in f1 however has as input a string, not an integer. Hence your function compose will not work. You can only chain a function if the output of the first function can be used as input of the second function:

        Function<Integer, Integer> f1 = i -> i + 1;
        Function<String, Integer> f2 = s -> Integer.valueOf(s) * 2;
        Function<String, Integer> f3 = f1.compose(f2);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM