MKod
MKod

Reputation: 823

Java 8: How BiFunction works while using andThen() and apply() methods

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

Answers (3)

Maurice Perry
Maurice Perry

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

ernest_k
ernest_k

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

Eran
Eran

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

Related Questions