What are Lambda Expressions and Functional Interfaces in Java 8

In this article we will see, what are Lambda Expressions in Java 8, Why and How to use them ?, What are functional interfaces and relation between lambda expressions and functional interfaces.

In Java 8 Lambda expressions can be considered as anonymous functions, which can be passed to a method as an argument. A lambda expression don't have a name but can have parameters, return type, body and can throw exceptions as well.

Lambda expressions are called functions and not methods because of not being associated with any particular class.

Lambda expressions are mainly used in Java 8 streams to encourage behaviour parameterization, lambdas does not do anything extra that can not be done before Java 8, but they makes it possible to write same code in more readable and less clumsy format.

Before Java 8
Comparator<Fruit> colourCompar = new Comparator<Fruit>() {
		@Override
		public int compare(Fruit arg0, Fruit arg1) {
			return arg0.colour.compareTo(arg1.colour);
		}
	};
	
	Comparator<Fruit> nameCompar = new Comparator<Fruit>() {
		@Override
		public int compare(Fruit arg0, Fruit arg1) {
			return arg0.name.compareTo(arg1.name);
		}
	};
In Java 8 Lambdas
Comparator<Fruit> colourCompar = (Fruit f1, Fruit f2) -> f1.colour.compareTo(f2.colour);
Comparator<Fruit> nameCompar = (Fruit f1, Fruit f2) -> f1.name.compareTo(f2.name);
Avobe two lines can also be written as:
Comparator<Fruit> colourCompar = (f1, f2) -> f1.colour.compareTo(f2.colour);
Comparator<Fruit> nameCompar = (f1, f2) -> f1.name.compareTo(f2.name);
As you can see in above example, the anonymous class implementation of Comparator has repetitive code, the only useful line in the code is:
arg0.colour.compareTo(arg1.colour)
the only difference between different anonymous implementations of Comparator is the condition line, that's what is written in Java 8 lambda representation of the same code, this way lambdas does the same work but in a precise and cleaner way.


Functional interface and Lambda in Java 8

A lambda expression can be assigned to a functional interface as shown in the example below, right hand side of equals (=) is lambda expression, while left of equals (=) is an functional interface.
Comparator<Fruit> colourCompar = (Fruit f1, Fruit f2) -> f1.colour.compareTo(f2.colour);
A functional interface is an interface that have one and only one abstract method, however as interfaces in Java 8 can have default non-abstract methods, a functional interface can have any number of default methods in it. Following interfaces in Java 8 library are functional interfaces:
@FunctionalInterface
public interface Comparator {
	int compare(T o1, T o2);
}

@FunctionalInterface
public interface Runnable {
	void run();
}
There are many more, as you may notice these interfaces are annotated with @FunctionalInterface, this annotation is used to denote an functional interface in same way as @Override is used to denote an overridden method in subclass.

Of course, we can also create our own functional interfaces and can have their lambda implementations to be passed through streams functions or any regular java method call.
@FunctionalInterface
interface MyFunctionalInterface {
	void print();
}

@FunctionalInterface
interface MyFunctionalInterfaceWithDefault {
	void print();

	default int getNumber() {
		return 1;
	}
}
As shown above both MyFunctionalInterface and MyFunctionalInterfaceWithDefault are valid functional interfaces, we can use them in many ways to pass dynamic behaviour parameterization, an example is given below:
	public void testFunctional(MyFunctionalInterface myFunctionalInterface) {
		myFunctionalInterface.print();
	}
Now while calling, testFunctional we can pass lambda expressions instead of an object of MyFunctionalInterface's implementation class or anonymous class, as shown below:
		ja8.testFunctional(() -> System.out.println("I am called 1"));
		ja8.testFunctional(() -> {
			// doing nothing
		});
As shown below, we are passing anonymous method implementation in form of lambda, we may call a sys.out in body, or we can do nothing or whatever on other call as shown above.

Lambda expressions can be used to provide inline implementation of abstract methods of functional interfaces, and can be passed as an instance of functional interface. As stated earlier the same functionality can be achieved using anonymous classes yet usage of lambdas is much cleaner.

The signature of an abstract method of functional interface is also called "function descriptor", it describes signature of a lambda expression.


Lambda expressions in Java 8 Streams

The java.util.function.* package provides a number of predefined functional interfaces, we can use them in our program; lets try to use one of them here:
java.util.function.Predicate
The signature of this functional interface is as shown below:
public interface Predicate{
	boolean test(T t);
}
As the signature suggests, it accept an object and return a Boolean value based on some test on that object, the condition to be tested can be passed as a lambda as shown below:
		Predicate<Fruit> predicateRed = (f)->f.colour.equals("Red");
		Predicate<Fruit> predicateGreen = f->f.colour.equals("Green");
These predicate implementations can be passed in .filter() functiona of Stream() api, as shown below:
		List<Fruit> fruits = new ArrayList<>();
		
		Predicate<Fruit> predicateRed = (f)->f.colour.equals("Red");
		List<Fruit> filteredFruits = fruits.stream().filter(predicateRed).collect(Collectors.toList());
Optionally, we can pass the lambda directly to filter() function as shwon below:
		List<Fruit> fruits = new ArrayList<>();
		List<Fruit> filteredFruits = fruits.stream().filter((f)->f.colour.equals("Red")).collect(Collectors.toList());
Now you can get an idea, how useful lambda expressions are while dealing with java 8 streams(), java 8 stream has a number of functions that requires an functional interface as parameter, and we know it really well by now that we can pass a lambda expression to a function where an instance of functional interface is needed.

In case a functional interface is having an abstract method that throws exception, that method can be called with lambda expressions as shown below:
@FunctionalInterface
interface MyFileReader {
	void read() throws IOException;
}

public void readFile(MyFileReader myFileReader) {
	try {
		myFileReader.read();
	} catch (IOException e) {
		e.printStackTrace();
	}
}

public static void main(String[] args) {
	Ja8 ja8 = new Ja8();
	ja8.readFile(()->System.out.println("Reading file"));
}
By now, you must be able to answer these questions ?

1) What are lambda expressions in Java 8, why to use them ?
2) How and Where to use Java 8 Lambda expressions ?
3) What are functional interfaces in Java 8, how and where to use them ?

About The Author

Nagesh Chauhan

Nagesh Chauhan has 8+ years of software design and development experience in variety of technologies like - Core Java, Java 8 (Streams, Lambda), J2EE (Servlet, JSP), Spring Framework (MVC, IOC, JDBC, SECURITY etc), Spring Boot and Microservices, Kafla, Redis, Cassandra and Spark.