An Interface that contains exactly one abstract method is known as a functional interface. It can have any number of default, static methods but can contain only one abstract method. Functional Interface is also known as Single Abstract Method Interfaces or SAM Interfaces. It is a new feature in Java, which helps to achieve functional programming approach.
@FunctionalInterface public interface AdditionalCalculator { int add(int num1, int num2); }
public class FunctionalInterfaceDemo { public static void main(String[] args) { AdditionalCalculator add = (int num1, int num2) -> num1+num2; System.out.println(add.add(2, 4)); } }
Result
6
Method reference is used to refer to a method of a functional interface. It is a compact and easy form of a lambda expression. Each time when you are using a lambda expression to just referring a method, you can replace your lambda expression with method reference.
There are following types of method references in java:
Reference to a static method
protected static void methodReferenceWithStaticMethod() { List<String> names = Arrays.asList("Laulau","Kinga","Fusi"); names.forEach(MethodReferenceDemo::printMe); } public static void printMe(String str) { System.out.println("print "+str); }
Reference to an Object method
List<Integer> numbers = Arrays.asList(5, 3, 50, 24, 40, 2, 9, 18); numbers = numbers.stream() .sorted((a, b) -> a.compareTo(b)).collect(Collectors.toList()); // equivalent numbers = numbers.stream().sorted(Integer::compareTo).collect(Collectors.toList()); System.out.println(numbers);
Reference with Constructor
class User{ private String name; public User(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { // TODO Auto-generated method stub return this.name; } } .... List<String> names = Arrays.asList("Laulau","Kinga","Fusi"); names.forEach(System.out::println); List<User> users = names.stream().map(User::new).collect(Collectors.toList()); System.out.println(users);
Result
[Laulau, Kinga, Fusi]
A lambda expression is an anonymous method. This anonymous method is not executed on its own. Instead, it is used to implement a method defined by a functional interface. A functional interface is an interface that contains one and only one abstract method which typically represents a single action.
These are characteristics of a lambda expression:
(String a, String b) -> a+" "+b; // same as (a, b) -> a+" "+b;
a -> a; // same as (a) -> a;
a -> a; // same as a -> {return a;};
public class LambdaTest { interface Operator { int operation(int a, int b); } public int operate(int a, int b, Operator op) { return op.operation(a, b); } public static void main(String args[]) { Operator add = (int x, int y) -> x + y; LambdaTest test = new LambdaTest(); System.out.println("Addition is " + test.operate(6, 3, add)); } }
Lambda expressions are used primarily to define inline implementation of a functional interface.
Using lambda expression, you can refer to any final variable or effectively final variable (which is assigned only once). Lambda expression throws a compilation error, if a variable is assigned a value the second time.
@FunctionalInterface annotation
@FunctionalInterface annotation is used to ensure that the functional interface can’t have more than one abstract method. In case more than one abstract methods are present, the compiler flags an ‘Unexpected @FunctionalInterface annotation’ message. However, it is not mandatory to use this annotation.
@FunctionalInterface public interface Operator { int operation(int a, int b); // can have static methods static String sayHi(String name) { return name; } }
Very often, lambda expressions just call methods which are already implemented elsewhere. You can use method references. This is not always shorter, but it makes the code more readable.
a -> a.toLowerCase(); // same as String::toLowerCase;
Benefits of using Lambda expression
Integer[] numbers = {2, 54, 20, 1}; Arrays.sort(numbers, new Comparator<Integer>() { @Override public int compare(Integer a, Integer b) { return a - b; } }); System.out.println(Arrays.toString(numbers));
How about this version which is much cleaner and more readable.
Integer[] numbers = {2, 54, 20, 1}; Arrays.sort(numbers, (a, b) -> a-b); System.out.println(Arrays.toString(numbers));