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?
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.
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".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With