Sunday, April 7, 2019

Function and BiFunction Functional Interface - JAVA 8

Function and BiFunction Functional Interface


In my previous blog, I’ve already talked about Predicate and BiPredicate Functional Interface. In this blog, I’ll talk about next predefined Functional Interface i.e. Function and BiFunction Functional Interface.
Function is a Functional Interface which accept single input and returns another. The functional method of Predicate is R apply(T t).

@FunctionalInterface
Public interface Function<T, R> { …}

Here is a simple source code of java.util.function.Function
package java.util.function;
    
import java.util.Objects;
    
@FunctionalInterface
public interface Function<T, R> {
    public <R> apply(T t);
  }

Where R apply (T t) is an abstract method where T is the type of the input to the Function and will return type of R.

Example 1:

import java.util.function.Function;

public class FunctionExample {

       public static void main(String[] args) {

             // Calling Function Functional Interface without using Lambda Expression
             FunctionExample.GetStringLength function = new FunctionExample().new GetStringLength();
             System.out.println("Length of String is : " + function.apply("www.waheedtechblog.com"));

             // Using Lambda Expression
             Function<String, Integer> f1 = (name) -> name.length();
             System.out.println("Lambda Expression, Length of String is : " + f1.apply("www.waheedtechblog.com"));
       }

       class GetStringLength implements Function<String, Integer> {

             @Override
             public Integer apply(String name) {
                    return name.length();
             }
       }
}



Example 2:
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class FunctionExample2 {

       public static void main(String[] args) {

             FunctionExample2 functionExample2 = new FunctionExample2();
             Function<Student, String> f2 = student -> student.getName();

             List<Student> students = functionExample2.populateStudentList();
             for (Student student : students) {
                    System.out.println("Student Name: " + f2.apply(student));
             }
       }

       class Student {
             private String name;
             private int age;

             public Student(String name, int age) {
                    super();
                    this.name = name;
                    this.age = age;
             }

             public String getName() {
                    return name;
             }

             public void setName(String name) {
                    this.name = name;
             }

             public int getAge() {
                    return age;
             }

             public void setAge(int age) {
                    this.age = age;
             }

             public boolean equals(Object obj) {
                    Student student = (Student) obj;
                    if ((this.getName().equals(student.getName()) && this.getAge() == student.getAge())) {
                           return true;
                    } else {
                           return false;
                    }
             }
       }

       public List<Student> populateStudentList() {
             List<Student> studentList = Arrays.asList(new Student("Abdul", 31), new Student("Waheed", 29),
                           new Student("DummyUser", 20), new Student("Adam", 25));
             return studentList;

       }

}

Output:
Student Name: Abdul
Student Name: Waheed
Student Name: DummyUser
Student Name: Adam


Apart from R Apply (T t) method, Function also has 2 default method and one static method.

Modifier and Type
Method and Description
default <V> Function<T,V>
andThen(Function<? super R,? extends V> after)
Returns a composed function that first applies this function to its input, and then applies the after function to the result.
default <V> Function<V,R>
compose(Function<? super V,? extends T> before)
Returns a composed function that first applies the before function to its input, and then applies this function to the result.
static <T> Function<T,T>
Returns a function that always returns its input argument.


1.     andThen(): default method combines the current Function instance with another one and returns a combined Function instance which applies the two functions in sequence with the function passed as parameter to andThen() being invoked after the current function.

2.     compose(): default method combines the current Function instance with another one and returns a combined Function instance which applies the two functions in sequence with the parameter function to compose() being invoked before the current function.

3.     identity(): it just returns back the parameter which it gets as input.



Let’s understand it with few more example

Example 3:

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class FunctioalExample3 {

       public static void main(String[] args) {

             FunctioalExample3 functioalExample3 = new FunctioalExample3();

             // return the name of Student
             Function<Student, String> f1 = student -> student.getName();
             // return name in uppercase
             Function<String, String> f2 = name -> name.toUpperCase();

             Function<Student, Student> f3 = student -> {
                    String name = "Adding via Compose " + student.getName();
                    return new Student(name, student.getAge());
             };

             Function<String, String> f4 = Function.identity();

             // andThen default method
             System.out.println("=============================");
             System.out.println("=====USING andThen Default Function======");
             List<Student> students = functioalExample3.populateStudentList();
             for (Student student : students) {
                    System.out.println("Student Name: " + f1.andThen(f2).apply(student));
             }

             // compose default method
             System.out.println("\n");
             System.out.println("=============================");
             System.out.println("=====USING default COMPOSE FUNCTION======");
             for (Student student : students) {
                    System.out.println("Student Name: " + f1.compose(f3).apply(student));
             }

             // Identity Static method
             System.out.println("\n");
             System.out.println("=============================");
             System.out.println("=====Identity Static method======");
             for (Student student : students) {
                    System.out.println("Student Name: " + f4.apply(student.getName()));
             }

       }

       public List<Student> populateStudentList() {
             List<Student> studentList = Arrays.asList(new Student("Abdul", 31), new Student("Waheed", 29),
                           new Student("DummyUser", 20), new Student("Adam", 25));
             return studentList;

       }

}

class Student {
       private String name;
       private int age;

       public Student(String name, int age) {
             super();
             this.name = name;
             this.age = age;
       }

       public String getName() {
             return name;
       }

       public void setName(String name) {
             this.name = name;
       }

       public int getAge() {
             return age;
       }

       public void setAge(int age) {
             this.age = age;
       }

       public boolean equals(Object obj) {
             Student student = (Student) obj;
             if ((this.getName().equals(student.getName()) && this.getAge() == student.getAge())) {
                    return true;
             } else {
                    return false;
             }
       }
}

Output:

=============================
=====USING andThen Default Function======
Student Name: ABDUL
Student Name: WAHEED
Student Name: DUMMYUSER
Student Name: ADAM


=============================
=====USING default COMPOSE FUNCTION======
Student Name: Adding via Compose Abdul
Student Name: Adding via Compose Waheed
Student Name: Adding via Compose DummyUser
Student Name: Adding via Compose Adam


=============================
=====Identity Static method======
Student Name: Abdul
Student Name: Waheed
Student Name: DummyUser
Student Name: Adam

BiFunction


It is very similar to Function Functional Interface. The only difference is just that it will accept two input arguments instead of one and as usual will return another.

@FunctionalInterface
public interface BiFunction<T,U,R> {
            R apply(T t, U u);
}


Let’s see another example

Example 4:

import java.util.function.BiFunction;

public class BiFunctionExample {

       public static void main(String[] args) {
             BiFunction<Integer, Integer, Integer> area = (a, b) -> a * b;

             System.out.println("Area of Rectangle: " + area.apply(5, 10));

       }

}
Output:

Area of Rectangle: 50


That’s it for Function and BiFunction Functional Interface, Will talk about other Predefined Functional Interface in my next blog.


Happy Coding…!!!

How TOPT Works: Generating OTPs Without Internet Connection

Introduction Have you ever wondered how authentication apps like RSA Authenticator generate One-Time Passwords (OTPs) without requiring an i...