Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 625
NickJ Avatar asked May 08 '17 13:05

NickJ


2 Answers

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.

like image 77
Holger Avatar answered Sep 20 '22 09:09

Holger


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

  • compose...

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

  • andThen...

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".

like image 24
Mena Avatar answered Sep 18 '22 09:09

Mena