Lambda Expressions
Lambda expressions, which were introduced in Java 8, are a concise way
of expressing anonymous functions. Lambda expressions allow you to
treat behavior as data, making it easier to pass it as arguments to methods or
store it in variables. They were added in Java 8 to help with functional
programming in the language.
Lambda expressions consist of three main components:
- Parameters: These are the lambda expression's input arguments. They can have a value of zero or more and are specified within parentheses. When there is only one parameter, the brackets are not required. Even if there are no parameters, you must use empty brackets.
- Arrow Operator (->): This detaches the parameters from the lambda expression's body. It's called the "arrow operator" because it resembles an arrow pointing from the parameters to the body.
- Body: This is the code that will be run when the lambda expression is called. It can be a single statement or a block of code surrounded by curly braces. If it's a single expression, the lambda's return value is the expression's value. If it's a block of code, you can specify the return value explicitly with a return statement.
First, we'll write a simple Java program that doesn't use a Lambda expression.
It's right here:
public class HelloWorld implements IIncrement, IConcatenate {
public static void main(String[] args) {
HelloWorld helloWorld = new HelloWorld();
System.out.println("Number increment :: " + helloWorld.increment(10));
System.out.println("String concatenation :: " + helloWorld.concatenate("Hello", "World!!!"));
}
@Override
public int increment(int a) {
return a + 5;
}
@Override
public String concatenate(String a, String b) {
return a + " " + b;
}
}
interface IIncrement {
int increment(int a);
}
interface IConcatenate {
String concatenate(String a, String b);
}
Output
Number increment :: 15
String concatenation :: Hello World!!!
The preceding code is an example of a traditional Java program in which the
HelloWorlds class implements two interfaces: IIncrement and
IConcatenate. It exemplifies imperative programming.
We will now rewrite the preceding code using the Lambda expression:
public class HelloWorld {
public static void main(String[] args) {
IIncrement increment = (a) -> {
return a + 5;
};
System.out.println("Number increment :: " + increment.increment(10));
IConcatenate concatenate = (a, b) -> {
return a + " " + b;
};
System.out.println("String concatenation :: " + concatenate.concatenate("Hello", "World!!!"));
}
}
interface IIncrement {
int increment(int a);
}
interface IConcatenate {
String concatenate(String a, String b);
}
Output
Number increment :: 15
String concatenation :: Hello World!!!
We have two interfaces here: IIncrement and IConcatenate, which
have abstract methods increment(int a) and
concatenate(String a, String b). We used the Lambda expression to
create instances of these interfaces within the main method. In contrast to
the previous program, the HelloWorld class does not implement the
interfaces. We have only provided the implementation of the interfaces'
methods here.
Here's another example of how to use the lambda expression to create a Thread.
public class ThreadLambdaExpressionExample {
public static void main(String args[]) {
Runnable runnable1 = () -> {
int sum = 0;
for (int i = 0; i < 10; i++) {
if(i%2 == 0){
sum += i;
}
}
System.out.println("Sum of even numbers :: " + sum);
};
(new Thread(runnable1)).start();
(new Thread(() -> {
int sum = 0;
for (int i = 0; i < 10; i++) {
if(i%2 != 0){
sum += i;
}
}
System.out.println("Sum of odd numbers :: " + sum);
})).start();
}
}
Output
Sum of even numbers :: 20
Sum of odd numbers :: 25
Functional Interface
The concept of a functional interface is closely related to the
concept of functional programming, which emphasizes writing
programs with pure functions and treating functions as first-class
citizens. A functional interface is one that has only one abstract
method, which is known as the functional method.
To define a functional interface, you must use the
@FunctionalInterface annotation, which is optional. This annotation is
not required, but using it ensures that the interface has only one abstract
method. If the interface contains more than one abstract method, the compiler
will generate an error.
We have interfaces with only one abstract method in the previous Lambda
expression example. Lambda expressions are frequently used with functional
interfaces. The context in which the lambda expression is used determines its
type, which is why it is critical to use functional interfaces that match the
lambda's signature.
In Java 8, the java.util.function package added several built-in
functional interfaces to cover various common use cases, such as
Consumer, Supplier, Predicate, Function, and so
on. These interfaces have already been annotated with
@FunctionalInterface and can be used with lambda expressions directly.
Function Interface
It denotes a function that accepts one argument and returns a result. It takes
two arguments: input and output. This interface has several
functional methods, including apply(object), andThen(object),
and compose(object). Now consider the Function interface example.
import java.util.function.Function;
public class FunctionInterfaceExample {
public static void main(String[] args) {
Function<Integer, Boolean> oddEvenFunction = (n) -> {
return (n%2 == 0 ? true : false);
};
System.out.println("Is 64 even number :: " + oddEvenFunction.apply(8));
Function<String, String> upperCaseFunction = (n) -> n.toUpperCase();
Function<String, String> concatFunction = (n) -> n.concat(" Interface");
System.out.println(upperCaseFunction.apply("functional programing"));
System.out.println(upperCaseFunction.andThen(concatFunction).apply("function"));
System.out.println(upperCaseFunction.compose(concatFunction).apply("function"));
}
}
Output
Is 64 even number :: true
FUNCTIONAL PROGRAMING
FUNCTION Interface
FUNCTION INTERFACE
The apply() method is used to invoke the function, which means
that the lambda expression contained within the function will be
executed. The apply() method is also used to pass a value
to a specific function.
The andThen() and compose() methods are used to
connect multiple functions to achieve a specific result.
When we use the andThen() method to connect two functions, the
parameterized function that we passed into andThen() is
executed after the first function. So, in this case,
upperCaseFunction will run first, followed by concatFunction.
In the case of the compose() method, the
parameterized function that we passed in will be executed first,
followed by the first function. So concatFunction will be executed
first, followed by upperCaseFunction.
Movie List
We've written a static method that returns a list of Movies. This movie list
is used later in the tutorial.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MovieList {
public static List<Movie> getMovieList() {
List<Movie> movieList = new ArrayList<>();
Movie movie = new Movie("Guardians of the Galaxy", "Sci-Fi", "2014",
121, 8.1, 757074, 333.13,
Arrays.asList("Chris Pratt", "Vin Diesel", "Bradley Cooper", "Zoe Saldana"));
movieList.add(movie);
movie = new Movie("Prometheus", "Sci-Fi", "2012",
124, 7, 485820, 126.46,
Arrays.asList("Noomi Rapace", "Logan Marshall-Green", "Michael Fassbender", "Charlize Theron"));
movieList.add(movie);
movie = new Movie("Split", "Horror", "2016",
117, 7.3, 157606, 138.12,
Arrays.asList("James McAvoy", "Anya Taylor-Joy", "Haley Lu Richardson", "Jessica Sula"));
movieList.add(movie);
movie = new Movie("Passengers", "Adventure", "2016",
116, 7, 192177, 100.01,
Arrays.asList("Jennifer Lawrence", "Chris Pratt", "Michael Sheen", "Laurence Fishburne"));
movieList.add(movie);
movie = new Movie("Frozen", "Animation", "2013",
102, 7.5, 451894, 400.74,
Arrays.asList("Kristen Bell", "Idina Menzel", "Jonathan Groff", "Josh Gad"));
movieList.add(movie);
movie = new Movie("12 Years a Slave", "Drama", "2013",
134, 8.1, 486338, 56.67,
Arrays.asList("Chiwetel Ejiofor", "Michael Kenneth Williams", "Michael Fassbender", "Brad Pitt"));
movieList.add(movie);
movie = new Movie("Into the Woods", "Drama", "2014",
125, 6, 109756, 128,
Arrays.asList("Anna Kendrick", "Meryl Streep", "Chris Pine", "Emily Blunt"));
movieList.add(movie);
return movieList;
}
}
class Movie {
String name;
String genre;
String year;
int lengthMinutes;
double rating;
int votes;
double revenue;
List<String> actors;
public Movie(String name, String genre, String year, int lengthMinutes, double rating, int votes, double revenue,
List<String> actors) {
this.name = name;
this.genre = genre;
this.year = year;
this.lengthMinutes = lengthMinutes;
this.rating = rating;
this.votes = votes;
this.revenue = revenue;
this.actors = actors;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGenre() {
return genre;
}
public void setGenre(String genre) {
this.genre = genre;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
public int getLengthMinutes() {
return lengthMinutes;
}
public void setLengthMinutes(int lengthMinutes) {
this.lengthMinutes = lengthMinutes;
}
public double getRating() {
return rating;
}
public void setRating(double rating) {
this.rating = rating;
}
public int getVotes() {
return votes;
}
public void setVotes(int votes) {
this.votes = votes;
}
public double getRevenue() {
return revenue;
}
public void setRevenue(double revenue) {
this.revenue = revenue;
}
public List<String> getActors() {
return actors;
}
public void setActors(List<String> actors) {
this.actors = actors;
}
@Override
public String toString() {
return "Movie [name=" + name + ", genre=" + genre + ", year=" + year + ", lengthMinutes=" + lengthMinutes
+ ", rating=" + rating + ", votes=" + votes + ", revenue=" + revenue + ", actors=" + actors + "]";
}
}
Consumer Interface
The java.util.function package contains the
Consumer interface. Java 8 introduced the Consumer interface.
It's used in Java to implement functional programming.
It denotes a function that takes a single argument and returns a result. It has the following functional methods: accept() and
andThen(). Consider the following example of a consumer interface:
import java.util.function.Consumer;
public class ConsumerExample {
public static void main(String[] args) {
Consumer<String> messageConsumer = (a) -> {
System.out.println("Consumer returns :: " + a);
};
messageConsumer.accept("Hello from Consumer!!!");
Consumer<Integer> mathConsumer = (a) -> {
System.out.println("a*a = " + a * a);
};
mathConsumer.accept(4);
System.out.println("----------------------");
List<Movie> movieList = MovieList.getMovieList();
// consumer to get all movie details
Consumer<Movie> consumerMovie = (c) -> System.out.println(c);
movieList.forEach(consumerMovie);
System.out.println("----------------------------");
// consumer to get all movie names
Consumer<Movie> consumerName = (m) -> System.out.println(m.getName());
movieList.forEach(consumerName);
System.out.println("----------------------------");
// consumer to get all movie name with it actor names
Consumer<Movie> consumerActors = (m) -> System.out.println(m.getActors());
movieList.forEach(consumerName.andThen(consumerActors));
System.out.println("----------------------------");
// movie details with genre 'Drama'
movieList.forEach(cons -> {
if (cons.getGenre().equals("Drama")) {
consumerMovie.accept(cons);
}
});
System.out.println("----------------------------");
// movie name and actor with genre 'Drama' and rating is greater than 6
movieList.forEach(cons -> {
if (cons.getGenre().equals("Drama") && cons.getRating() > 6) {
consumerName.andThen(consumerActors).accept(cons);
}
});
}
}
Output
Consumer returns :: Hello from Consumer!!!
a*a = 16
----------------------
Movies with it details ::
Movie [name=Guardians of the Galaxy, genre=Sci-Fi, year=2014, lengthMinutes=121, rating=8.1, votes=757074, revenue=333.13, actors=[Chris Pratt, Vin Diesel, Bradley Cooper, Zoe Saldana]]
Movie [name=Prometheus, genre=Sci-Fi, year=2012, lengthMinutes=124, rating=7.0, votes=485820, revenue=126.46, actors=[Noomi Rapace, Logan Marshall-Green, Michael Fassbender, Charlize Theron]]
Movie [name=Split, genre=Horror, year=2016, lengthMinutes=117, rating=7.3, votes=157606, revenue=138.12, actors=[James McAvoy, Anya Taylor-Joy, Haley Lu Richardson, Jessica Sula]]
Movie [name=Passengers, genre=Adventure, year=2016, lengthMinutes=116, rating=7.0, votes=192177, revenue=100.01, actors=[Jennifer Lawrence, Chris Pratt, Michael Sheen, Laurence Fishburne]]
Movie [name=Frozen, genre=Animation, year=2013, lengthMinutes=102, rating=7.5, votes=451894, revenue=400.74, actors=[Kristen Bell, Idina Menzel, Jonathan Groff, Josh Gad]]
Movie [name=12 Years a Slave, genre=Drama, year=2013, lengthMinutes=134, rating=8.1, votes=486338, revenue=56.67, actors=[Chiwetel Ejiofor, Michael Kenneth Williams, Michael Fassbender, Brad Pitt]]
Movie [name=Into the Woods, genre=Drama, year=2014, lengthMinutes=125, rating=6.0, votes=109756, revenue=128.0, actors=[Anna Kendrick, Meryl Streep, Chris Pine, Emily Blunt]]
----------------------------
Only movie names ::
Guardians of the Galaxy
Prometheus
Split
Passengers
Frozen
12 Years a Slave
Into the Woods
----------------------------
Movie names with its actors ::
Guardians of the Galaxy
[Chris Pratt, Vin Diesel, Bradley Cooper, Zoe Saldana]
Prometheus
[Noomi Rapace, Logan Marshall-Green, Michael Fassbender, Charlize Theron]
Split
[James McAvoy, Anya Taylor-Joy, Haley Lu Richardson, Jessica Sula]
Passengers
[Jennifer Lawrence, Chris Pratt, Michael Sheen, Laurence Fishburne]
Frozen
[Kristen Bell, Idina Menzel, Jonathan Groff, Josh Gad]
12 Years a Slave
[Chiwetel Ejiofor, Michael Kenneth Williams, Michael Fassbender, Brad Pitt]
Into the Woods
[Anna Kendrick, Meryl Streep, Chris Pine, Emily Blunt]
----------------------------
Movies with specific genre ::
Movie [name=12 Years a Slave, genre=Drama, year=2013, lengthMinutes=134, rating=8.1, votes=486338, revenue=56.67, actors=[Chiwetel Ejiofor, Michael Kenneth Williams, Michael Fassbender, Brad Pitt]]
Movie [name=Into the Woods, genre=Drama, year=2014, lengthMinutes=125, rating=6.0, votes=109756, revenue=128.0, actors=[Anna Kendrick, Meryl Streep, Chris Pine, Emily Blunt]]
----------------------------
Movies with a particular genre and rating ::
12 Years a Slave
[Chiwetel Ejiofor, Michael Kenneth Williams, Michael Fassbender, Brad Pitt]
----------------------------
The accept() method operates on the given argument. The
andThen() method returns a Consumer that performs this
operation first, followed by the after operation.
BiConsumer Interface
The BiConsumer interface is included in the
java.util.function package. The BiConsumer interface has been available
since Java 8. It is used to implement functional programming in Java. It
represents a function that takes two arguments and returns a result. It
is similar to the Consumer interface, with the exception that it takes
two arguments. Consider the following example:
import java.util.function.BiConsumer;
public class BiConsumerExample {
public static void main(String[] args) {
// printing two numbers
BiConsumer<Integer, Integer> simpleBiConsumer =
(x, y) -> System.out.println(x + ", " + y);
simpleBiConsumer.accept(23, 32);
// sum of two numbers
BiConsumer<Integer, Integer> mathBiConsumer =
(x, y) -> System.out.println("Sum :: " + (x + y));
mathBiConsumer.accept(23, 32);
System.out.println("-------------------------------");
List<Movie> movieList = MovieList.getMovieList();
System.out.println("Movie name with year :: ");
BiConsumer<String, String> movieBiConsumer = (name, year) -> System.out.println(name + " (" + year + ")");
movieList.forEach(movie -> {
movieBiConsumer.accept(movie.getName(), movie.getYear());
});
}
}
Output
23, 32
Sum :: 55
-------------------------------
Movie name with year ::
Guardians of the Galaxy (2014)
Prometheus (2012)
Split (2016)
Passengers (2016)
Frozen (2013)
12 Years a Slave (2013)
Into the Woods (2014)
Predicate Interface
Predicate is Java 8 functional interfaces.
A predicate is a function with a single argument that returns true or
false. The test method of Predicate returns true or false. Predicate is a simple
statement that determines whether the opinions are true or false based on
arguments. It has the following functional methods: test(),
and(), or() and negate(). Consider the following
example:
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args) {
Predicate<Integer> greaterThan = (x) -> x > 30;
System.out.println("Is greater than : " + greaterThan.test(100));
Predicate<Integer> checkEven = (x) -> x % 2 == 0;
System.out.println("Is even : " + checkEven.test(60));
System.out.println("Negate : " + checkEven.negate().test(60));
// both the conditions are true
System.out.println("Chaining with and : " + greaterThan.and(checkEven).test(40));
// any one condition is true
System.out.println("Chaining with or : " + greaterThan.or(checkEven).test(25));
// both the conditions are !true
System.out.println("Chaining with negate : " + greaterThan.and(checkEven.negate()).test(28));
System.out.println("-------------------------------");
List<Movie> movieList = MovieList.getMovieList();
Predicate<Movie> checkRating = (m) -> m.getRating() >= 7;
Predicate<Movie> checkRevenue = (m) -> m.getRevenue() > 130;
Predicate<Movie> checkGenre = (m) -> m.getGenre().equals("Drama");
// movies with rating > 7 && revenue > 130
movieList.forEach(m -> {
if (checkRating.and(checkRevenue).test(m)) {
System.out.println(m);
}
});
System.out.println("-------------------------------");
// movies with genre = 'Drama' && rating > 7
movieList.forEach(m -> {
if (checkGenre.and(checkRating).test(m)) {
System.out.println(m);
}
});
System.out.println("-------------------------------");
// movies with genre = 'Drama' && !rating > 7
movieList.forEach(m -> {
if (checkGenre.and(checkRating.negate()).test(m)) {
System.out.println(m);
}
});
}
}
Output
Is greater than : true
Is even : true
Negate : false
Chaining with and : true
Chaining with or : false
Chaining with negate : false
-------------------------------
Movie [name=Guardians of the Galaxy, genre=Sci-Fi, year=2014, lengthMinutes=121, rating=8.1, votes=757074, revenue=333.13, actors=[Chris Pratt, Vin Diesel, Bradley Cooper, Zoe Saldana]]
Movie [name=Split, genre=Horror, year=2016, lengthMinutes=117, rating=7.3, votes=157606, revenue=138.12, actors=[James McAvoy, Anya Taylor-Joy, Haley Lu Richardson, Jessica Sula]]
Movie [name=Frozen, genre=Animation, year=2013, lengthMinutes=102, rating=7.5, votes=451894, revenue=400.74, actors=[Kristen Bell, Idina Menzel, Jonathan Groff, Josh Gad]]
-------------------------------
Movie [name=12 Years a Slave, genre=Drama, year=2013, lengthMinutes=134, rating=8.1, votes=486338, revenue=56.67, actors=[Chiwetel Ejiofor, Michael Kenneth Williams, Michael Fassbender, Brad Pitt]]
-------------------------------
Movie [name=Into the Woods, genre=Drama, year=2014, lengthMinutes=125, rating=6.0, votes=109756, revenue=128.0, actors=[Anna Kendrick, Meryl Streep, Chris Pine, Emily Blunt]]
The test() method evaluates the predicate on the given argument.
The and() method returns a composed predicate representing a
logical AND of this predicate and another. or() method returns a composed predicate representing a short-circuiting
logical OR of this and another predicate. The negate() method
returns a predicate representing the logical inverse of this predicate.
BiPredicate Interface
BiPredicate is a functional interface in Java 8. It is similar
to the Predicate interface except that it accepts two arguments.
Consider the following example:
public class BiPredicateExample {
public static void main(String[] args) {
List<Movie> movieList = MovieList.getMovieList();
// bipredicate with rating >= 7 && revenue > 130
BiPredicate<Double, Double> biPredicate = (rating, revenue) -> rating >= 7 && revenue > 130;
// biconsumer to print movie name and its actors
BiConsumer<String, List<String>> biConsumer = (name, actors) -> {
System.out.println("Movie name : " + name);
System.out.println("Actors : " + actors);
};
movieList.forEach(m -> {
if (biPredicate.test(m.getRating(), m.getRevenue())) {
biConsumer.accept(m.getName(), m.getActors());
System.out.println("--------------------------------");
}
});
}
}
Output
Movie name : Guardians of the Galaxy
Actors : [Chris Pratt, Vin Diesel, Bradley Cooper, Zoe Saldana]
--------------------------------
Movie name : Split Actors : [James McAvoy, Anya
Taylor-Joy, Haley Lu Richardson, Jessica Sula]
--------------------------------
Movie name : Frozen
Actors : [Kristen Bell, Idina Menzel, Jonathan Groff, Josh Gad]
--------------------------------
Happy coding!!! 😊
More examples like Movie list
ReplyDeleteHowever, I don't understand why the lambda expression only allows pure functions. Is there a way to do impure operations in lambda?.. more about this topic please.
ReplyDelete