Java Fundamentals. Lesson 18_ Simple Lambda Expressions
Java Fundamentals. Lesson 18_ Simple Lambda Expressions
Lambda expressions are anonymous methods (methods without names) used to implement a method
defined by a functional interface.
A functional interface is an interface that contains one and only one abstract method.
@FunctionalInterface
interface NumberValidator {
boolean validate(int n);
}
Coding without lambda expressions
To use the interface EmpValidator you should define a class that implements it.
@Override
public boolean validate(Emp emp) {
return (emp.getPerformanceRating() >= 5);
}
}
Coding without lambda expressions
What happens if you want to check another attribute of an Emp instance, say, name?
@Override
public boolean validate(Emp emp) {
return (emp.getName.startsWith("P"));
}
}
Note how just the boolean condition is changing in the check methods in the classes ValidateName
and ValidatePerformanceRating.
Coding without lambda expressions
class Test {
public static void main(String args[]) {
Emp e1 = new Emp("Shreya", 5);
Emp e2 = new Emp("Paul", 4);
You’ll need to create multiple classes (that implement the interface EmpValidator) to use different
validity rules. Apart from being mostly repetitive, it’s verbose too.
To define the validation condition, we’ll use lambdas (continued on next slide):
Coding with lambda expressions
class Test {
public static void main(String args[]) {
Emp e1 = new Emp("Shreya", 5);
Emp e2 = new Emp("Paul", 4);
In the preceding code, there isn’t any change to the method filter that accepts a method parameter of
type EmpValidator (an interface).
The code defines a lambda expression. It defines code to be passed to the method filter.
vs
- The method validate accepts only one method parameter and so does the lambda expression,
that is, (emp).
- The method validate returns a boolean value and so does the expression
emp.getPerformanceRating() >= 5 in the lambda expression.
Syntax of lambda expressions
Lambda expressions introduce the new arrow operator '->' into Java. It divides the lambda expressions
in two parts:
The left side specifies the parameters required by the expression, which could also be empty if no
parameters are required.
The right side is the lambda body which specifies the actions of the lambda expression.
Syntax of lambda expressions
The return value of the lambda expression must match or must be compatible with the return value of
the abstract method defined in the interface.
Incorrect use of a lambda expression
● () -> { do something }
● (int a) -> { do something }
● (int a, int b ,……,n) -> { do something }
Some facts about lambda expressions
Parameters, if there are more than one, must be enclosed in parenthesis and also must be separated with
commas:
● a -> { do something }
Some facts about lambda expressions
When there is a single statement in its body, curly brackets are not mandatory.
However, if the lambda expression needs to contain several statements, then they must be wrapped
within curly brackets and an explicit return statement must be declared.
a -> {
System.out.println(“Inside lambda expressions”);
return a > 45;
}
Some facts about lambda expressions
Lambdas are allowed to access variables like any other ordinary method does.
Let’s pretend that there are valid interfaces that can consume a lambda with zero, one, or two String
parameters. Here’s how lambda expressions might look like:
Java 8 Method Reference
Java 8 Method Reference
A method reference is the shorthand syntax for a lambda expression that executes just ONE method.
In a method reference, you place the object or class that contains the method before the :: (double
colon) operator and the name of the method after it without arguments.
Java 8 Method Reference
Notice that between a static method and a static method reference, instead of the . (dot) operator,
we use the :: (double colon) operator, and that we don't pass arguments to the method reference.
I. Static method reference
We’ll begin with a very simple example, capitalizing and printing a list of Strings:
We can achieve this by leveraging a simple lambda expression calling the StringUtils.capitalize()
method directly:
Or, we can use a method reference to simply refer to the capitalize static method:
messages.forEach(StringUtils::capitalize);
II. Instance method reference of an object of a particular type
where an instance of an object is passed, and one of its methods is executed with some optional(s)
parameter(s).
If we use a classic lambda expression, the parameter needs to be explicitly passed, while using a method
reference is much more straightforward:
// Method reference
people.forEach(Person::printName);
// Lambda expression
people.forEach(person -> person.printName());
III. Instance method reference of an existing object
// Method reference
Collections.sort(list, myComparator::compare);
// Lambda expression
Collections.sort(list, (a,b) -> myComparator.compare(a,b));
IV. Constructor method reference
The only thing this lambda expression does is to create a new object and we just reference a constructor
of the class with the keyword new.
IV. Constructor method reference
Let’s create a Bicycle array out of a String list with different brands:
List<String> bikeBrands = Arrays.asList("Giant", "Scott", "Trek", "GT");
Next, we’ll use our new constructor from a method reference and make a Bicycle array from the original
String list:
bikeBrands.stream().map(Bicycle::new).toArray(Bicycle[]::new);
Interface Predicate
Interface Predicate
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the
predicate,
* otherwise {@code false}
*/
boolean test(T t);
Interface Predicate
In the preceding code, the class declaration includes <T>, which declares that Predicate is a generic
interface, which isn’t limited to a particular type. It can be used with multiple types.
To use Predicate in your code, your method must accept a parameter of type Predicate and you
must use its public method test to evaluate an argument.
Interface Predicate
class Test {
public static void main(String args[]) {
Emp e1 = new Emp("Shreya", 5);
Emp e2 = new Emp("Paul", 4);
Java 8 has also modified many of its existing API methods, which work with functional interfaces like
Predicate. For example, the class ArrayList defines the method removeIf, which accepts a method
parameter of type Predicate.
// Creating predicate
Predicate<Integer> lessThan = i -> (i < 18);
validateNumber(10, greaterThanZero);
validateNumber(10, a -> a != 0);
// Creating predicate
Predicate<Integer> greaterThanTen = num -> num > 10;
Predicate<Integer> lowerThanTwenty = num -> num < 20;
// Creating predicate
Predicate<String> hasLengthOf10 = str -> str.length() > 10;
Predicate<String> containsLetterA = str -> str.contains("A");
√
Q&A #2
√
Exercise #18.1
Define an interface that would help validating a number against different conditions:
a. Create appropriate validator classes and make sure they work as expected.
b. Implement an alternative for the validators built in #a, using Java lambda expressions. Test them.
c. Implement the same validation rules, using the Predicate interface.
Exercise #18.2
Define an interface that would help validating a String against different conditions:
a. Create appropriate validator classes and make sure they work as expected.
b. Implement an alternative for the validators built in #a, using Java lambda expressions. Test them.
c. Implement the same validation rules, using the Predicate interface.
Resources
Lambda expressions
(https://howtodoinjava.com/java8/lambda-expressions/)
Java Predicate
(https://www.concretepage.com/java/java-8/java-predicate)
Java Fundamentals
Lesson 18: Simple Lambda Expressions
End.