Section D.2 Higher Order Functions
When processing a collection of data, we often want to keep only certain items from that collection. For example, we might want to keep only negative values and discard non-negative values when going through a list of debits and credits. Or, we might want to keep only strings that have more than ten characters when selecting a password. This process is also called filtering; we are “filtering out” the values we don’t want.
Consider the following program that implements three methods that take an
ArrayList
and create a new ArrayList
that retains only specific elements of the original list. The first method will keep only the even elements. The second method keeps only the negative elements, and the third method keeps only the two-digit numbers from the original list:That’s a lot of duplicated code! Wouldn’t it be nice if there were some way to have a program like this, where we pass the “testing” code as a parameter (and also use a generic type so that we can use it on an
ArrayList
of any type):Spoiler alert: Yes, it would be nice. And that’s what we’re going to examine in this section: Higher Order Functions, which give us the ability to pass methods as parameters to other methods. Higher order functions are a core concept in functional programming.
Subsection D.2.1 Predicates
We will use the
Predicate
class to implement our higher order function. A predicate is another name for a boolean method. (This isn’t like a predicate in an English sentence; it means something is conditional, or predicated on something else.)Let’s start with the code for our new
keep
method. It will have two parameters: an ArrayList<T>
and a Predicate<T>
, which will be our boolean method. We’ll have to import java.util.function.Predicate
. The Predicate
class uses a generic to specify what kind of value is being tested, and it contains a test
method that invokes the method passed to it:Note D.2.5.
Although we usually want meaningful variable names, the predicate can be virtually anything, so there is really no good descriptive name for it. Thus we’ll go with
p
. We could also have used pred
to be a bit more specific; use whichever name you prefer in your code.Subsection D.2.2 Lambda Expressions
Now that we have a method that requires a
Predicate<T>
, let’s look at the main
method. This is where we will use lambda expressions to specify the code we want to pass to a method.In essence, a lambda expression is a method without a name. There are many different ways to write a lambda expression, but we’ll stick with one format for the sake of simplicity and not go into all the possible shortcuts. Let’s look at a boolean method for determining whether a number is even or not:
To convert this method into a lambda expression, we get rid of the return type and the name, and insert an arrow operator
->
before the opening brace:We can now put that into our
main
method:You may have noticed that it’s a bit tricky to keep track of the braces and parentheses in the call to
keep
in lines 5-8. Let’s do the lambda expression for testing negative numbers as a separate entity. We’ll have to assign it to a Predicate<Integer>
variable, because that is what keep
expects. Add this code before the end of main
:And we’ll do the same for our lambda expression to test if the number is a two-digit number or not:
Here’s the entire program:
You have attempted of activities on this page.