Chapter 6 Lambdas and Functional Interfaces Flashcards
Lambdas and Functional Interfaces
In Java 8, the language added the ability to write code using another style.
Functional programming is a way of writing code more declaratively.
You specify what you want to do rather than dealing with the state of objects.
You focus more on expressions than loops.
Functional programming uses lambda expressions to write code.
A lambda expression is a block of code that gets passed around.
You can think of a lambda expression as an unnamed method.
It has parameters and a body just like full-fledged methods do, but it doesn’t have a name like a real method.
Lambda expressions are often referred to as lambdas for short.
You might also know them as closures if Java isn’t your first language. If you had a bad experience with closures in the past, don’t worry. They are far simpler in Java.
Deferred execution means that code is specified now but will run later.
Lambdas work with interfaces that have only one abstract method.
Java relies on context when figuring out what lambda expressions mean.
The syntax of lambdas is tricky because many parts are optional.
These two lines do the exact same thing:
~~~
a -> a.canHop()
(Animal a) -> { return a.canHop(); }
~~~
Lambda syntax omitting optional parts
* A single parameter specified with the name a
* The arrow operator to separate the parameter and body
* A body that calls a single method and returns the result of that method
a -> a.canHop()
example shows the most verbose form of a lambda that returns a boolean:
* A single parameter specified with the name a and stating the type is Animal
* The arrow operator to separate the parameter and body
* A body that has one or more lines of code, including a semicolon and a return statement
(Animal a) -> { return a.canHop(); }
The parentheses can be omitted only if there is a single parameter and its type is not explicitly stated.
What is different here is that the rules change when you omit the braces.
Java doesn’t require you to type return or use a semicolon when no braces are used.
This special shortcut doesn’t work when we have two or more statements. At least this is consistent with using {} to create blocks of code elsewhere.
Here’s a fun fact: s -> {} is a valid lambda.
If there is no code on the right side of the expression, you don’t need the semicolon or return statement.
Valid Lambdas
~~~
() -> true // 0 parameter
a -> a.startsWith(“test”) //1 parameter, one parameter and doesn’t specify the type.
(String a) -> a.startsWith(“test”) //1 parameter
(a, b) -> a.startsWith(“test”) //2 parameters
((String a, String b) ->
a.startsWith(“test”)a, b) -> a.startsWith(“test”) //2 parameters
~~~
Invalid lambda
~~~
a, b -> a.startsWith(“test”) //Missing parentheses
a -> { a.startsWith(“test”); } //Missing return
a -> { return a.startsWith(“test”)
} //Missing semicolon
~~~
Functional Interfaces
Lambdas work with interfaces that have only one abstract method. These are called functional interfaces.
functional interface has only one abstract method.
Your friend Sam can help you remember this because it is officially known as a Single Abstract Method (SAM) rule.
Single Abstract Method (SAM) rule.
Java provides an annotation @FunctionalInterface on some, but not all, functional interfaces. This annotation means the authors of the interface promise it will be safe to use in a lambda in the future. However, just because you don’t see the annotation doesn’t mean it’s not a functional interface. Remember that having exactly one abstract method is what makes it a functional interface, not the annotation.
There are four functional interfaces you are likely to see on the exam. The next sections take a look at Predicate, Consumer, Supplier, and Comparator.
PREDICATE
It’s in the package java.util.function and the gist
of it is as follows:
public interface Predicate<T> { boolean test(T t); }
CONSUMER
The Consumer functional interface has one method you need to know:void accept(T t)
SUPPLIER
The Supplier functional interface has only one method:T get()
A good use case for a Supplier is when generating values.
COMPARATOR
The Comparator rules.
A negative number means the first value is smaller,
zero means they are equal,
and a positive number means the first value is bigger.
The method signature is as follows:int compare(T o1, T o2)
This interface is a functional interface since it has only one unimplemented method.
It has many static and default methods to facilitate writing complex comparators.
The Comparator interface existed prior to lambdas being added to Java.
As a result, it is in a different package. You can find Comparator in java.util.
Can you figure out whether this sorts in ascending or descending order?
Comparator<Integer> ints = (i1, i2) -> i1 - i2;
The ints comparator uses natural sort order.
If the first number is bigger, it will return a positive number.
Try it. Suppose we are comparing 5 and 3.
The comparator subtracts 5-3 and gets 2. This is a positive number that means the first number is bigger and we are sorting in ascending order.
Do you think these two statements would sort in ascending or descending order?
Comparator<String> strings = (s1, s2) -> s2.compareTo(s1); Comparator<String> moreStrings = (s1, s2) -> - s1.compareTo(s2);
Both of these comparators actually do the same thing: sort in descending order. In the first example, the call to compareTo() is “backwards,” making it descending.
In the second example, the call uses the default order; however, it applies a negative sign to the result, which reverses it.
Basic functional interfaces
- Comparator, 2 parameters, return int
- Consumer, 1 parameter, not return (void)
- Predicate, 1 parameter, return boolean
- Supplier, no parameter, type varies return