In Java, lambda expressions and functional interfaces go hand in hand. Let’s break it down step by step:
What is a Functional Interface?
A functional interface is an interface that has exactly one abstract method.
These interfaces can be annotated with @FunctionalInterface (optional but recommended) to indicate their intent.
Example: The Runnable interface is a functional interface because it has only one abstract method: run().
What is a Lambda Expression?
A lambda expression is a concise way to write an implementation of a functional interface.
Instead of creating an anonymous class to implement the interface, you can write it using a lambda.
An anonymous class is an inline implementation of an interface or abstract class, using the following syntax:
java
Copy code
InterfaceName obj = new InterfaceName() {
// Implementation of interface methods
};
Example of Creating an Anonymous Class
Let’s create an interface and use an anonymous class to implement it:
Step 1: Define the Interface
interface Greeting {
void sayHello();
}
Step 2: Create an Anonymous Class
java
Copy code
public class Main {
public static void main(String[] args) {
// Create an anonymous class implementing the Greeting interface
Greeting greeting = new Greeting() {
@Override
public void sayHello() {
System.out.println("Hello from an anonymous class!");
}
};
// Call the method
greeting.sayHello();
}
}
Output
Hello from an anonymous class!
Real-World Example
Consider a button click handler in a GUI application. For instance, you want to handle the click event using an anonymous class.
java
Copy code
interface ClickListener {
void onClick();
}
public class ButtonExample {
public static void main(String[] args) {
// Create an anonymous class for the ClickListener interface
ClickListener buttonClickListener = new ClickListener() {
@Override
public void onClick() {
System.out.println("Button clicked!");
}
};
// Simulate a button click
buttonClickListener.onClick();
}
}
Output
Button clicked!
Key Points
Compact Implementation: You don’t need to create a separate named class for simple, one-time use.
Limitations:
Anonymous classes cannot have constructors.
They can only extend one class or implement one interface at a time.
When to Use:
Use anonymous classes for simple, temporary implementations.
Avoid them for complex logic, as it can reduce code readability.
Anonymous Classes vs Lambda Expressions
In Java 8 and later, lambda expressions are preferred over anonymous classes for functional interfaces (interfaces with only one abstract method), as they make the code more concise and readable. For interfaces with multiple methods, anonymous classes are still required.
How Do They Relate?
Lambda expressions can only be used with functional interfaces.
The lambda provides the implementation of the single abstract method in the functional interface.
Real-Time Project Example
Let’s consider a real-world scenario: Processing a List of Employees
Project Context:
You are working on an HR management system.
You need to filter employees based on different criteria like age, department, or salary.
Without Lambda Expressions (Verbose Approach)
java
Copy code
import java.util.ArrayList;
import java.util.List;
public class EmployeeFilter {
public static void main(String[] args) {
List<Employee> employees = List.of(
new Employee("Alice", 30, "IT", 60000),
new Employee("Bob", 45, "HR", 50000),
new Employee("Charlie", 25, "IT", 70000)
);
// Filter employees aged above 30
List<Employee> filtered = filterEmployees(employees, new EmployeeCriteria() {
@Override
public boolean test(Employee e) {
return e.getAge() > 30;
}
});
System.out.println(filtered);
}
// Method to filter employees
public static List<Employee> filterEmployees(List<Employee> employees, EmployeeCriteria criteria) {
List<Employee> result = new ArrayList<>();
for (Employee e : employees) {
if (criteria.test(e)) {
result.add(e);
}
}
return result;
}
}
// Functional Interface
interface EmployeeCriteria {
boolean test(Employee e);
}
// Employee Class
class Employee {
private String name;
private int age;
private String department;
private double salary;
public Employee(String name, int age, String department, double salary) {
this.name = name;
this.age = age;
this.department = department;
this.salary = salary;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
With Lambda Expressions (Simpler Approach)
java
Copy code
import java.util.ArrayList;
import java.util.List;
public class EmployeeFilter {
public static void main(String[] args) {
List<Employee> employees = List.of(
new Employee("Alice", 30, "IT", 60000),
new Employee("Bob", 45, "HR", 50000),
new Employee("Charlie", 25, "IT", 70000)
);
// Filter employees aged above 30 using lambda
List<Employee> filtered = filterEmployees(employees, e -> e.getAge() > 30);
System.out.println(filtered);
}
// Method to filter employees
public static List<Employee> filterEmployees(List<Employee> employees, EmployeeCriteria criteria) {
List<Employee> result = new ArrayList<>();
for (Employee e : employees) {
if (criteria.test(e)) {
result.add(e);
}
}
return result;
}
}
// Functional Interface
interface EmployeeCriteria {
boolean test(Employee e);
}
// Employee Class
class Employee {
private String name;
private int age;
private String department;
private double salary;
public Employee(String name, int age, String department, double salary) {
this.name = name;
this.age = age;
this.department = department;
this.salary = salary;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
Explanation of Code
Functional Interface:
The EmployeeCriteria interface is a functional interface because it has only one abstract method, test(Employee e).Lambda Expression:
Instead of creating an anonymous class to implement the test method, we use a lambda expression: e -> e.getAge() > 30.Concise and Readable:
The lambda expression makes the code concise and more readable.
You can change the filter criteria easily by just modifying the lambda, e.g., e -> e.getSalary() > 50000.
Summary
A functional interface provides the "blueprint" for a lambda expression.
A lambda expression is the implementation of the functional interface’s single abstract method.
Together, they simplify tasks like filtering, sorting, or transforming data in a functional programming style.
This combination is powerful in real-time projects where readability, maintainability, and concise coding are crucial.
0 Comments