A lambda expression is the representation of anonymous function(function that doesn't have any function name)lambda expression is key feature of functional programming. Functional programming is followed by declarative programming approach .
Declarative programming: Declarative programming is a programming approach where main focus is on what is need but not how to do .
Now lets have an example where we want to filter Contact information based on certain criteria .
Model:
@Getter
@Setter
@ToString
public class Contact {
public enum Gender {
MALE, FEMALE
};
private String name;
private String email;
private int age;
private Gender gender;
public Contact(String name, String email, int age, Gender gender) {
this.name = name;
this.email = email;
this.age = age;
this.gender = gender;
}
}
Now we want to filter those contact whose age is greater than 18 and less than 25 and gender MALE.
So what can we do ?
Ans: We can create a ContactFilterService class that will filter and return filtered contacts.
public class ContactFilterService {
public List<Contact> findContactsAgeBetween18to25AndMale(List<Contact> contacts) {
List<Contact> filteredContacts = new ArrayList<>();
for (Contact contact : contacts) {
if (18 <= contact.getAge() && contact.getAge() <= 25
&& contact.getGender() == Gender.MALE) {
filteredContacts.add(contact);
}
}
return filteredContacts;
}
}
Now I want to filter contacts where age is age is greater than 18 and less than 25 and gender FEMALE.
So we can can create another method to do that .
But ContactFilterService growing , because in every need we are creating new methods and we are duplicating code.
We can create a generic method in ContactFilterService class that only check the condition .
We don't want to modify this class every time . We want to pass the filter logic from outside of the class .
lets do that,
Interface:
public interface FilterCriteria {
boolean match(Contact contact);
}
ContactFilterService:
public class ContactFilterService {
public List<Contact> filter(List<Contact> contacts, FilterCriteria criteria) {
List<Contact> filteredContacts = new ArrayList<>();
for (Contact contact : contacts) {
if (criteria.match(contact)) {
filteredContacts.add(contact);
}
}
return filteredContacts;
}
}
MainApp:
public class MainApp {
public static void main(String[] args) {
Contact contact1 = new Contact("rupta", "rupta@gmail.com", 25, Contact.Gender.FEMALE);
Contact contact2 = new Contact("asik", "asik@gmail.com", 30, Contact.Gender.MALE);
Contact contact3 = new Contact("ruhul", "ruhul@gmail.com", 22, Contact.Gender.MALE);
Contact contact4 = new Contact("nusrat", "nusrat@gmail.com", 31, Contact.Gender.FEMALE);
List<Contact> contacts = Arrays.asList(contact1, contact2, contact3, contact4);
ContactFilterService contactFilterService = new ContactFilterService();
List<Contact> filterdList = contactFilterService.filter(contacts, new FilterCriteria() {
@Override
public boolean match(Contact contact) {
if(18 <= contact.getAge() && contact.getAge() <= 25) {
return true;
}
return false;
}
});
System.out.println(filterdList);
}
}
}
Here we are just passing our logic into ContactFilterService filter() method.
So we no need to create new method every time .
Now we have solved one problem but we still implementing anonymous inner class as boilerplate code.
every time we are writing new FilterCriteria() and @Override and return type of the function.
So here we can pass lambda expression.
lets refactor our code,
List<Contact> filterdList = contactFilterService.filter(contacts, (Contact contact) -> {
return 18 <= contact.getAge() && contact.getAge() <= 25;
});
System.out.println(filterdList);
Here lamda expression,
(Contact contact) -> {
return 18 <= contact.getAge() && contact.getAge() <= 25;
}
But think in mind ,
Lambda expression will apply in Functional Interface only .
A functional interface only have one abstract method.
The type of lambda expression is functional interface(interface that has at least an abstract method).
The target type of the lambda expression is functional interface .