December 16, 2018

How to use and implement apply and andThen functions provided by java.util.function.BinaryOperator in java

java.util.function.BinaryOperator is a Functional Interface, it has only one abstract method.

It extends another Functional Interface java.util.function.BiFunction. It inherits apply and andThen methods from BiFunction, and adds two static factory methods maxBy  and minBy.

BinaryOperator is special case of BiFunction, where all the parameter types and return type are of the same data-type.

This is how the method declaration looks like in this interface.

  1. R apply(T t, U u)  :- is the return type. T and U are parameter types. It takes two parameters and returns one value. But, in the case of BinaryOperator, T U and R are the same.
    So, we can also write T apply(T p1, T p2) .
  2. default <T> BiFunction<T, T, T> andThen(Function<? super T, ? extends T> afterProcessor) :- It is used for chaining new functions. The afterProcessor Function will be applied after the current BinaryOperator .
  3. static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) :- This returns a BinaryOperator, this BinaryOperator returns max among two inputs, and they are of data-type T. maxBy takes a comparator as it’s argument and returns a BinaryOperator  as a result.
  4. static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) :- This returns a BinaryOperator , this BinaryOperator returns min among two inputs, and they are of data type TminBy takes comparator as it’s input and returns BinaryOperator.

In this article, we will go through these methods one by one.

This apply method implementation will take two integer value, it will raise one number to the power of the other.

We will provide four different implementations for this operation.

Class implementation :- 

static class PowerOperatorClass implements BinaryOperator<Integer> {
    @Override
    public Integer apply(Integer num, Integer power) {
        return mathPower(num, power);
    }
}

Anonymous class implementation :- 

BinaryOperator<Integer> raiseUsingAnonymousClass =
    new BinaryOperator<Integer>(){
        @Override
        public Integer apply(Integer num, Integer power) {
            return  mathPower(num, power);
        }
};

Lambda implementation :-

we explicitly mention the data-type of lambda parameters.

BinaryOperator<Integer> raiseByLambdaWithExplicitDataTypeMention =
            (Integer number, Integer pow) -> mathPower(number, pow);

We don’t mention the data-type and, we let the compiler do this job for us.

BinaryOperator<Integer> raiseBySimpleLambda = (number, pow) -> mathPower(number, pow);

We can pick any one of the implementations and use it, it will produce the same result.

We will use these two variables to run the code.

int numberToBeRaised = 100;
int power = 5;

This is our utility function that does real job of raising to the power.

static int mathPower(Integer number, Integer power) {
    return number << power;
}

I am using the smallest implementation from the list of above implementations.

int raisedValue = raiseBySimpleLambda.apply(numberToBeRaised, power);
System.out.println(raisedValue);

And we get the following output.

3200

We will get the same result with other three implementations too.

Now, we will look into the andThen method.

We are going to use above implementations for this, in the above implementations a number ‘x’ is raised to a power of ‘y’, after that we will multiply that value by two then add 100 to it.

This is our lambda, which multiplies a number by 2.

Function<Integer, Integer> multiplyBy2	= (num) -> num * 2;

This is our lambda, which adds 100 to a number.

Function<Integer, Integer> add100 = (num) -> num + 100;

Let us chain these lambdas to get the desired result.

int finalValue   =   raiseBySimpleLambda
                                    .andThen(multiplyBy2)
                                    .andThen(add100)
                                    .apply(numberToBeRaised, power);

Output :-

6500

So, this is our BinaryOperator interface.

I only covered andThen and apply methods in this article. You can read maxBy and minBy methods here.

Complete Code :- 

import java.util.function.BinaryOperator;
import java.util.function.Function;
import static java.lang.System.out;

public class BinaryOperatorImplementation {
    public static void main(String ... args) {
        int numberToBeRaised = 100;
        int power = 5;
        BinaryOperator<Integer> raiseUsingAnonymousClass =
            new BinaryOperator<Integer>(){
                @Override
                public Integer apply(Integer num, Integer power) {
                    return  mathPower(num, power);
                }
            };

        BinaryOperator<Integer> raiseByLambdaWithExplicitDataTypeMention =
            (Integer number, Integer pow) -> mathPower(number, pow);

        BinaryOperator<Integer> raiseBySimpleLambda = (number, pow) -> mathPower(number, pow);

        out.println("#1 - Using Class Implementation.");
        PowerOperatorClass raiseToThePowerByClass = new PowerOperatorClass();
        int raisedValue = raiseToThePowerByClass.apply(numberToBeRaised, power);
        out.println(raisedValue);

        out.println("#2 - Using anonymous class implementation");
        raisedValue = raiseUsingAnonymousClass.apply(numberToBeRaised, power);
        out.println(raisedValue);

        out.println("#3 - Using Lambda with explicit type declaration");
        raisedValue = raiseByLambdaWithExplicitDataTypeMention.apply(numberToBeRaised, power);
        out.println(raisedValue);


        out.println("#4 - Lambda without type declaration");
        raisedValue = raiseBySimpleLambda.apply(numberToBeRaised, power);
        out.println(raisedValue);

        Function<Integer, Integer> multiplyBy2 = (num) -> num * 2;
        Function<Integer, Integer> add100 = (num) -> num + 100;

        int finalValue = raiseBySimpleLambda.andThen(multiplyBy2).andThen(add100).apply(numberToBeRaised, power);
        out.println("#5 And Then Final Value");
        out.println(finalValue);


    }

    static int mathPower(Integer number, Integer power) {
        return number << power;
    }

    static class PowerOperatorClass implements BinaryOperator<Integer> {
        @Override
        public Integer apply(Integer num, Integer power) {
            return mathPower(num, power);
        }
    }

}

Output :- 

#1 - Using Class Implementation.
3200
#2 - Using anonymous class implementation
3200
#3 - Using Lambda with explicit type declaration
3200
#4 - Lambda without type declaration
3200
#5 And Then Final Value
6500