We may not have the course you’re looking for. If you enquire or give us a call on +1 7204454674 and speak to our training experts, we may still be able to help with your training requirements.
Training Outcomes Within Your Budget!
We ensure quality, budget-alignment, and timely delivery by our expert instructors.
As a Java Developer, you’ve probably encountered situations where you wished for a more elegant way to handle repetitive logic. Well, Functional Interfaces in Java are here to rescue you! These nifty tools streamline your code by allowing you to define a single abstract method contract.
This blog delves into the world of Functional Interfaces in Java. We’ll explore how they simplify your code, boost readability, and set the stage for using powerful features like lambda expressions and method references.
So buckle up, fellow coder! Let’s unlock a new level of development elegance together!
Table of Contents
1) What is a Functional Interface in Java?
2) Ways to use Functional Interface
3) Functional Interface Annotation
4) Types of Functional Interface
5) Primitive Function Specialisations
6) Conclusion
What is a Functional Interface in Java?
Java is an Object-oriented Programming Language, meaning everything revolves around classes and their objects. In Java, no function exists independently; functions are always part of classes or interfaces. To use a function, you need either the class or an object of that class to call it.
Functional Interfaces in Java enable the implementation of Functional Programming concepts. In Functional Programming, a function is treated as an independent entity capable of performing actions similar to variables, such as being passed as a parameter or returned by another function. Functions in Python exemplify functional programming.
Introduced in Java 8, a Functional Interface can contain only one abstract method but can include any number of static and default (non-abstract) methods.
Want to learn more advanced concepts in Java and become a better programmer? Sign up for the Java Programming course now.
What is Lambda Expression?
Lambda Expression was added in Java 8, which made Functional Interface possible. Earlier, you would have to create a class for every piece of functionality. Lambda Expressions allows you to pass or return from any method.
Ideally, Lambda Expressions must be specific in expressing the functionality it has.
Example
public class LambdaExample
{
public static void main(String[] args)
{
Runnable r = () -> System.out.println("Hello, world!");
r.run();
}
}
This example creates a new 'Runnable' object using a Lambda expression. The 'Runnable' interface has only one abstract method called run(), which takes no arguments and returns no value.
Instead of defining a separate class that implements the 'Runnable' interface, we can use a Lambda expression to directly create a new instance of the 'Runnable' interface.
This Lambda Expression is a short function that takes no arguments and prints "Hello, world!" to the console.
() -> System.out.println("Hello, world!")
Finally, it calls the run() method on the 'Runnable' object to execute the Lambda expression and print the message "Hello, world!" to the console.
What is Abstract Method?
An abstract method is a type of method that is only declared but not defined in a class. It has no implementation details and behaves like a placeholder for any subclass declaring the abstract method. The abstract method ensures that any subclass of the declaring class implementing the method has a common behaviour across all subclasses.
Example
Let's say you have an abstract class called 'Animal'. 'eat()', 'sleep()', and 'move()' can be a set of common methods and properties that all animals share in the class 'Animal'. However, the 'Animal' class doesn't provide any implementation details for these methods; instead, it simply declares them abstract.
public abstract class Animal
{
public abstract void eat();
public abstract void sleep();
public abstract void move();
}
By defining these methods as abstract, the 'Animal' class declares that any subclass of 'Animal' must implement these methods. For example, you might have a subclass called 'Dog' that extends 'Animal'. This class would need to implement the 'eat()', 'sleep()', and 'move()' methods to be a valid subclass of 'Animal'.
public class Dog extends Animal
{
public void eat()
{
System.out.println("The dog is eating");
}
public void sleep()
{
System.out.println("The dog is sleeping");
}
public void move()
{
System.out.println("The dog is running"); }
}
By using the required methods in the 'Dog' subclass, you can be sure that any instance of the 'Dog' class will have the required behaviour of an animal.
Ways to use Functional Interface
Now that you know Java Functional Interface, it's time to learn how to use them. There are two ways to use Functional Interface. One method uses the Lambda expression, and another implements the Interface (overriding the abstract method).
Using Lambda Expression to use Functional Interface
Lambda expressions in Java are similar to regular methods but offer a more concise, readable way to write code. Here are key points to remember when using lambda expressions to implement a Functional Interface:
a) Always annotate the interface declaration with @FunctionalInterface.
b) A lambda expression can be passed as a parameter to a method or returned as a value, functioning like a regular function.
c) A Functional Interface can only contain one abstract method; otherwise, the compiler will throw an "Unexpected @FunctionalInterface annotation" error.
d) You don't need to specify the abstract keyword before the method, as all methods in a Functional Interface are implicitly abstract.
For example, to create a Functional Interface that calculates the area of a rectangle, you can define the interface as follows:
@FunctionalInterface
public interface RectangleAreaCalculator
{
public double calculateArea(double length, double width);
}
After defining the Functional Interface, you can implement its single abstract method using Lamba expression. Let's say you want to implement a 'RectangleAreaCalculator' interface; you can do it like this:
RectangleAreaCalculator calculator = (length, width) -> length * width;
This example uses the lambda expression '(length, width) -> length * width' to take two parameters as length and width and returns the product of it. The lambda expression is then assigned to 'RectangleAreaCalculator', the Functional Interface implemented earlier.
When you are done implementing the Functional Interface with a Lambda expression, you can use it like any other object in your code. You can use the 'calculator' variable to calculate the area of a rectangle like this.
double area = calculator.calculateArea(5.0, 10.0); // area is 50.0
In this case, the 'calculateArea' is the method, and the 'calculator' is the object with arguments '5.0' and '10.0'. This method uses a Lambda expression to calculate the area of the rectangle to the assigned 'area' variable.
Using Functional Interface by implementing the Interface (overriding the abstract method)
Using the Functional Interface implements the Interface in the class and overrides the abstract method. To call the method, you have to create the object of the class and then use the syntax obj.AbstractMethod().
First, you must define the Functional Interface with a single abstract method like before. Let's take the same example of calculating the area of a rectangle. The first step of implementing the Functional Interface with the abstract method will remain the same.
@FunctionalInterface
public interface RectangleAreaCalculator
{
public double calculateArea(double length, double width);
}
Next, you must create a class that implements the Functional Interface and then overrides the abstract method. This is where the code differs from the method used earlier.
public class CalculateRectangleArea implements RectangleArea
{
@Override
public double calculate(double length, double width)
{
return length * width;
}
}
Here, the 'CalculateRectangleArea' class implements the method 'calculate' of the 'RectangleArea' interface that takes the length and width to return the area value.
Now that you have implemented the Functional Interface by overriding the abstract method, you can use it like any object in the code like this.
RectangleArea areaCalculator = new CalculateRectangleArea();
double length = 5.0;
double width = 3.0;
double area = areaCalculator.calculate(length, width);
System.out.println("The area of the rectangle is: " + area);
Here, an instance of the 'CalculateRectangleArea' class is created and assigned to a variable 'RectangleArea', which is the Functional Interface. The method calculates the rectangle area and returns it as a double value stored in the 'area' variable.
Functional Interface with Methods of the Object Class
A Functional Interface in Java can include methods from the Object class. Here's an example demonstrating this concept:
@FunctionalInterface
interface ObjectClassMethods {
// Abstract method
int abstractMethod(int val);
// Methods from the Object class
int hashCode();
String toString();
boolean equals(Object obj);
}
In the interface above, hashCode(), toString(), and equals() are methods from the Object class. We can include any number of methods from the Object class in a Functional Interface, and they do not require an implementation within the interface.
Functional Interface with Multiple Default and Static Methods
Let's look at an example of a Functional Interface in Java that includes default and static methods:
@FunctionalInterface
interface StaticandDefaultMethods {
// Abstract method
int square(int x);
// Default methods
default int add(int a, int b) {
return a + b;
}
default int sub(int a, int b) {
return a - b;
}
// Static methods
static int multiply(int a, int b) {
return a * b;
}
static int divide(int a, int b) {
return a / b;
}
}
// Public class
public class Test implements StaticandDefaultMethods {
public static void main(String[] args) {
int a = 8;
int b = 6;
// Object of Test class
Test t = new Test();
// Default methods called using class object
int add = t.add(a, b);
int sub = t.sub(a, b);
// Static methods called directly by the interface name
int mul = StaticandDefaultMethods.multiply(a, b);
int div = StaticandDefaultMethods.divide(a, b);
}
// Abstract method implementation
@Override
public int square(int x) {
return x * x;
}
}
In this example, square is an abstract method, add and sub are default methods, and multiply and divide are static methods. We override the square() method in the Test class. The default methods add() and sub() can be overridden in the Test class and are called using an instance of the Test class. The static methods multiply() and divide() are called using the interface name.
Functional Interface Extending a Non-Functional Interface
A Functional Interface in Java can extend other interfaces. The extends keyword is used to inherit methods from a parent interface. The parent interface must not be a Functional Interface and should not contain any abstract methods. The child interface (Functional Interface) can have a single abstract method and multiple default and static methods.
Consider a scenario with a BookStore interface and a Library interface as a Functional Interface.
interface BookStore {
int sell();
int buy();
List
// boolean issue_book(); // Uncommenting this will cause a compilation error
}
@FunctionalInterface
interface Library extends BookStore {
boolean issue_book();
}
The compiler throws an exception because the BookStore interface has three abstract methods. Therefore, the Library interface cannot extend BookStore.
Learn to build applications from scratch with our Introduction To Java EE Training.
Functional Interface Annotation
The @FunctionalInterface annotation ensures that a functional interface cannot have more than one abstract method. If more than one abstract method is present, the compiler will flag an "Unexpected @FunctionalInterface annotation" message. However, using this annotation is not mandatory.
Here’s an implementation demonstrating the concept:
// Java program to demonstrate lambda expressions to
// implement a user-defined functional interface.
@FunctionalInterface
interface Greeting {
String sayHello(String name);
}
class Test {
public static void main(String[] args) {
// Lambda expression to define the sayHello method
Greeting greeting = (String name) -> "Hello, " + name;
// Parameter passed and return type must match the prototype
String result = greeting.sayHello("John");
System.out.println(result);
}
}
Output:
Hello, John
In this example, Greeting is a functional interface with a single abstract method sayHello. The lambda expression (String name) -> "Hello, " + name implements the sayHello method. The result is printed by calling greeting.sayHello("John").
Types of Functional Interface
These are the four common types of Functional Interface used in Java
a) Predicate
b) Consumer
c) Supplier
d) Function
Predicate
This type of Functional Interface represents a function that takes in an argument and returns a Boolean value based on a condition. For example, it can check whether a given number is even or odd.
Here is an example of a Predicate Functional Interface
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class PredicateExample
{
public static void main(String[] args)
{
List numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
numbers.add(5);
Predicate isEven = n -> n % 2 == 0;
List oddNumbers = numbers.stream()
.filter(isEven.negate())
.toList();
System.out.println("Odd numbers: " + oddNumbers);
}
}
Here, the 'Predicate' Functional Interface named 'isEven' checks whether the given integer is even by using the modulo operator to check whether the remainder is zero after dividing it by two. Further, it uses the 'Stream' class' 'filter()' method to create a list of odd numbers by negating the' isEven' predicate using the 'negate()' method.
Consumer
This is a type of Functional Interface that takes in an argument but does not return any value. For example, you can print out a list of names.
Here is an example of a consumer Functional Interface.
import java.util.function.Consumer;
public class ExampleConsumer
{
public static void main(String[] args)
{
Consumer
printLength.accept("Hello, world!"); // Output: Length of string: 13
}
}
Here, the 'Consumer
Supplier
Supplier Functional Interface is the type which doesn't take in any arguments but returns a value. For example, you can use the Supplier to generate a random number or alphabet.
Here's an example of a Supplier Functional Interface
import java.util.function.Supplier;
public class ExampleSupplier
{
public static void main(String[] args)
{
Supplier
System.out.println("Random number: " + randomInt.get());
}
}
Here, the 'Supplier< Integer' Functional Interface called the 'randomInt' returns a random integer between 0 and 100. The lambda expression used here defines the behaviour of the 'Supplier' interface. Using 'get' method, a random integer is generated as output.
Function
The function is a type of Functional Interface that returns a value after taking in a single argument. For example, you can Function to convert a string into an integer.
Here’s an example of function Functional Interface:
import java.util.function.Function;
public class ExampleFunction
{
public static void main(String[] args)
{
Function
System.out.println("Square of 5: " + square.apply(5)); // Output: Square of 5: 25
}
}
Here, the 'Function
Some built-in Functional Interfaces
Post Java 8, many interfaces were converted into Functional Interfaces, and these are annotated with @FunctionalInterface. These interfaces are given below.
a) Runnable: Contains only the run() method
b) Comparable: Contains only the compareTo() method
c) ActionListener: Contains only the actionPerformed() method
d) Callable: Contains only the call() method
Primitive Function Specialisations
Primitive data types cannot be directly used as parameters for generic type arguments. For example, we cannot pass int, double, or float instead of T or R in R apply(T t) of Function
In functional interfaces and Streams, certain classes are designed specifically to operate with int, long, and double without boxing them into wrapper classes. This is known as primitive specialisation.
There are various versions of the Function interface tailored for commonly used primitive data types, both as argument and return types:
a) IntFunction, LongFunction, DoubleFunction: The argument type is specified in the function name, and the return type is parameterised.
b) ToIntFunction, ToLongFunction, ToDoubleFunction: The return type is specified in the function name, and the argument type is parameterised.
c) DoubleToIntFunction, DoubleToLongFunction, IntToDoubleFunction, IntToLongFunction, LongToIntFunction, LongToDoubleFunction: Both the argument and return types are specified in the function name.
Improve your understanding of JavaScript by signing up for our JavaScript for Beginners Course now!
Conclusion
To sum it up, Java Functional Interface in Java enables programmers to write code more concisely and modularly. The best part about the Functional Interface is that it significantly reduces bloat in the code, making debugging easier. There are a lot of predefined Functional Interface in Java to implement them using method references and lambda expressions, and you can use your own custom interfaces.
Want to learn more advanced concepts in Java and become a better programmer? Sign up for our comprehensive Java Programming Course today!
Frequently Asked Questions
Encapsulation in Java is a mechanism that binds the data (variables) and methods (functions) acting on the data into a single unit known as a class. It restricts access to some of the object's components, promoting data hiding and protection, ensuring that the internal implementation details are hidden from the outside world.
Functional Interfaces in Java have three rules:
a) It must have only one abstract method.
b) It can have multiple default or static methods.
c) It must be annotated with the @FunctionalInterface annotation to ensure that it only has one abstract method, making it clear for functional programming and compatibility with lambda expressions.
The Knowledge Academy’s Knowledge Pass, a prepaid voucher, adds another layer of flexibility, allowing course bookings over a 12-month period. Join us on a journey where education knows no bounds.
The Knowledge Academy offers various Java Training including Java Programming, JavaScript for Beginners and Java Swing Development Training. These courses cater to different skill levels, providing comprehensive insights into How to Become a Java Developer.
Our Programming and DevOps blogs cover a range of topics related to Java, offering valuable resources, best practices, and industry insights. Whether you are a beginner or looking to advance your Java Programming skills, The Knowledge Academy's diverse courses and informative blogs have you covered.
The Knowledge Academy takes global learning to new heights, offering over 30,000 online courses across 490+ locations in 220 countries. This expansive reach ensures accessibility and convenience for learners worldwide.
Alongside our diverse Online Course Catalogue, encompassing 17 major categories, we go the extra mile by providing a plethora of free educational Online Resources like News updates, Blogs, videos, webinars, and interview questions. Tailoring learning experiences further, professionals can maximise value with customisable Course Bundles of TKA.
Upcoming Programming & DevOps Resources Batches & Dates
Date
Mon 13th Jan 2025
Mon 10th Mar 2025
Mon 19th May 2025
Mon 21st Jul 2025
Mon 15th Sep 2025
Mon 17th Nov 2025
Mon 15th Dec 2025