Reputation: 823
Currently BiFunction
interface has two methods andThen()
and apply()
. I found different examples in web, but the below example is something I can't figure out - 'How the chaining of these methods works'
Example 1:
BiFunction<String, String,String> bi = (x, y) -> {
return x + y;
};
Function<String,String> f = x-> x+" spinner";
System.out.println(bi.andThen(f).apply("hello", " world"));
After reading following link 'Default andThen() method in BiFunction interface', I took below lines
Assume we had two functions f and g , function f doing some logic and function g doing some other type of logic so when you compose f.andThen(g) that essentially means g(f(x)) i.e. we first apply the function given as argument f(x) and then apply the function g to the result.
and concluded that bi.apply("hello", " world"))
happens first and then the result
is
passed on to bi.andThen(f(result))
and this gives final output hello world spinner
.
I understood to some extent, but not completely satisfied. I had to ask this because in the past I have used builder pattern and it is something like the below,
BankAccount account = new BankAccount.Builder("bank_account")
.withOwner("account_owner")
.atBranch("branch_name")
.openingBalance(balance)
.build();
Here, the method calling happens in sequence, first the Builder
(static) class gets initialised, then withOwner
assigns owner name and returns builder, and then branch name is assigned and returns builder,
next opening balance is given and returns builder, and finally build will return BankAccount
instance. Please see the BankAccount
class.
public class BankAccount {
public static class Builder {
private long accountNumber;
private String owner;
private String branch;
private double balance;
public Builder(long accountNumber) {
this.accountNumber = accountNumber;
}
public Builder withOwner(String owner){
this.owner = owner;
return this;
}
public Builder atBranch(String branch){
this.branch = branch;
return this;
}
public Builder openingBalance(double balance){
this.balance = balance;
return this;
}
public BankAccount build(){
//Here we create the actual bank account object, which is always in a fully initialised state when it's returned.
BankAccount account = new BankAccount(); //Since the builder is in the BankAccount class, we can invoke its private constructor.
account.accountNumber = this.accountNumber;
account.owner = this.owner;
account.branch = this.branch;
account.balance = this.balance;
return account;
}
}
}
As you can see the methods are called in sequence and the output of methods -withOwner
, atBranch
, openingBalance
, is Builder
instance in the chain. and for me this is called chaining of methods, because the output of each method in sequence is used for later and this is very clear. But, my ask is - how the chaining of methods of the above example 1 (BiFunction and its methods chaining)
works internally.
Upvotes: 4
Views: 3499
Reputation: 9650
The andThen
method differs from the Builder
pattern in several ways:
andThen
returns a new function that is the composition of two other functions, whereas each method of the builder returns itself, just to allow the chaining of method calls, thus making the code more compact, but you can also write:
BankAccount.Builder builder = new BankAccount.Builder("bank_account");
builder.withOwner("account_owner");
builder.atBranch("branch_name");
builder.openingBalance(balance);
BankAccount account = builder.build();
Also, with the andThen
method, everything is immutable, whereas the builder is inherently mutable (although the built object is often itself immutable).
Upvotes: 0
Reputation: 45319
It's simple function composition, meaning if we were to give the resulting function a name:
BiFunction<String, String, String> composed = bi.andThen(f);
Then a simple definition would be:
composed(x,y) = f(bi(x,y))
So BiFunction.andThen
returns a BiFunction
that will apply the current (bi
) function's logic to compute a result that's then passed to another function (f
), applying its logic to return the final output.
Upvotes: 0
Reputation: 393821
You can look at the default implementation:
default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t, U u) -> after.apply(apply(t, u));
}
As you can see, first they call the apply
method of the BiFunction
(i.e. they evaluate apply(t, u)
), and the result of that method is passed to the Function
's apply
method (after.apply(...)
).
I'm not sure why you feel andThen
doesn't call the methods in sequence. After all bi.andThen(f)
creates a BiFunction
that first calls bi
's apply
method and then calls f
's apply
method (just as the name andThen
implies).
Upvotes: 2