You are on page 1of 14

Lambda Expressions

One issue with anonymous classes is that if the implementation of your anonymous class
is very simple, such as an interface that contains only one method, then the syntax of
anonymous classes may seem unwieldy and unclear. In these cases, you're usually trying
to pass functionality as an argument to another method, such as what action should be
taken when someone clicks a button. Lambda expressions enable you to do this, to treat
functionality as method argument, or code as data.
The previous section, nonymous !lasses, shows you how to implement a base class
without giving it a name. lthough this is often more concise than a named class, for
classes with only one method, even an anonymous class seems a bit excessive and
cumbersome. Lambda expressions let you express instances of single"method classes
more compactly.
This section covers the following topics#
Ideal $se !ase for Lambda %xpressions
pproach &# !reate 'ethods That (earch for 'embers That 'atch One
!haracteristic
pproach )# !reate 'ore *enerali+ed (earch 'ethods
pproach ,# (pecify (earch !riteria !ode in a Local !lass
pproach -# (pecify (earch !riteria !ode in an nonymous !lass
pproach .# (pecify (earch !riteria !ode with a Lambda %xpression
pproach /# $se (tandard 0unctional Interfaces with Lambda %xpressions
pproach 1# $se Lambda %xpressions Throughout 2our pplication
pproach 3# $se *enerics 'ore %xtensively
pproach 4# $se ggregate Operations That ccept Lambda %xpressions
as 5arameters
Lambda %xpressions in *$I pplications
(yntax of Lambda %xpressions
ccessing Local 6ariables of the %nclosing (cope
Target Typing
Target Types and 'ethod rguments
(eriali+ation
Ideal Use Case for Lambda Expressions
(uppose that you are creating a social networking application. 2ou want to create a
feature that enables an administrator to perform any kind of action, such as sending a
message, on members of the social networking application that satisfy certain criteria.
The following table describes this use case in detail#
Field Description
7ame 5erform action on selected members
5rimary
ctor
dministrator
5recondit
ions
dministrator is logged in to the system.
5ostcondi
tions
ction is performed only on members that fit the specified criteria.
'ain
(uccess
(cenario
dministrator specifies criteria of members on which to perform a certain
action.
dministrator specifies an action to perform on those selected members.
dministrator selects the Submit button.
The system finds all members that match the specified criteria.
The system performs the specified action on all matching members.
%xtension
s
&a. dministrator has an option to preview those members who match the
specified criteria before he or she specifies the action to be performed or before
selecting the Submit button.
0re8uenc
y of
Occurren
ce
'any times during the day.
(uppose that members of this social networking application are represented by the
following Person class#
public class Person {
public enum Sex {
MALE, FEMALE
}
String name;
LocalDate birthda;
Sex gender;
String emailAddress;
public int getAge!" {
## $$$
}
public %oid printPerson!" {
## $$$
}
}
(uppose that the members of your social networking application are stored in a
List&Person' instance.
This section begins with a naive approach to this use case. It improves upon this approach
with local and anonymous classes, and then finishes with an efficient and concise
approach using lambda expressions. 0ind the code excerpts described in this section in
the example (oster)est.
Approach 1: Create Methods hat Search for Members hat Match
!ne Characteristic
One simplistic approach is to create several methods9 each method searches for members
that match one characteristic, such as gender or age. The following method prints
members that are older than a specified age#
public static %oid printPersons*lder)han!List&Person' roster, int age" {
+or !Person p , roster" {
i+ !p$getAge!" '- age" {
p$printPerson!";
}
}
}
"ote# List is an ordered .ollection. collection is an ob:ect that groups multiple
elements into a single unit. !ollections are used to store, retrieve, manipulate, and
communicate aggregate data. 0or more information about collections, see the !ollections
trail.
This approach can potentially make your application brittle, which is the likelihood of an
application not working because of the introduction of updates ;such as newer data
types<. (uppose that you upgrade your application and change the structure of the Person
class such that it contains different member variables9 perhaps the class records and
measures ages with a different data type or algorithm. 2ou would have to rewrite a lot of
your 5I to accommodate this change. In addition, this approach is unnecessarily
restrictive9 what if you wanted to print members younger than a certain age, for example=
Approach #: Create More $enerali%ed Search Methods
The following method is more generic than printPersons*lder)han9 it prints members
within a specified range of ages#
public static %oid printPersons/ithinAge(ange!
List&Person' roster, int lo0, int high" {
+or !Person p , roster" {
i+ !lo0 &- p$getAge!" 11 p$getAge!" & high" {
p$printPerson!";
}
}
}
>hat if you want to print members of a specified sex, or a combination of a specified
gender and age range= >hat if you decide to change the Person class and add other
attributes such as relationship status or geographical location= lthough this method is
more generic than printPersons*lder)han, trying to create a separate method for each
possible search 8uery can still lead to brittle code. 2ou can instead separate the code that
specifies the criteria for which you want to search in a different class.
Approach &: Specif' Search Criteria Code in a Local Class
The following method prints members that match search criteria that you specify#
public static %oid printPersons!
List&Person' roster, .hec2Person tester" {
+or !Person p , roster" {
i+ !tester$test!p"" {
p$printPerson!";
}
}
}
This method checks each Person instance contained in the List parameter roster
whether it satisfies the search criteria specified in the .hec2Person parameter tester by
invoking the method tester$test. If the method tester$test returns a true value,
then the method printPersons is invoked on the Person instance.
To specify the search criteria, you implement the .hec2Person interface#
inter+ace .hec2Person {
boolean test!Person p";
}
The following class implements the .hec2Person interface by specifying an
implementation for the method test. This method filters members that are eligible for
(elective (ervice in the $nited (tates# it returns a true value if its Person parameter is
male and between the ages of &3 and ).#
class .hec2PersonEligibleForSelecti%eSer%ice implements .hec2Person {
public boolean test!Person p" {
return p$gender -- Person$Sex$MALE 11
p$getAge!" '- 34 11
p$getAge!" &- 56;
}
}
To use this class, you create a new instance of it and invoke the printPersons method#
printPersons!
roster, ne0 .hec2PersonEligibleForSelecti%eSer%ice!"";
lthough this approach is less brittle?you don't have to rewrite methods if you change
the structure of the Person?you still have additional code# a new interface and a local
class for each search you plan to perform in your application. @ecause
.hec2PersonEligibleForSelecti%eSer%ice implements an interface, you can use an
anonymous class instead of a local class and bypass the need to declare a new class for
each search.
Approach (: Specif' Search Criteria Code in an Anon'mous Class
One of the arguments of the following invocation of the method printPersons is an
anonymous class that filters members that are eligible for (elective (ervice in the $nited
(tates# those who are male and between the ages of &3 and ).#
printPersons!
roster,
ne0 .hec2Person!" {
public boolean test!Person p" {
return p$get7ender!" -- Person$Sex$MALE
11 p$getAge!" '- 34
11 p$getAge!" &- 56;
}
}
";
This approach reduces the amount of code re8uired because you don't have to create a
new class for each search that you want to perform. Aowever, the syntax of anonymous
classes is bulky considering that the .hec2Person interface contains only one method. In
this case, you can use a lambda expression instead of an anonymous class, as described in
the next section.
Approach ): Specif' Search Criteria Code *ith a Lambda Expression
The .hec2Person interface is a functional interface. functional interface is any
interface that contains only one abstract method. ; functional interface may contain one
or more default methods or static methods.< @ecause a functional interface contains only
one abstract method, you can omit the name of that method when you implement it. To
do this, instead of using an anonymous class expression, you use a lambda expression,
which is highlighted in the following method invocation#
printPersons!
roster,
(Person p) -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25
";
(ee (yntax of Lambda %xpressions for information about how to define lambda
expressions.
2ou can use a standard functional interface in place of the interface .hec2Person, which
reduces even further the amount of code re8uired.
Approach +: Use Standard Functional Interfaces *ith Lambda
Expressions
Beconsider the .hec2Person interface#
inter+ace .hec2Person {
boolean test!Person p";
}
This is a very simple interface. It's a functional interface because it contains only one
abstract method. This method takes one parameter and returns a boolean value. The
method is so simple that it might not be worth it to define one in your application.
!onse8uently, the CDE defines several standard functional interfaces, which you can find
in the package 8a%a$util$+unction.
0or example, you can use the Predicate&)' interface in place of .hec2Person. This
interface contains the method boolean test!) t"#
inter+ace Predicate&)' {
boolean test!) t";
}
The interface Predicate&)' is an example of a generic interface. ;0or more information
about generics, see the *enerics ;$pdated< lesson.< *eneric types ;such as generic
interfaces< specify one or more type parameters within angle brackets ;&'<. This interface
contains only one type parameter, ). >hen you declare or instantiate a generic type with
actual type arguments, you have a parameteri+ed type. 0or example, the parameteri+ed
type Predicate&Person' is the following#
inter+ace Predicate&Person' {
boolean test!Person t";
}
This parameteri+ed type contains a method that has the same return type and parameters
as .hec2Person$boolean test!Person p". !onse8uently, you can use Predicate&)'
in place of .hec2Person as the following method demonstrates#
public static %oid printPersons/ithPredicate!
List&Person' roster, Predicate&Person' tester" {
+or !Person p , roster" {
i+ !tester$test!p"" {
p$printPerson!";
}
}
}
s a result, the following method invocation is the same as when you invoked
printPersons in pproach ,# (pecify (earch !riteria !ode in a Local !lass to obtain
members who are eligible for (elective (ervice#
printPersons/ithPredicate!
roster,
p 9' p$get7ender!" -- Person$Sex$MALE
11 p$getAge!" '- 34
11 p$getAge!" &- 56
";
This is not the only possible place in this method to use a lambda expression. The
following approach suggests other ways to use lambda expressions.
Approach ,: Use Lambda Expressions hrou-hout .our Application
Beconsider the method printPersons/ithPredicate to see where else you could use
lambda expressions#
public static %oid printPersons/ithPredicate!
List&Person' roster, Predicate&Person' tester" {
+or !Person p , roster" {
i+ !tester$test!p"" {
p$printPerson!";
}
}
}
This method checks each Person instance contained in the List parameter roster
whether it satisfies the criteria specified in the Predicate parameter tester. If the
Person instance does satisfy the criteria specified by tester, the method printPersron
is invoked on the Person instance.
Instead of invoking the method printPerson, you can specify a different action to
perform on those Person instances that satisfy the criteria specified by tester. 2ou can
specify this action with a lambda expression. (uppose you want a lambda expression
similar to printPerson, one that takes one argument ;an ob:ect of type Person< and
returns void. Bemember, to use a lambda expression, you need to implement a functional
interface. In this case, you need a functional interface that contains an abstract method
that can take one argument of type Person and returns void. The .onsumer&)' interface
contains the method %oid accept!) t", which has these characteristics. The following
method replaces the invocation p$printPerson!" with an instance of
.onsumer&Person' that invokes the method accept#
public static %oid processPersons!
List&Person' roster,
Predicate&Person' tester,
Cons!er<Person> "#o$%" {
+or !Person p , roster" {
i+ !tester$test!p"" {
"#o$%.&$$ept(p)'
}
}
}
s a result, the following method invocation is the same as when you invoked
printPersons in pproach ,# (pecify (earch !riteria !ode in a Local !lass to obtain
members who are eligible for (elective (ervice. The lambda expression used to print
members is highlighted#
processPersons!
roster,
p 9' p$get7ender!" -- Person$Sex$MALE
11 p$getAge!" '- 34
11 p$getAge!" &- 56,
p -> p.pr(ntPerson()
";
>hat if you want to do more with your members' profiles than printing them out.
(uppose that you want to validate the members' profiles or retrieve their contact
information= In this case, you need a functional interface that contains an abstract method
that returns a value. The Function&),(' interface contains the method ( appl!) t".
The following method retrieves the data specified by the parameter mapper, and then
performs an action on it specified by the parameter bloc2#
public static %oid processPersons/ithFunction!
List&Person' roster,
Predicate&Person' tester,
Function&Person, String' mapper,
.onsumer&String' bloc2" {
+or !Person p , roster" {
i+ !tester$test!p"" {
String data - mapper$appl!p";
bloc2$accept!data";
}
}
}
The following method retrieves the email address from each member contained in
roster who are eligible for (elective (ervice and then prints it#
processPersons/ithFunction!
roster,
p 9' p$get7ender!" -- Person$Sex$MALE
11 p$getAge!" '- 34
11 p$getAge!" &- 56,
p 9' p$getEmailAddress!",
email 9' Sstem$out$println!email"
";
Approach /: Use $enerics More Extensi0el'
Beconsider the method processPersons/ithFunction. The following is a generic
version of it that accepts, as a parameter, a collection that contains elements of any data
type#
public static &:, ;' %oid processElements!
<terable&:' source,
Predicate&:' tester,
Function &:, ;' mapper,
.onsumer&;' bloc2" {
+or !: p , source" {
i+ !tester$test!p"" {
; data - mapper$appl!p";
bloc2$accept!data";
}
}
}
To print the e"mail address of members who are eligible for (elective (ervice, invoke the
processElements method as follows#
processElements!
roster,
p 9' p$get7ender!" -- Person$Sex$MALE
11 p$getAge!" '- 34
11 p$getAge!" &- 56,
p 9' p$getEmailAddress!",
email 9' Sstem$out$println!email"
";
This method invocation performs the following actions#
Obtains a source of ob:ects from the collection source. In this example, it obtains a
source of Person ob:ects from the collection roster. 7otice that the collection
roster, which is a collection of type List, is also an ob:ect of type <terable.
0ilters ob:ects that match the Predicate ob:ect tester. In this example, the
Predicate ob:ect is a lambda expression that specifies which members would be
eligible for (elective (ervice.
'aps each filtered ob:ect to a value as specified by the Function ob:ect mapper. In
this example, the Function ob:ect is a lambda expression that returns the e"mail
address of a member.
5erforms an action on each mapped ob:ect as specified by the .onsumer ob:ect
bloc2. In this example, the .onsumer ob:ect is a lambda expression that prints a
string, which is the e"mail address returned by the Function ob:ect.
2ou can replace each of these actions with an aggregate operation.
Approach 1: Use A--re-ate !perations hat Accept Lambda
Expressions as 2arameters
The following example uses aggregate operations to print the e"mail addresses of those
members contained in the collection roster who are eligible for (elective (ervice#
roster
$stream!"
$+ilter!
p 9' p$get7ender!" -- Person$Sex$MALE
11 p$getAge!" '- 34
11 p$getAge!" &- 56"
$map!p 9' p$getEmailAddress!""
$+orEach!email 9' Sstem$out$println!email"";
The following table maps each of the operations the method processElements performs
with the corresponding aggregate operation#
pro$essE#e!ents Action A--re-ate !peration
Obtain a source of ob:ects
Stream&E' stre&!!"
0ilter ob:ects that match a Predicate ob:ect
Stream&)' )(#ter!Predicate&=
super )' predicate"
'ap ob:ects to another value as specified by a
Function ob:ect
&(' Stream&(' !&p!Function&=
super ),= extends (' mapper"
5erform an action as specified by a .onsumer
ob:ect
%oid )orE&$*!.onsumer&= super )'
action"
The operations +ilter, map, and +orEach are aggregate operations. ggregate
operations process elements from a stream, not directly from a collection ;which is the
reason why the first method invoked in this example is stream<. stream is a se8uence
of elements. $nlike a collection, it is not a data structure that stores elements. Instead, a
stream carries values from a source, such as collection, through a pipeline. pipeline is a
se8uence of stream operations, which in this example is +ilter" map"+orEach. In
addition, aggregate operations typically accept lambda expressions as parameters,
enabling you to customi+e how they behave.
0or a more thorough discussion of aggregate operations, see the ggregate Operations
lesson.
Lambda Expressions in $UI Applications
To process events in a graphical user interface ;*$I< application, such as keyboard
actions, mouse actions, and scroll actions, you typically create event handlers, which
usually involves implementing a particular interface. Often, event handler interfaces are
functional interfaces9 they tend to have only one method.
In the Cava0F example >ello/orld$8a%a ;discussed in the previous section nonymous
!lasses<, you can replace the highlighted anonymous class with a lambda expression in
this statement#
btn$set*nAction!ne+ E,ent-&nd#er<A$t(onE,ent>() .
/0,err(de
p"#($ ,o(d *&nd#e(A$t(onE,ent e,ent) .
S1ste!.ot.pr(nt#n(2-e##o 3or#d42)'
5
5";
The method invocation btn$set*nAction specifies what happens when you select the
button represented by the btn ob:ect. This method re8uires an ob:ect of type
E%ent>andler&ActionE%ent'. The E%ent>andler&ActionE%ent' interface contains
only one method, %oid handle!) e%ent". This interface is a functional interface, so
you could use the following highlighted lambda expression to replace it#
btn$set*nAction!
e,ent -> S1ste!.ot.pr(nt#n(2-e##o 3or#d42)
";
S'ntax of Lambda Expressions
lambda expression consists of the following#
comma"separated list of formal parameters enclosed in parentheses. The
.hec2Person$test method contains one parameter, p, which represents an
instance of the Person class.
"ote# 2ou can omit the data type of the parameters in a lambda expression. In
addition, you can omit the parentheses if there is only one parameter. 0or
example, the following lambda expression is also valid#
p 9' p$get7ender!" -- Person$Sex$MALE
11 p$getAge!" '- 34
11 p$getAge!" &- 56
The arrow token, 9'
body, which consists of a single expression or a statement block. This example
uses the following expression#
p$get7ender!" -- Person$Sex$MALE
11 p$getAge!" '- 34
11 p$getAge!" &- 56
If you specify a single expression, then the Cava runtime evaluates the expression
and then returns its value. lternatively, you can use a return statement#
p 9' {
return p$get7ender!" -- Person$Sex$MALE
11 p$getAge!" '- 34
11 p$getAge!" &- 56;
}
return statement is not an expression9 in a lambda expression, you must enclose
statements in braces ;{}<. Aowever, you do not have to enclose a void method
invocation in braces. 0or example, the following is a valid lambda expression#
email 9' Sstem$out$println!email"
7ote that a lambda expression looks a lot like a method declaration9 you can consider
lambda expressions as anonymous methods?methods without a name.
The following example, .alculator, is an example of lambda expressions that take more
than one formal parameter#
public class .alculator {

inter+ace <ntegerMath {
int operation!int a, int b";
}

public int operate?inar!int a, int b, <ntegerMath op" {
return op$operation!a, b";
}

public static %oid main!String$$$ args" {

.alculator mApp - ne0 .alculator!";
<ntegerMath addition - !a, b" 9' a @ b;
<ntegerMath subtraction - !a, b" 9' a 9 b;
Sstem$out$println!ABC @ 5 - A @
mApp$operate?inar!BC, 5, addition"";
Sstem$out$println!A5C 9 3C - A @
mApp$operate?inar!5C, 3C, subtraction"";
}
}
The method operate?inar performs a mathematical operation on two integer operands.
The operation itself is specified by an instance of <ntegerMath. The example defines two
operations with lambda expressions, addition and subtraction. The example prints the
following#
BC @ 5 - B5
5C 9 3C - 3C
Accessin- Local 3ariables of the Enclosin- Scope
Like local and anonymous classes, lambda expressions can capture variables9 they have
the same access to local variables of the enclosing scope. Aowever, unlike local and
anonymous classes, lambda expressions do not have any shadowing issues ;see
(hadowing for more information<. Lambda expressions are lexically scoped. This means
that they do not inherit any names from a supertype or introduce a new level of scoping.
Declarations in a lambda expression are interpreted :ust as they are in the enclosing
environment. The following example, LambdaScope)est, demonstrates this#
import 8a%a$util$+unction$.onsumer;
public class LambdaScope)est {
public int x - C;
class FirstLe%el {
public int x - 3;
%oid method<nFirstLe%el!int x" {

## )he +ollo0ing statement causes the compiler to generate
## the error Alocal %ariables re+erenced +rom a lambda
expression
## must be +inal or e++ecti%el +inalA in statement A,
##
## x - DD;

.onsumer&<nteger' m.onsumer - !" 9'
{
Sstem$out$println!Ax - A @ x"; ## Statement A
Sstem$out$println!A - A @ ";
Sstem$out$println!Athis$x - A @ this$x";
Sstem$out$println!ALambdaScope)est$this$x - A @
LambdaScope)est$this$x";
};
m.onsumer$accept!x";
}
}
public static %oid main!String$$$ args" {
LambdaScope)est st - ne0 LambdaScope)est!";
LambdaScope)est$FirstLe%el +l - st$ne0 FirstLe%el!";
+l$method<nFirstLe%el!5E";
}
}
This example generates the following output#
x - 5E
- 5E
this$x - 3
LambdaScope)est$this$x - C
If you substitute the parameter x in place of in the declaration of the lambda expression
m.onsumer, then the compiler generates an error#
.onsumer&<nteger' m.onsumer - !x" 9' {
## $$$
}
The compiler generates the error Gvariable x is already defined in method
methodIn0irstLevel;int<G because the lambda expression does not introduce a new level
of scoping. !onse8uently, you can directly access fields, methods, and local variables of
the enclosing scope. 0or example, the lambda expression directly accesses the parameter
x of the method method<nFirstLe%el. To access variables in the enclosing class, use the
keyword this. In this example, this$x refers to the member variable FirstLe%el$x.
Aowever, like local and anonymous classes, a lambda expression can only access local
variables and parameters of the enclosing block that are final or effectively final. 0or
example, suppose that you add the following assignment statement immediately after the
method<nFirstLe%el definition statement#
%oid method<nFirstLe%el!int x" {
x = 66'
## $$$
}
@ecause of this assignment statement, the variable FirstLe%el$x is not effectively final
anymore. s a result, the Cava compiler generates an error message similar to Glocal
variables referenced from a lambda expression must be final or effectively finalG where
the lambda expression m.onsumer tries to access the FirstLe%el$x variable#
Sstem$out$println!Ax - A @ x";
ar-et 'pin-
Aow do you determine the type of a lambda expression= Becall the lambda expression
that selected members who are male and between the ages &3 and ). years#
p 9' p$get7ender!" -- Person$Sex$MALE
11 p$getAge!" '- 34
11 p$getAge!" &- 56
This lambda expression was used in the following two methods#
public static %oid printPersons!List&Person' roster, .hec2Person
tester" in pproach ,# (pecify (earch !riteria !ode in a Local !lass
public %oid printPersons/ithPredicate!List&Person' roster,
Predicate&Person' tester" in pproach /# $se (tandard 0unctional
Interfaces with Lambda %xpressions
>hen the Cava runtime invokes the method printPersons, it's expecting a data type of
.hec2Person, so the lambda expression is of this type. Aowever, when the Cava runtime
invokes the method printPersons/ithPredicate, it's expecting a data type of
Predicate&Person', so the lambda expression is of this type. The data type that these
methods expect is called the target type. To determine the type of a lambda expression,
the Cava compiler uses the target type of the context or situation in which the lambda
expression was found. It follows that you can only use lambda expressions in situations
in which the Cava compiler can determine a target type#
6ariable declarations
ssignments
Beturn statements
rray initiali+ers
'ethod or constructor arguments
Lambda expression bodies
!onditional expressions, =,
!ast expressions
ar-et 'pes and Method Ar-uments
0or method arguments, the Cava compiler determines the target type with two other
language features# overload resolution and type argument inference.
!onsider the following two functional interfaces ; 8a%a$lang$(unnable and
8a%a$util$concurrent$.allable&F'<#
public inter+ace (unnable {
%oid run!";
}
public inter+ace .allable&F' {
F call!";
}
The method (unnable$run does not return a value, whereas .allable&F'$call does.
(uppose that you have overloaded the method in%o2e as follows ;see Defining 'ethods
for more information about overloading methods<#
%oid in%o2e!(unnable r" {
r$run!";
}
&)' ) in%o2e!.allable&)' c" {
return c$call!";
}
>hich method will be invoked in the following statement=
String s - in%o2e!!" 9' AdoneA";
The method in%o2e!.allable&)'" will be invoked because that method returns a value9
the method in%o2e!(unnable" does not. In this case, the type of the lambda expression
!" 9' AdoneA is .allable&)'.
Seriali%ation
2ou can seriali+e a lambda expression if its target type and its captured arguments are
seriali+able. Aowever, like inner classes, the seriali+ation of lambda expressions is
strongly discouraged.

You might also like