NickJ
NickJ

Reputation: 9559

Java 8 Functions - compose and andThen

I find my Java knowledge out-of-date with Java 8, and there are many new language features I am trying to learn. One of them is Functions, specifically the compose and andThen methods.

I have written a trivial experiment to test the reversibility of compose and andThen:

/** Wraps a value 
 */
public class Wrap<T> {
    private final T value;
    private Wrap(T value) {
        this.value = value;
    }
    public static <T> Wrap<T> of(T value) {
        return new Wrap<>(value);
    }
}

static void functions() {

    Function<Integer,String> itos = i->"'"+i+"'";
    Function<String,Wrap<String>> stow = s->Wrap.of(s);

    Function<Integer,Wrap<String>> itow = itos.andThen(stow);
    Function<Integer,Wrap<String>> itow2 = stow.compose(itos);

    System.out.println(itow.apply(3));
    System.out.println(itow2.apply(3));
}

In the above code, as expected, the 2 Functions itow and itow2 seem to be equivalent. But are they actually equivalent? Do the have the same result somewhat by accident in this case?

The thought occurs that both compose and andThen methods exist for a reason, and that Functions or BiFunctions might not always be reversible in this way. Can you think of any cases where the reversibility would not apply?

Upvotes: 21

Views: 37382

Answers (9)

Hasan Dag
Hasan Dag

Reputation: 51

if order is important than it makes difference

Function<Integer,Integer> sum2 = integer -> integer + 2;
Function<Integer,Integer> multiply5 = integer -> integer * 5;
    
System.out.println(sum2.andThen(multiply5).apply(3));  
System.out.println(sum2.compose(multiply5).apply(3));

output:
25
17

Upvotes: 0

Payel Senapati
Payel Senapati

Reputation: 1356

They are different in respect to the sequence in which they work.

A Simple example -

Program 1:

Function<String, String> x = myString -> myString + ",\tx function";
Function<String, String> y = myString -> myString + ",\ty function";

x = x.andThen(y);

System.out.println(x.apply("Hello"));

Output -

Hello,  x function, y function

Here, x function function gets executed and then y function gets executed

Program 2:

Function<String, String> x = myString -> myString + ",\tx function";
Function<String, String> y = myString -> myString + ",\ty function";

y = y.compose(x);

System.out.println(y.apply("Hello"));

Output -

Hello,  x function, y function

Here, y function composes x function first and then executes itself.

Thus, although outcome is same, the sequence of execution is different.

A second example -

        final double startNumber = 3.5;

        final Function<Double, Double> cubeRoot = x -> {
            System.out.println("Calculating cube root");
            return Math.pow(x, 1.0/3);
        };

        final Function<Double, Double> square = x -> {
            System.out.println("Calculating square");
            return Math.pow(x, 2);
        };

        final Function<Double, Long> round = x -> {
            System.out.println("Rounding");
            return Math.round(x);
        };

        Long result = cubeRoot.andThen(square).andThen(round).apply(startNumber);
        System.out.println("Result: " + result);

        result = round.compose(square).compose(cubeRoot).apply(startNumber);
        System.out.println("Result: " + result);

Output -

Calculating cube root
Calculating square
Rounding
Result: 2
Calculating cube root
Calculating square
Rounding
Result: 2

In cubeRoot.andThen(square).andThen(round).apply(startNumber) first cubeRoot is done, then square is done, then round is done.

In round.compose(square).compose(cubeRoot).apply(startNumber) first cubeRoot is composed and performed, then square is composed and performed, then round is composed and performed.

Thus, although outcome is same here too, the sequence of execution is different.

UPDATE

Look at the following code -

import java.util.function.Function;

public class App {
    public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder();

        int x = 1;

        String string1 = "Neha Wakes up";
        String string2 = "Brushes teeth";
        String string3 = "Goes to toilet";
        String string4 = "Takes a shower";
        String string5 = "Feeds the cat";
        String string6 = "Cleans the litter box";
        String string7 = "Eats breakfast";
        String string8 = "Goes for work";

        Function<Integer, Integer> step1 = a -> {
                stringBuilder.append(string1).append("\n");
                return a+1;
        };
        Function<Integer, Integer> step2 = a -> {
            stringBuilder.append(string2).append("\n");
            return a+1;
        };
        Function<Integer, Integer> step3 = a -> {
            stringBuilder.append(string3).append("\n");
            return a+1;
        };
        Function<Integer, Integer> step4 = a -> {
            stringBuilder.append(string4).append("\n");
            return a+1;
        };
        Function<Integer, Integer> step5 = a -> {
            stringBuilder.append(string5).append("\n");
            return a+1;
        };
        Function<Integer, Integer> step6 = a -> {
            stringBuilder.append(string6).append("\n");
            return a+1;
        };
        Function<Integer, Integer> step7 = a -> {
            stringBuilder.append(string7).append("\n");
            return a+1;
        };
        Function<Integer, Integer> step8 = a -> {
            stringBuilder.append(string8).append("\n");
            return a+1;
        };

        int num1 = step1.andThen(step2).andThen(step3).andThen(step4).andThen(step5).andThen(step6).andThen(step7).andThen(step8).apply(x);
        System.out.println(num1);
        System.out.println(stringBuilder.toString());

        stringBuilder.setLength(0);

        int num2 = step1.compose(step2).compose(step3).compose(step4).compose(step5).compose(step6).compose(step7).compose(step8).apply(x);
        System.out.println(num2);
        System.out.println(stringBuilder.toString());

    }
}

Output -

9
Neha Wakes up
Brushes teeth
Goes to toilet
Takes a shower
Feeds the cat
Cleans the litter box
Eats breakfast
Goes for work

9
Goes for work
Eats breakfast
Cleans the litter box
Feeds the cat
Takes a shower
Goes to toilet
Brushes teeth
Neha Wakes up

This further proves my point. Here in both cases the numerical output is same that is 9. But in first case andThen() executes the chain from front to end, while compose() composes the chain first from end to front and then executes it.

Upvotes: 4

slim
slim

Reputation: 41213

The source code for Function is freely available:

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

default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
    Objects.requireNonNull(after);
    return (T t) -> after.apply(apply(t));
}

From this it's pretty clear that a.andThen(b) is equivalent to b.compose(a).

It's perhaps even clearer if we make the implied this explicit:

return (V v) -> this .apply(before.apply(v)); //compose
return (T t) -> after.apply(this  .apply(t)); // andThen

You may ask, if they're equivalent, why do both exist?

Well, they're only there as a convenience in the first place. You could manage without either of them:

 a.andThen(b)

... is of course equivalent to:

 (x) -> b.apply(a.apply(x));

So, given that they're there as a convenience, each is convenient in different circumstances. You can choose which is most expressive in a particular situation.


In many functional languages that don't use the method construct, the equivalent to compose and andThen are compose and pipe, which differ only in the order the composed functions are applied.

In those languages, these are all equivalent:

fn = x => a(b(c(x)))
fn = compose(a, b, c)
fn = pipe(c, b, a)

You can see that with compose the functions are written in the same order as they would be if you wrote them nested.

With pipe the functions are written in the order they'll be applied.

Which of those is appropriate depends on circumstances, how the coder's brain is working when they write it, and how the coder would like the reader's brain to work when they read it.

One style guide for Ramda suggests that one-liners should use pipe whereas multi-line compositions should use compose:

// one-liner
const toDocument = pipe(fillTemplate, addTitles, toPdf)
// multi-line
const toDocument = compose(
   toPdf,
   addTitles,
   fillTemplate
)
 

Java's .compose() and .andThen() are just the Java equivalent of this. Use the one that makes the code seem easiest to you. In terms of performance there is no significant difference.

Upvotes: 5

Holger
Holger

Reputation: 298123

While a.andThen(b) is equivalent to b.compose(a), there’s a practical difference at the use side, when only one of these two functions is an already existing function.

Suppose, you have the already existing function

Function<Integer, String> iToHex = i -> "'" + Integer.toHexString(i) + "'";

and then, you want to chain a string transformation, e.g.

Function<Integer, String> itoUpperHex = iToHex.andThen(String::toUpperCase);

andThen obviously is much more convenient, compared to

Function<Integer,String> itoUpperHex
                       = ((Function<String,String>)String::toUpperCase).compose(iToHex);

On the other hand, if your already existing function is

Function<String, String> quote = s -> "'" + s + "'";

and you want to create the quoted hex function,

Function<Integer, String> iToHex = quote.compose(Integer::toHexString);

will be much more convenient, compared to

Function<Integer, String> iToHex = ((Function<Integer, String>) Integer::toHexString).andThen(quote);

So the decision for either method depends on which function already exists. If both are already existing functions, it doesn’t matter which method you use (unless you suspect that one of these functions might have overridden these methods to perform a more efficient composition). If you have no existing function as starting point, there is no reason to use any of these methods, as you can write the composed expression as a single lambda expression.

Upvotes: 40

Xavi
Xavi

Reputation: 119

Both are similar except the sequence how it executes the functions, refer example below-

import java.util.function.Function;

public class FunctionThenComposeTest {

    public static void main(String[] xavis_args) {

        Function<Integer, Integer> f1 = i -> {
            System.out.println("Inside F1");
            return i * i;
        };

        Function<Integer, Integer> f2 = i -> {
            System.out.println("Inside F2");
            return i * i;
        };

        System.out.println("And Then method");
        System.out.println(f1.andThen(f2).apply(2));// Execute f1 function first, take the result of f1 and then apply it to f2 function(The result of f1 function will be the input to f2 function)
        System.out.println("Compose method");        
        System.out.println(f1.compose(f2).apply(2));// First execute f2 function and then take the result of f2 and execute f1 (The result of f2 will be the input to f1 function)
    }
}

OUTPUT

And Then method

Inside F1

Inside F2

16

Compose method

Inside F2

Inside F1

16

Upvotes: 3

shubham bellale
shubham bellale

Reputation: 211

below example shows that andThen() & compose() are contradictory methods. its produces opposite result to each other.(see output for more clarification)

f1.andThen(f2).apply(10); => first execute f1.apply(10) method. based on output first method, f2.apply(result_of_f1_method) method execute.

f1.compose(f2).apply(10); => here just opposite to andThen() method. first f2.apply() and then f1.apply(output_of_f2_method) execute.

public class FunctionDemo {
    public static void main(String[] args) {

        Function<Integer, Integer> f1 = num -> (num - 4);
        Function<Integer, Integer> f2 = num -> (num * 2);

        // Using andThen() method
        int a=f1.andThen(f2).apply(10);
        System.out.println(a);// Output - 12

        //Using compose function
        int b=f1.compose(f2).apply(10);
        System.out.println(b);// Output - 16
    }
}

Upvotes: 2

Hugues M.
Hugues M.

Reputation: 20467

I'd say they are equivalent, see the implementation:

x.compose(y) = x.apply(y.apply(...))

and

y.andThen(x) = x.apply(y.apply(...))

From Function.java (I added this. for clarity):

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

default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
    Objects.requireNonNull(after);
    return (T t) -> after.apply(this.apply(t));
}

Upvotes: 2

Mena
Mena

Reputation: 48404

From the Javadocs, there's a clear difference between compose and andThen:

Returns a composed function that first applies the before function to its input, and then applies this function to the result.

Returns a composed function that first applies this function to its input, and then applies the after function to the result.

As such, reversibility will depend on the implementation of your function.

In your case, itow and itow2 are just two alternative ways of expressing the same: "run itos, then stow in this order".

Upvotes: 7

mtj
mtj

Reputation: 3554

They are equivalent.

Or in other words: x.andThen(y) is the same as y.compose(x).

Upvotes: 7

Related Questions