Sunday, April 5, 2020

Java Functional Interface


Java Lambda expression
  • Lambda expression came to enable to use functional programming feature in java.
  • It provides the facility to assign a function into a variable.
  • Lambda expression provides implementation of functional interface.
  • Lambda expression just like a function.
Benefits of Lambda Expression
  1. Length of code reduced.
  2. Increase the code readability.
Java Lambda Expression Syntax
(argument-list) -> {body}

Java lambda expression is consisted of 3 components.
1) Argument-list: It can be empty or non-empty as well.
2) Arrow-token: It is used to link arguments-list and body of expression.
3) Body: It contains expressions and statements for lambda expression.

Java Lambda Expression Example
( ) ->  System.out.println("Welcome");

Output: Welcome

 

Java Functional Interfaces
  • Functional Interfaces are used to invoke the lambda expression.
  • It helps to achieve functional programming approach in java.
Key points:
  1. An Interface that contains exactly one abstract method is known as functional interface.
  2. It can have any number of default and static methods.
  3. Functional Interface is also known as Single Abstract Method Interfaces or SAM Interfaces.
  4. Some functional interface are-Runnable - run()
    Callable - call()
    Comparable - compareTo()
  5. @FunctionalInterface annotation used to indicate that interface explicitly as functional interface.
 

Java pre-defined Functional Interfaces
Java contains a set of functional interfaces designed for commonly occurring use cases, so we don't have to create our own functional interfaces for every little use case.

1- Predicate<T>
It represents a predicate (Boolean-valued return function) of one argument.


Example 1-

import java.util.function.Predicate;

public class PredicateExample {

          public static void main(String[] args) {
                   Predicate<Integer> predicate = (age) -> age >= 18;
                   System.out.println("Voter- " + predicate.test(15));
                   System.out.println("Voter- " + predicate.test(18));
          }
}

Output:
Voter- false
Voter- true
Example 2-
Same example by using IntPredicate.

import java.util.function.IntPredicate;

public class PredicateExample {

          public static void main(String[] args) {
                   IntPredicate predicate = (age) -> age >= 18;
                   System.out.println("Voter- " + predicate.test(15));
                   System.out.println("Voter- " + predicate.test(18));
          }
}


Output:
Voter- false
Voter- true
Example 3-
Method reference example

public class PredicateExample {

          public static void main(String[] args) {
                   Predicate<String> p = String::isEmpty;
                   System.out.println(p.test("india"));
                   System.out.println(p.test(""));
          }
}

Output:
false
true
Example 4-

import java.util.function.BiPredicate;

public class PredicateExample {

          public static void main(String[] args) {
                   BiPredicate<Integer, String> predicate = (age, citizen) -> {
                             return age >= 18 && citizen.equalsIgnoreCase("INDIA");
                   };
                   System.out.println("Voter- " + predicate.test(15, "INDIA"));
                   System.out.println("Voter- " + predicate.test(19, "INDIA"));
                   System.out.println("Voter- " + predicate.test(19, "US"));
          }
}

Output:
Voter- false
Voter- true
Voter- false


2- Consumer<T>
It represents an operation that accepts a single argument and returns no result.


Example 1-

import java.util.function.Consumer;

public class ConsumerExample {

          public static void main(String[] args) {
                   Consumer<Integer> consumer = (age) -> System.out.print("Your age is: " + age);
                   consumer.accept(25);
          }
}

Output:
Your age is: 25
Example 2-
Same example by using IntConsumer.

import java.util.function.IntConsumer;

public class ConsumerExample {

          public static void main(String[] args) {
                   IntConsumer consumer = (age) -> System.out.print("Your age is: " + age);
                   consumer.accept(25);
          }
}

Output:
Your age is: 25
Example 3-

import java.util.function.BiConsumer;

public class ConsumerExample {

          public static void main(String[] args) {
                   BiConsumer<String, Integer> consumer = (name, age) -> {
                             System.out.println("Your name is: " + name);
                             System.out.println("Your age is: " + age);
                   };

                   consumer.accept("Rahul", 30);
          }
}

Output:
Your name is: Rahul
Your age is: 30
Example 4-
Same example by using ObjIntConsumer.

import java.util.function.ObjIntConsumer;

public class ConsumerExample {

          public static void main(String[] args) {
                   ObjIntConsumer<String> consumer = (name, age) -> {
                             System.out.println("Your name is: " + name);
                             System.out.println("Your age is: " + age);
                   };

                   consumer.accept("Rahul", 30);
          }
}

Output:
Your name is: Rahul
Your age is: 30
Example 5-

@FunctionalInterface
public interface MyTriConsumer  {
          public void sum(int a, int b, int c);
}

public class ConsumerExample {

          public static void main(String[] args) {
                   MyTriConsumer myInterf = (a, b, c) -> {
                             System.out.println("SUM= " + (a + b + c));
                   };
                   myInterf.sum(10, 20, 30);
          }
}

Output:
SUM= 60
Example 6-

@FunctionalInterface
public interface ArithmeticOpeation {
          public void sum(int a, int b, int c);
}


public class ConsumerExample {

          public static void main(String[] args) {
                   ArithmeticOpeation consumer = (a, b, c) -> {
                             System.out.println("SUM= " + (a + b + c));
                   };
                   consumer.sum(10, 20, 30);
          }
}

Output:
SUM= 60
Example 7-

public class Employee {
          private Long id;
          private String name;
          private String job;
          private double salary;
   
        // getter/setter and constructor
}


public class ConsumerExample {

          public static void main(String[] args) {
                   Consumer<Employee> consumer = (employee) -> {
                             System.out.println(employee.getId());
                             System.out.println(employee.getName());
                             System.out.println(employee.getJob());
                             System.out.println(employee.getSalary());
                   };
                   consumer.accept(new Employee(1L, "Rahul", "CA", 150000.00));
          }
}
Output:
1
Rahul
CA
150000.0



3- Function<T, R>
It represents a function that accepts one argument and returns a result.


Example 1-

import java.util.function.Function;

public class FunctionExample {

          public static void main(String[] args) {
                   Function<String, Integer> function = (x) -> x.length();
                   int result = function.apply("javatonline");
                   System.out.println("Length : " + result);
          }
}

Output:
Length : 11
Example 2-

public class FunctionExample {

          public static void main(String[] args) {
                   ToIntFunction<String> function = (x) -> x.length();
                   int result = function.applyAsInt("javatonline");
                   System.out.println("Length : " + result);
          }
}

Output:
Length : 11
Example 3-
Same program as above but by using method reference.

public class FunctionExample {

          public static void main(String[] args) {
                   ToIntFunction<String> function =  String::length;
                   int result = function.applyAsInt("javatonline");
                   System.out.println("Length : " + result);
          }
}

Output:
Length : 11
Example 4-

public class FunctionExample {

          public static void main(String[] args) {
                   BiFunction<Integer, Integer, Integer> function = (a, b) -> {
                             return a + b;
                   };
                   int sum = function.apply(10, 20);
                   System.out.println("SUM = " + sum);
          }
}

Output:
SUM : 30
Example 5-

public class FunctionExample {

          public static void main(String[] args) {
                   IntBinaryOperator function = (a, b) -> {
                             return a + b;
                   };
                   int sum = function.applyAsInt(10, 20);
                   System.out.println("SUM = " + sum);
          }
}

Output:
SUM : 30



4- Supplier<R>
It represents a function that don’t accepts any argument and returns a result.


Example 1-

import java.util.function.Supplier;

public class SupplierExample {
          public static void main(String[] args) {
                   Supplier<Double> randomValue = () -> Math.random();
                   System.out.println(randomValue.get());
          }
}

Output:
Any random double number like-
0.5685808855697841
Example 2-

import java.util.function.DoubleSupplier;

public class SupplierExample {
          public static void main(String[] args) {
                   DoubleSupplier randomValue = () -> Math.random();
                   System.out.println(randomValue.getAsDouble());
          }
}

Output:
Any random double number like-
0.5685808855697841
Example 3-

import java.util.function.Supplier;

import com.test.Employee;

public class SupplierExample {
          public static void main(String[] args) {
                   Supplier<Employee> supplier = () -> {
                             return new Employee(1L, "Rahul", "CA", 150000.00);
                   };
                   System.out.println(supplier.get().getId());
                   System.out.println(supplier.get().getName());
                   System.out.println(supplier.get().getJob());
                   System.out.println(supplier.get().getSalary());
          }
}

Output:
1
Rahul
CA
150000.0


 


List of all Java pre-defined Functional Interfaces
We can also define our own custom functional interface. Following is the list of functional interface which are placed in java.util.function package.

Interface
Description
BiConsumer<T,U>
It represents an operation that accepts two input arguments and returns no result.
Consumer<T>
It represents an operation that accepts a single argument and returns no result.
Function<T,R>
It represents a function that accepts one argument and returns a result.
It represents a predicate (boolean-valued function) of one argument.
BiFunction<T,U,R>
It represents a function that accepts two arguments and returns a a result.
BinaryOperator<T>
It represents an operation upon two operands of the same data type. It returns a result of the same type as the operands.
BiPredicate<T,U>
It represents a predicate (boolean-valued function) of two arguments.
BooleanSupplier
It represents a supplier of boolean-valued results.
DoubleBinaryOperator
It represents an operation upon two double type operands and returns a double type value.
DoubleConsumer
It represents an operation that accepts a single double type argument and returns no result.
DoubleFunction<R>
It represents a function that accepts a double type argument and produces a result.
DoublePredicate
It represents a predicate (boolean-valued function) of one double type argument.
DoubleSupplier
It represents a supplier of double type results.
DoubleToIntFunction
It represents a function that accepts a double type argument and produces an int type result.
DoubleToLongFunction
It represents a function that accepts a double type argument and produces a long type result.
DoubleUnaryOperator
It represents an operation on a single double type operand that produces a double type result.
IntBinaryOperator
It represents an operation upon two int type operands and returns an int type result.
IntConsumer
It represents an operation that accepts a single integer argument and returns no result.
IntFunction<R>
It represents a function that accepts an integer argument and returns a result.
IntPredicate
It represents a predicate (boolean-valued function) of one integer argument.
IntSupplier
It represents a supplier of integer type.
IntToDoubleFunction
It represents a function that accepts an integer argument and returns a double.
IntToLongFunction
It represents a function that accepts an integer argument and returns a long.
IntUnaryOperator
It represents an operation on a single integer operand that produces an integer result.
LongBinaryOperator
It represents an operation upon two long type operands and returns a long type result.
LongConsumer
It represents an operation that accepts a single long type argument and returns no result.
LongFunction<R>
It represents a function that accepts a long type argument and returns a result.
LongPredicate
It represents a predicate (boolean-valued function) of one long type argument.
LongSupplier
It represents a supplier of long type results.
LongToDoubleFunction
It represents a function that accepts a long type argument and returns a result of double type.
LongToIntFunction
It represents a function that accepts a long type argument and returns an integer result.
LongUnaryOperator
It represents an operation on a single long type operand that returns a long type result.
ObjDoubleConsumer<T>
It represents an operation that accepts an object and a double argument, and returns no result.
ObjIntConsumer<T>
It represents an operation that accepts an object and an integer argument. It does not return result.
ObjLongConsumer<T>
It represents an operation that accepts an object and a long argument, it returns no result.
Supplier<T>
It represents a supplier of results.
ToDoubleBiFunction<T,U>
It represents a function that accepts two arguments and produces a double type result.
ToDoubleFunction<T>
It represents a function that returns a double type result.
ToIntBiFunction<T,U>
It represents a function that accepts two arguments and returns an integer.
ToIntFunction<T>
It represents a function that returns an integer.
ToLongBiFunction<T,U>
It represents a function that accepts two arguments and returns a result of long type.
ToLongFunction<T>
It represents a function that returns a result of long type.
UnaryOperator<T>
It represents an operation on a single operand that returnsa a result of the same type as its operand.

 

Static method inside interface
1.   To define general purpose utility methods.
2.   Interface static method by default not available to the implemented class.
3.   Interface static method always invoke by using only interface name.
4.   Overriding concepts are not applicable for interface static methods.
5.   We can define exactly same name static method but not able to override.
6.   We can define main method inside interface in java 8.
 



What will the output?
NOTE- @FunctionalInterface annotation indicates that interface explicitly as functional interface. If interface not contains SAM then compiler gives error.
Example 1-

@FunctionalInterface
public interface MyInterf {

}

Output:
MyInterf.java:3: error: Unexpected @FunctionalInterface annotation
@FunctionalInterface
^
  MyInterf is not a functional interface
    no abstract method found in interface MyInterf
1 error
Example 2-

@FunctionalInterface
public interface MyInterf {
          public void m1();
          public void m2();
}

Output:
MyInterf.java:3: error: Unexpected @FunctionalInterface annotation
@FunctionalInterface
^
  MyInterf is not a functional interface
    multiple non-overriding abstract methods found in interface MyInterf
1 error
Example 3-

public interface Sayable {
         
          default void doIt() {
                   System.out.println("Provides Dummy Implementation");
          }

          public static void welcomeMessage() {
                   System.out.println("General purpose utility method.");
          }
}

public class StaticTest {
          public static void main(String[] args) {
                   Sayable.welcomeMessage();
          }
}

Output:
General purpose utility method.

Note- Interface static method always invoke by using only interface name.
Example 4-

public interface MainInterfaceTest {
          public static void main(String[] args) {
                   System.out.println("Welcome");
          }
}

Output:
Welcome

Note- We can define main method inside interface in java 8


Java Functional Interface

Java Lambda expression Lambda expression came to enable to use functional programming feature in java. It provides the facility t...