Friday, March 10, 2017

Functional Interface in Java 8

INTRODUCTION

Functional Interfaces meant for performing a single task. In programming way, a Functional Interface will have only one method. Some of the examples are:
  1. Runnable - has only run() method.
  2. Callable - has only call() method.
  3. Comparable - has only compareTo() method.
  4. ActionListener - has only actionPerformed() method.
Java 8 introduced lot more functional interfaces and all are packaged into java.util.function. The notable point here is that there is NO Class defined in this package.
Some of the major Functional Interfaces are:
  1. Function
  2. Predicate
  3. Consumer
  4. Supplier
In this post, we are going see how can we use those Functional Interfaces.
Java 8 also introduced a separate Annotation called @FunctionalInterface to indicate the Interface is Functional Interface. Using this annotation, we can create our own Functional Interfaces.
Let us have a Model Class: Person
public class Person {
 private String firstname;
 private String lastname;
 private Gender gender;
 private String address;
 private int age;
 private int phone;
.....
}

More details on each Functional Interface below.

FUNCTION INTERFACE

Function interface will be assigned as the result of Lambda expression or Method references.
Function<T,R> -> here T denotes the Type of the input and R denotes the Result of the output.
Consider If we want to print the firstname first followed by lastname from the list of person, we can do as below.
Create a list of the person object.
List<Person> persons = Arrays.asList(new Person[]{
  new Person("Arun", "Kumar", Gender.MALE, "Hydrabad", 55, 88000),
  new Person("Bala", "Ram", Gender.MALE, "Chennai", 23, 96000),
  new Person("Cavin", "Raj", Gender.MALE, "Bangalore", 3, 86000),
  new Person("Nancy", "David", Gender.FEMALE, "Delhi", 1, 97000) });

Function<Person, String> firstNameFirst = p -> "Name: "
+ p.getFirstname() + "," + p.getLastname()
+  "\nAddress: " + p.getAddress() + "\nPhone: " + p.getPhone();
here Type of the Input is Person Class and Result of the output is String. And go on print as below.
for (Person person : persons){
 System.out.println(person.printMe(firstNameFirst));
}

Chain operations are helpful to reduce the complexity of the code. For example, if we want to calculate multiplication of input after the sum, then we can do it easily by below example.
public static int calc(int value, Function<Integer, Integer> operation) {
return operation.apply(value);
}

Function<Integer, Integer> increment = e -> e + 1;
Function<Integer, Integer> multiplication = e -> e * 2;
System.out.println("Sum and Multi: "
+ calc(10, increment.andThen(multiplication)));
And very easy to add another into that existing chain.

Function<Integer, Integer> division = e -> e / 2;
System.out.println("Sum, Multi and Division: " +
  calc(10,increment.andThen(multiplication).andThen(division)));     

PREDICATE INTERFACE

Same as Function, Predicate also can be assigned as the result of Lambda expression or Method references.
Predicate<T> - T indicates the Type of the input. Only one input and output the result as boolean.
Consider if we want to categorize the persons based on their age, then we can apply the Predicate and group them as below.
Create an Enum for person category.

public enum PersonCategory {
 CHILDREN, TEEN, OLD;
}
Create a method which will accept the PersonCategory and result in the person who belongs to which category.

public static Predicate<Person> getCategory(PersonCategory category) {
 Map<PersonCategory, Predicate<Person>> categories
      = new HashMap<PersonCategory, Predicate<Person>>();

 Predicate<Person> children = p -> p.getAge() < 12;
 Predicate<Person> teenage = p -> p.getAge() > 12 && p.getAge() < 25;
 Predicate<Person> older = p -> p.getAge() > 25;

 categories.put(PersonCategory.CHILDREN, children);
 categories.put(PersonCategory.TEEN, teenage);
 categories.put(PersonCategory.OLD, older);

 return categories.get(category);
}
Now apply the filter using this Category and print it.

persons.stream().filter(getCategory(PersonCategory.OLD))
               .forEach(Person::firstNameFirst);

CONSUMER INTERFACE

Consumer<T> - T denotes the type of the input and it will not return any result.

List<Person> persons = Arrays.asList(new Person[] {
       new Person("A", "a", Gender.MALE, "Hydrabad", 55, 88000),
       new Person("B", "b", Gender.MALE, "Chennai", 23, 96000),
       new Person("C", "c", Gender.MALE, "Bangalore", 3, 86000),
       new Person("D", "d", Gender.FEMALE, "Delhi", 1, 97000) });
Now create a consumer with list of person with first name first.
Consumer<Person> consumer = Person::firstNameFirst;
Now using consumer object, we can add a new Person as below.
consumer.accept(new Person("E", "e", Gender.MALE, "Kerala", 33, 87874));

the main beauty of this code is, we are not at all modifying the existing person list rather we are adding a new Person dynamically.

SUPPLIER INTERFACE

Supplier<T> - T denotes the type of output by the Supplier.
Consider the below example to print the age of the person. It will accept the value but will not return anything.

public class SupplierInterface {
 public static void main(String[] args) {
   Supplier<Person> supplier = () ->
          new Person("Anand", "Kumar", Gender.MALE, "Hydrabad", 55, 88000);
   printAge(supplier);
 }
 private static void printAge(Supplier<Person> supplier) {
   System.out.println(supplier.get().getAge());
 }
}

CUSTOM FUNCTIONAL INTERFACE

We can create our own functional interfaces using @FunctionalInterface annotation.
For example, if we want to calculate Sum, multiplication, we can do it as below.

public class CustomFuncationInterfaces {
 public static void main(String[] args) {
   Sum sum = (a, b) -> a + b;
   System.out.println("Sum is: " + sum.add(2, 4));

   Multiplication mul = (x, y, z) -> x * y * z;
   System.out.println("Multiplication is: " + mul.mul(2, 3, 4));
 }
}

@FunctionalInterface
interface Sum {
 int add(int a, int b);
}

@FunctionalInterface
interface Multiplication {
 int mul(int a, int b, int c);
}
Hope this post throws some lights on Functional Interfaces in Java 8.
Please share your thoughts in the comment box.
Happy Knowledge Sharing!!!

No comments :

Post a Comment