December 13, 2018

Learn how to implement java.util.function.BiFunction in java.

I am using java 11, you will need to modify the codes a bit to work in java below version 11.

BiFunction is a Functional Interface , It has two methods in it, andThen  and apply. The method andThen  has a default implementation and apply  method is an abstract.

  1. andThen :- This method is used to chain multiple BiFunction together. It helps to execute multiple actions in sequence, one after the other.
    This looks like this in java default <C> BiFunction<A,B,C> andThen(Function<? super X,? extends C> after)
  2. apply :- This functions is the terminal state. The execution of sequence of methods will stop right here. This is what it looks like in java C apply(A a, B b)

These are our variables and Lambdas .

Variables :-

String firstName = "anurag";
String lastName = "anand";

This my first-name and last-name, which is obvious from the variable names.

Lambda 1 :-

Function<String, String> upperCaseIt = String::toUpperCase;

This is a lambda, which converts the input string to uppercase and returns it.

If you don’t believe me, then let me run this code.

var upperCaseFirstName = upperCaseIt.apply(firstName);
System.out.println("Name converted to uppercase" + upperCaseFirstName);

and see the output.

Name converted to uppercase :- ANURAG

My first name is printed in uppercase.

Lambda 2 :-

Function<String, String> sayHello = (name) -> "Hello " + name;

This lambda will prepend "Hello" in the name to any string passed to it.

Don’t believe a code without running it. So, I am going to run it now.

var helloMessage = sayHello.apply(lastName);
System.out.println(helloMessage);

Now, I am going to show the output.

Hello anand

So, here it is, it prepended "Hello" to my last name. All is good, because it compiles and runs and produces the correct output.

Now, getting to real thing. Understanding  how to implement BiFunction  in java.

We are going to do following in our implementation.

  1. put underscore between first-name and last-name
  2. convert it to uppercase
  3. prepend "Hello" to the output of above of two operations. that will be applied in order from top to bottom.

This is our parent BiFunction.

BiFunction<String, String, String> putUnderscore = (fName, lName) -> fName + "_" + lName;

It accepts two string-type arguments and joins the arguments by an underscore.

Run it.

var underscoreNames = putUnderscore.apply(firstName, lastName);
System.out.println(underscoreNames);

Output :-

anurag_anand

See, there is underscore present between first-name and last-name.

Now, we will pass the upperCaseIt Function into it’s andThen method. This will return another BiFunction.

BiFunction<String, String, String> upperCaseBiFunction = putUnderscore.andThen(upperCaseIt);

Now, we will pass sayHello Function in the BiFunction created above. Which will give us a new BiFunction.

BiFunction<String, String, String> sayHelloBiFunction = upperCaseBiFunction.andThen(sayHello);

This sayHelloBiFunction is the BiFunction that we need. This will apply all the methods in the order of application of the Function.

Run it.

var finalMessage = sayHelloBiFunction.apply(firstName, lastName);
System.out.println(finalMessage);

Output :- 

Hello ANURAG_ANAND

We can see that the firstName and lastName is joined by underscore. Then it was converted to uppercase. And lastly, "Hello" was prepended to it.

We don’t need to create all these variables to store the intermediate BiFunctions. We can just chain the calls to andThen methods, like this.

putUnderscore
    .andThen(upperCaseIt)
    .andThen(sayHello)
    .apply(firstName, lastName);

And we can go one more step and wrap above code inside a print statement.

System.out.println(
   putUnderscore
      .andThen(upperCaseIt)
      .andThen(sayHello)
      .apply(firstName, lastName)
);

We can go one more step and write entire code in single line. 🙂

System.out.println(putUnderscore.andThen(upperCaseIt).andThen(sayHello).apply(firstName, lastName));

See.. now we are Functional Ninjas .. hehehe hahaha 🙂

Complete Code.

package com.functionalinterface;

import java.util.function.BiFunction;
import java.util.function.Function;

public class BiFunctionTest {
    public static void main(String[] args) {
        String firstName = "anurag";
        String lastName = "anand";
        Function<String, String> upperCaseIt = String::toUpperCase;
        Function<String, String> sayHello = (name) -> "Hello " + name;

        BiFunction<String, String, String> putUnderscore = (fName, lName) -> fName + "_" + lName;
        BiFunction<String, String, String> upperCaseBiFunction = putUnderscore.andThen(upperCaseIt);
        BiFunction<String, String, String> sayHelloBiFunction = upperCaseBiFunction.andThen(sayHello);

        System.out.print("#1 -> ");
        System.out.println(sayHelloBiFunction.apply(firstName, lastName));
        System.out.println();

        //One liners
        System.out.print("#2 -> ");
        System.out.println(
                putUnderscore
                        .andThen(upperCaseIt)
                        .andThen(sayHello)
                        .apply(firstName, lastName)
        );
        System.out.println();

        System.out.print("#3 -> ");
        System.out.println(putUnderscore.andThen(upperCaseIt).andThen(sayHello).apply(firstName, lastName));



    }
}

Output :-

#1 -> Hello ANURAG_ANAND

#2 -> Hello ANURAG_ANAND

#3 -> Hello ANURAG_ANAND

 

So, we are done with BiFunction .