Professional Documents
Culture Documents
Overview
Purpose
ThistutorialintroducesthenewlambdaexpressionsincludedinJavaPlatform
StandardEdition8(JavaSE8).
TimetoComplete
Approximately1hour
Introduction
LambdaexpressionsareanewandimportantfeatureincludedinJavaSE8.
Theyprovideaclearandconcisewaytorepresentonemethodinterface
usinganexpression.LambdaexpressionsalsoimprovetheCollection
librariesmakingiteasiertoiteratethrough,filter,andextractdatafroma
Collection.Inaddition,newconcurrencyfeaturesimproveperformancein
multicoreenvironments.
ThisOraclebyExample(OBE)providesanintroductiontolambda
expressionsincludedinJavaSE8.Anintroductiontoanonymousinner
functionsisprovided,followedbyadiscussionoffunctionalinterfacesandthe
newlambdasyntax.Then,examplesofcommonusagepatternsbeforeand
afterlambdaexpressionsareshown.
ThenextsectionreviewsacommonsearchusecaseandhowJavacodecan
beimprovedwiththeinclusionoflambdaexpressions.Inaddition,someof
thecommonfunctionalinterfaces,PredicateandFunction,providedin
java.util.functionareshowninaction.
TheOBEfinishesupwithareviewofhowtheJavacollectionhasbeen
updatedwithlambdaexpressions.
Thesourcecodeforallexamplesisprovidedtoyou.
HardwareandSoftwareRequirements
Thefollowingisalistofhardwareandsoftwarerequirements:
JavaDevelopmentKit(JDK8)earlyaccess
JavaDevelopmentKit(JDK8)earlyaccess
NetBeans7.4
Prerequisites
Toruntheexamples,youmusthaveanearlyaccessversionofJDK8anda
copyofNetBeans7.4orlater.LinkscanbefoundatthemainLambdasite.
Foryourconvenience,herearethedirectlinks.
JavaDevelopmentKit8(JDK8)EarlyAccess
Recommended:DownloadtheJDK8APIDocsfromthesame
page.
NetBeans7.4orlater.Version7.4ofNetBeansincludessupportforJDK
8.
Note:Buildsareprovidedforallmajoroperatingsystems.ThisOBEwas
developedusingLinuxMint13(Ubuntu/Debian).
InstallJDK8andNetBeansfollowingtheinstructionsprovidedwiththe
downloads.AddthebindirectoriesforJavaandNetBeanstoyourPATH.
Note:ThisOBEwaslastupdatedDecember2013.
Background
AnonymousInnerClass
InJava,anonymousinnerclassesprovideawaytoimplementclassesthat
mayoccuronlyonceinanapplication.Forexample,inastandardSwingor
JavaFXapplicationanumberofeventhandlersarerequiredforkeyboardand
mouseevents.Ratherthanwritingaseparateeventhandlingclassforeach
event,youcanwritesomethinglikethis.
16
17
18
19
20
21
Otherwise,aseparateclassthatimplementsActionListenerisrequiredfor
eachevent.Bycreatingtheclassinplace,whereitisneeded,thecodeisa
littleeasiertoread.Thecodeisnotelegant,becausequiteabitofcodeis
requiredjusttodefineonemethod.
FunctionalInterfaces
ThecodethatdefinestheActionListenerinterface,lookssomethinglike
this:
this:
1
2
3
4
5
6
7
8
package java.awt.event;
import java.util.EventListener;
public interface ActionListener extends EventListener {
public void actionPerformed(ActionEvent e);
}
TheActionListenerexampleisaninterfacewithonlyonemethod.With
JavaSE8,aninterfacethatfollowsthispatternisknownasa"functional
interface."
Note:Thistypeofinterface,waspreviouslyknownasaSingleAbstract
Methodtype(SAM).
Usingfunctionalinterfaceswithanonymousinnerclassesareacommon
patterninJava.InadditiontotheEventListenerclasses,interfaceslike
RunnableandComparatorareusedinasimilarmanner.Therefore,
functionalinterfacesareleveragedforusewithlambdaexpressions.
LambdaExpressionSyntax
Lambdaexpressionsaddressthebulkinessofanonymousinnerclassesby
convertingfivelinesofcodeintoasinglestatement.Thissimplehorizontal
solutionsolvesthe"verticalproblem"presentedbyinnerclasses.
Alambdaexpressioniscomposedofthreeparts.
Argument
List
ArrowToken
Body
(intx,int
y)
>
x+y
Thebodycanbeeitherasingleexpressionorastatementblock.Inthe
expressionform,thebodyissimplyevaluatedandreturned.Intheblockform,
thebodyisevaluatedlikeamethodbodyandareturnstatementreturns
controltothecalleroftheanonymousmethod.Thebreakandcontinue
keywordsareillegalatthetoplevel,butarepermittedwithinloops.Ifthebody
producesaresult,everycontrolpathmustreturnsomethingorthrowan
exception.
Takealookattheseexamples:
(int x, int y) -> x + y
() -> 42
(String s) -> { System.out.println(s); }
Thefirstexpressiontakestwointegerarguments,namedxandy,anduses
theexpressionformtoreturnx+y.Thesecondexpressiontakesno
argumentsandusestheexpressionformtoreturnaninteger42.Thethird
expressiontakesastringandusestheblockformtoprintthestringtothe
console,andreturnsnothing.
Withthebasicsofsyntaxcovered,let'slookatsomeexamples.
LambdaExamples
Herearesomecommonusecasesusingthepreviouslycoveredexamples.
RunnableLambda
HereishowyouwriteaRunnableusinglambdas.
6 public class RunnableTest {
7
public static void main(String[] args) {
8
9
System.out.println("=== RunnableTest ===");
10
11
// Anonymous Runnable
12
Runnable r1 = new Runnable(){
13
14
@Override
15
public void run(){
16
System.out.println("Hello world one!");
17
}
18
};
19
20
// Lambda Runnable
21
Runnable r2 = () -> System.out.println("Hello world two!");
22
23
// Run em!
24
r1.run();
25
r2.run();
26
27
}
28 }
Inbothcases,noticethatnoparameterispassedandisreturned.The
Runnablelambdaexpression,whichusestheblockformat,convertsfivelines
ofcodeintoonestatement.
ComparatorLambda
InJava,theComparatorclassisusedforsortingcollections.Inthefollowing
example,anArrayListconsistingofPersonobjectsissortedbasedon
surName.ThefollowingarethefieldsincludedinthePersonclass.
9 public class Person {
10
11
12
13
14
15
16
17
ThefollowingcodeappliesaComparatorbyusingananonymousinnerclass
andacouplelambdaexpressions.
10 public class ComparatorTest {
11
12
public static void main(String[] args) {
13
14
List<Person> personList = Person.createShortList();
15
16
// Sort with Inner Class
17
Collections.sort(personList, new Comparator<Person>(){
18
public int compare(Person p1, Person p2){
19
return p1.getSurName().compareTo(p2.getSurName());
20
}
21
});
22
23
System.out.println("=== Sorted Asc SurName ===");
24
for(Person p:personList){
25
p.printName();
26
}
27
28
// Use Lambda instead
29
30
// Print Asc
31
System.out.println("=== Sorted Asc SurName ===");
32
Collections.sort(personList, (Person p1, Person p2) ->
p1.getSurName().compareTo(p2.getSurName()));
33
34
for(Person p:personList){
35
p.printName();
36
}
37
38
// Print Desc
39
System.out.println("=== Sorted Desc SurName ===");
40
Collections.sort(personList, (p1, p2) ->
p2.getSurName().compareTo(p1.getSurName()));
41
42
for(Person p:personList){
43
p.printName();
44
}
45
46
}
47 }
Lines1721areeasilyreplacedbythelambdaexpressiononline32.Notice
thatthefirstlambdaexpressiondeclarestheparametertypepassedtothe
expression.However,asyoucanseefromthesecondexpression,thisis
expression.However,asyoucanseefromthesecondexpression,thisis
optional.Lambdasupports"targettyping"whichinferstheobjecttypefrom
thecontextinwhichitisused.Becauseweareassigningtheresulttoa
Comparatordefinedwithageneric,thecompilercaninferthatthetwo
parametersareofthePersontype.
ListenerLambda
Finally,let'srevisittheActionListenerexample.
13 public class ListenerTest {
14
public static void main(String[] args) {
15
16
JButton testButton = new JButton("Test Button");
17
testButton.addActionListener(new ActionListener(){
18
@Override public void actionPerformed(ActionEvent ae){
19
System.out.println("Click Detected by Anon Class");
20
}
21
});
22
23
testButton.addActionListener(e -> System.out.println("Click
Detected by Lambda Listner"));
24
25
// Swing stuff
26
JFrame frame = new JFrame("Listener Test");
27
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
28
frame.add(testButton, BorderLayout.CENTER);
29
frame.pack();
30
frame.setVisible(true);
31
32
}
33 }
Noticethatthelambdaexpressionispassedasaparameter.Targettypingis
usedinanumberofcontextsincludingthefollowing:
Variabledeclarations
Assignments
Returnstatements
Arrayinitializers
Methodorconstructorarguments
Lambdaexpressionbodies
Conditionalexpressions?:
Castexpressions
Resources
ANetBeansprojectcontainingthesourcefilesfortheexamplescoveredto
thispointisinthefollowingzipfile.
LambdaExamples01.zip
ImprovingCodewithLambdaExpressions
Thissectionbuildsuponthepreviousexamplestoshowyouhowlambda
expressionscanimproveyourcode.Lambdasshouldprovideameansto
bettersupporttheDon'tRepeatYourself(DRY)principleandmakeyourcode
simplerandmorereadable.
ACommonQueryUseCase
Acommonusecaseforprogramsistosearchthroughacollectionofdatato
finditemsthatmatchaspecificcriteria.Intheexcellent"JumpStarting
Lambda"presentationatJavaOne2012,StuartMarksandMikeDuigouwalk
thoughjustsuchausecase.Givenalistofpeople,variouscriteriaareused
tomakerobocalls(automatedphonecalls)tomatchingpersons.Thistutorial
followsthatbasicpremisewithslightvariations.
Inthisexample,ourmessageneedstogetouttothreedifferentgroupsinthe
UnitedStates:
Drivers:Personsovertheageof16
Draftees:Malepersonsbetweentheagesof18and25
Pilots(specificallycommercialpilots):Personsbetweentheagesof23
and65
Theactualrobotthatdoesallthisworkhasnotyetarrivedatourplaceof
business.Insteadofcalling,mailingoremailing,amessageisprintedtothe
console.Themessagecontainsaperson'sname,age,andinformation
specifictothetargetmedium(forexample,emailaddresswhenemailingor
phonenumberwhencalling).
PersonClass
EachpersoninthetestlistisdefinedbyusingthePersonclasswiththe
followingproperties:
10 public class Person {
11
private String givenName;
12
private String surName;
13
private int age;
14
private Gender gender;
15
private String eMail;
16
private String phone;
17
private String address;
18
ThePersonclassusesaBuildertocreatenewobjects.Asamplelistof
peopleiscreatedwiththecreateShortListmethod.Hereisashortcode
fragmentofthatmethod.Note:Allsourcecodeforthistutorialisincludedina
NetBeansprojectthatislinkedattheendofthissection.
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
AFirstAttempt
WithaPersonclassandsearchcriteriadefined,youcanwriteaRoboContact
class.Onepossiblesolutiondefinesamethodforeachusecase:
RoboContactsMethods.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.example.lambda;
import java.util.List;
/**
*
* @author MikeW
*/
public class RoboContactMethods {
public void callDrivers(List<Person> pl){
for(Person p:pl){
12
13
14
15
16
for(Person p:pl){
if (p.getAge() >= 16){
roboCall(p);
}
}
17
}
18
19
public void emailDraftees(List<Person> pl){
20
for(Person p:pl){
21
if (p.getAge() >= 18 && p.getAge() <= 25 && p.getGender()
== Gender.MALE){
22
roboEmail(p);
23
}
24
}
25
}
26
27
public void mailPilots(List<Person> pl){
28
for(Person p:pl){
29
if (p.getAge() >= 23 && p.getAge() <= 65){
30
roboMail(p);
31
}
32
}
33
}
34
35
36
public void roboCall(Person p){
37
System.out.println("Calling " + p.getGivenName() + " " +
p.getSurName() + " age " + p.getAge() + " at " + p.getPhone());
38
}
39
40
public void roboEmail(Person p){
41
System.out.println("EMailing " + p.getGivenName() + " " +
p.getSurName() + " age " + p.getAge() + " at " + p.getEmail());
42
}
43
44
public void roboMail(Person p){
45
System.out.println("Mailing " + p.getGivenName() + " " +
p.getSurName() + " age " + p.getAge() + " at " + p.getAddress());
46
}
47
48 }
Asyoucanseefromthenames(callDrivers,emailDraftees,and
mailPilots)themethodsdescribethekindofbehaviorthatistakingplace.
Thesearchcriteriaisclearlyconveyedandanappropriatecallismadeto
eachroboaction.However,thisdesignhassomenegativesaspects:
TheDRYprincipleisnotfollowed.
Eachmethodrepeatsaloopingmechanism.
Theselectioncriteriamustberewrittenforeachmethod
Alargenumberofmethodsarerequiredtoimplementeachusecase.
Thecodeisinflexible.Ifthesearchcriteriachanged,itwouldrequirea
numberofcodechangesforanupdate.Thus,thecodeisnotvery
maintainable.
RefactortheMethods
Howcantheclassbefixed?Thesearchcriteriaisagoodplacetostart.Iftest
conditionsareisolatedinseparatemethods,thatwouldbeanimprovement.
RoboContactMethods2.java
1 package com.example.lambda;
2
3 import java.util.List;
4
5 /**
6 *
7 * @author MikeW
8 */
9 public class RoboContactMethods2 {
10
11
public void callDrivers(List<Person> pl){
12
for(Person p:pl){
13
if (isDriver(p)){
14
roboCall(p);
15
}
16
}
17
}
18
19
public void emailDraftees(List<Person> pl){
20
for(Person p:pl){
21
if (isDraftee(p)){
22
roboEmail(p);
23
}
24
}
25
}
26
27
public void mailPilots(List<Person> pl){
28
for(Person p:pl){
29
if (isPilot(p)){
30
roboMail(p);
31
}
32
}
33
}
34
35
public boolean isDriver(Person p){
36
return p.getAge() >= 16;
37
}
38
39
public boolean isDraftee(Person p){
40
return p.getAge() >= 18 && p.getAge() <= 25 &&
p.getGender() == Gender.MALE;
41
}
42
43
public boolean isPilot(Person p){
44
return p.getAge() >= 23 && p.getAge() <= 65;
45
}
46
47
public void roboCall(Person p){
48
System.out.println("Calling " + p.getGivenName() + " " +
p.getSurName() + " age " + p.getAge() + " at " + p.getPhone());
49
}
50
51
public void roboEmail(Person p){
52
System.out.println("EMailing " + p.getGivenName() + " " +
p.getSurName() + " age " + p.getAge() + " at " + p.getEmail());
53
}
54
55
public void roboMail(Person p){
56
System.out.println("Mailing " + p.getGivenName() + " " +
p.getSurName() + " age " + p.getAge() + " at " + p.getAddress());
57
}
57
}
58
59 }
Thesearchcriteriaareencapsulatedinamethod,animprovementoverthe
previousexample.Thetestconditionscanbereusedandchangesflowback
throughouttheclass.Howeverthereisstillalotofrepeatedcodeanda
separatemethodisstillrequiredforeachusecase.Isthereabetterwayto
passthesearchcriteriatothemethods?
AnonymousClasses
Beforelambdaexpressions,anonymousinnerclasseswereanoption.For
example,aninterface(MyTest.java)writtenwithonetestmethodthat
returnsaboolean(afunctionalinterface)isapossiblesolution.Thesearch
criteriacouldbepassedwhenthemethodiscalled.Theinterfacelookslike
this:
6 public interface MyTest<T> {
7
public boolean test(T t);
8 }
Theupdatedrobotclasslookslikethis:
RoboContactsAnon.java
34
35
public void roboCall(Person p){
36
System.out.println("Calling " + p.getGivenName() + " " +
p.getSurName() + " age " + p.getAge() + " at " + p.getPhone());
37
}
38
39
public void roboEmail(Person p){
40
System.out.println("EMailing " + p.getGivenName() + " " +
p.getSurName() + " age " + p.getAge() + " at " + p.getEmail());
41
}
42
43
public void roboMail(Person p){
44
System.out.println("Mailing " + p.getGivenName() + " " +
p.getSurName() + " age " + p.getAge() + " at " + p.getAddress());
45
}
46
47 }
Thatisdefinitelyanotherimprovement,becauseonlythreemethodsare
neededtoperformroboticoperations.However,thereisaslightproblemwith
uglinesswhenthemethodsarecalled.Checkoutthetestclassusedforthis
class:
RoboCallTest03.java
1 package com.example.lambda;
2
3 import java.util.List;
4
5 /**
6 * @author MikeW
7 */
8 public class RoboCallTest03 {
9
10
public static void main(String[] args) {
11
12
List<Person> pl = Person.createShortList();
13
RoboContactAnon robo = new RoboContactAnon();
14
15
System.out.println("\n==== Test 03 ====");
16
System.out.println("\n=== Calling all Drivers ===");
17
robo.phoneContacts(pl,
18
new MyTest<Person>(){
19
@Override
20
public boolean test(Person p){
21
return p.getAge() >=16;
22
}
23
}
24
);
25
26
System.out.println("\n=== Emailing all Draftees ===");
27
robo.emailContacts(pl,
28
new MyTest<Person>(){
29
@Override
30
public boolean test(Person p){
31
return p.getAge() >= 18 && p.getAge() <= 25 &&
p.getGender() == Gender.MALE;
32
}
33
}
34
);
34
35
36
37
38
);
System.out.println("\n=== Mail all Pilots ===");
robo.mailContacts(pl,
39
new MyTest<Person>(){
40
@Override
41
public boolean test(Person p){
42
return p.getAge() >= 23 && p.getAge() <= 65;
43
}
44
}
45
);
46
47
48
}
49 }
Thisisagreatexampleofthe"vertical"probleminpractice.Thiscodeisa
littledifficulttoread.Inaddition,wehavetowritecustomsearchcriteriafor
eachusecase.
LambdaExpressionsGetitJustRight
Lambdaexpressionssolvealltheproblemsencounteredsofar.Butfirsta
littlehousekeeping.
java.util.function
Inthepreviousexample,theMyTestfunctionalinterfacepassedanonymous
classestomethods.However,writingthatinterfacewasnotnecessary.Java
SE8providesthejava.util.functionpackagewithanumberofstandard
functionalinterfaces.Inthiscase,thePredicateinterfacemeetsourneeds.
3 public interface Predicate<T> {
4
public boolean test(T t);
5 }
Thetestmethodtakesagenericclassandreturnsabooleanresult.Thisis
justwhatisneededtomakeselections.Hereisthefinalversionoftherobot
class.
RoboContactsLambda.java
1
2
3
4
5
6
7
8
9
10
package com.example.lambda;
import java.util.List;
import java.util.function.Predicate;
/**
*
* @author MikeW
*/
public class RoboContactLambda {
Withthisapproachonlythreemethodsareneeded,oneforeachcontact
method.ThelambdaexpressionpassedtothemethodselectsthePerson
instancesthatmeetthetestconditions.
VerticalProblemSolved
Lambdaexpressionssolvetheverticalproblemandallowtheeasyreuseof
anyexpression.Takealookatthenewtestclassupdatedforlambda
expressions.
RoboCallTest04.java
1 package com.example.lambda;
1 package com.example.lambda;
2
3 import java.util.List;
4 import java.util.function.Predicate;
5
6 /**
7 *
8 * @author MikeW
9 */
10 public class RoboCallTest04 {
11
12
public static void main(String[] args){
13
14
List<Person> pl = Person.createShortList();
15
RoboContactLambda robo = new RoboContactLambda();
16
17
// Predicates
18
Predicate<Person> allDrivers = p -> p.getAge() >= 16;
19
Predicate<Person> allDraftees = p -> p.getAge() >= 18 &&
p.getAge() <= 25 && p.getGender() == Gender.MALE;
20
Predicate<Person> allPilots = p -> p.getAge() >= 23 &&
p.getAge() <= 65;
21
22
System.out.println("\n==== Test 04 ====");
23
System.out.println("\n=== Calling all Drivers ===");
24
robo.phoneContacts(pl, allDrivers);
25
26
System.out.println("\n=== Emailing all Draftees ===");
27
robo.emailContacts(pl, allDraftees);
28
29
System.out.println("\n=== Mail all Pilots ===");
30
robo.mailContacts(pl, allPilots);
31
32
// Mix and match becomes easy
33
System.out.println("\n=== Mail all Draftees ===");
34
robo.mailContacts(pl, allDraftees);
35
36
System.out.println("\n=== Call all Pilots ===");
37
robo.phoneContacts(pl, allPilots);
38
39
}
40 }
NoticethataPredicateissetupforeachgroup:allDrivers,allDraftees,
andallPilots.YoucanpassanyofthesePredicateinterfacestothe
contactmethods.Thecodeiscompactandeasytoread,anditisnot
repetitive.
Resources
TheNetBeansprojectwiththesourcecodeisincludedinthefollowingzipfile.
RoboCallExample.zip
Thejava.util.functionPackage
Thejava.util.functionPackage
Thejava.util.functionPackage
Ofcourse,PredicateisnottheonlyfunctionalinterfaceprovidedwithJava
SE8.Anumberofstandardinterfacesaredesignedasastartersetfor
developers.
Predicate:Apropertyoftheobjectpassedasargument
Consumer:Anactiontobeperformedwiththeobjectpassedas
argument
Function:TransformaTtoaU
Supplier:ProvideaninstanceofaT(suchasafactory)
UnaryOperator:AunaryoperatorfromT>T
BinaryOperator:Abinaryoperatorfrom(T,T)>T
Inaddition,manyoftheseinterfacesalsohaveprimitiveversions.Thisshould
giveyouagreatstartingpointforyourlambdaexpressions.
EasternStyleNamesandMethodReferences
Whenworkingonthepreviousexample,Idecideditwouldbenicetohavea
flexibleprintingsystemforthePersonclass.Onefeaturerequirementisto
displaynamesinbothawesternstyleandaneasternstyle.IntheWest,
namesaredisplayedwiththegivennamefirstandthesurnamesecond.In
manyeasterncultures,namesaredisplayedwiththesurnamefirstandthe
givennamesecond.
AnOldStyleExample
HereisanexampleofhowtoimplementaPersonprintingclasswithout
lambdasupport.
Person.java
128
public void printWesternName(){
129
130
System.out.println("\nName: " + this.getGivenName() + " " +
this.getSurName() + "\n" +
131
"Age: " + this.getAge() + " " + "Gender: " +
this.getGender() + "\n" +
132
"EMail: " + this.getEmail() + "\n" +
133
"Phone: " + this.getPhone() + "\n" +
134
"Address: " + this.getAddress());
135
}
136
137
138
139
public void printEasternName(){
140
141
System.out.println("\nName: " + this.getSurName() + " " +
this.getGivenName() + "\n" +
142
"Age: " + this.getAge() + " " + "Gender: " +
this.getGender() + "\n" +
143
"EMail: " + this.getEmail() + "\n" +
144
"Phone: " + this.getPhone() + "\n" +
144
145
146
Amethodexistsforeachstylethatprintsoutaperson.
TheFunctionInterface
TheFunctioninterfaceisusefulforthisproblem.Ithasonlyonemethod
applywiththefollowingsignature:
publicRapply(Tt){}
IttakesagenericclassTandreturnsagenericclassR.Forthisexample,
passthePersonclassandreturnaString.Amoreflexibleprintmethodfor
personcouldbewrittenlikethis:
Person.java
123
124
125
126
Thatisquiteabitsimpler.AFunctionispassedtothemethodandastring
returned.Theapplymethodprocessesalambdaexpressionwhich
determineswhatPersoninformationisreturned.
HowaretheFunctionsdefined?Hereisthetestcodethatcallstheprevious
method.
NameTestNew.java
26
// Define Western and Eastern Lambdas
27
28
Function<Person, String> westernStyle = p -> {
29
return "\nName: " + p.getGivenName() + " " + p.getSurName()
+ "\n" +
30
"Age: " + p.getAge() + " " + "Gender: " +
p.getGender() + "\n" +
31
"EMail: " + p.getEmail() + "\n" +
32
"Phone: " + p.getPhone() + "\n" +
33
"Address: " + p.getAddress();
34
};
35
36
Function<Person, String> easternStyle = p -> "\nName: " +
p.getSurName() + " "
37
+ p.getGivenName() + "\n" + "Age: " + p.getAge() + "
"+
38
"Gender: " + p.getGender() + "\n" +
39
"EMail: " + p.getEmail() + "\n" +
40
"Phone: " + p.getPhone() + "\n" +
41
"Address: " + p.getAddress();
42
43
// Print Western List
44
System.out.println("\n===Western List===");
45
for (Person person:list1){
46
System.out.println(
47
person.printCustom(westernStyle)
48
);
49
}
50
51
// Print Eastern List
52
System.out.println("\n===Eastern List===");
53
for (Person person:list1){
54
System.out.println(
55
person.printCustom(easternStyle)
56
);
57
}
58
59
60
}
61 }
Thefirstloopjustprintsgivennameandtheemailaddress.Butanyvalid
expressioncouldbepassedtotheprintCustommethod.Easternand
westernprintstylesaredefinedwithlambdaexpressionsandstoredina
variable.Thevariablesarethenpassedtothefinaltwoloops.Thelambda
expressionscouldveryeasilybeincorporatedintoaMaptomaketheirreuse
mucheasier.Thelambdaexpressionprovidesagreatdealofflexibility.
SampleOutput
Hereissomesampleoutputfromtheprogram.
==== NameTestNew02 ===
===Custom List===
Name: Bob EMail: bob.baker@example.com
Name: Jane EMail: jane.doe@example.com
Name: John EMail: john.doe@example.com
Name: James EMail: james.johnson@example.com
Name: Joe EMail: joebob.bailey@example.com
Resources
TheNetBeansprojectwiththesourcecodefortheexamplesinthissectionis
includedinthefollowingzipfile.
LambdaFunctionExamples.zip
LambdaExpressionsandCollections
TheprevioussectionintroducedtheFunctioninterfaceandfinishedup
examplesofbasiclambdaexpressionsyntax.Thissectionreviewshow
lambdaexpressionsimprovetheCollectionclasses.
LambdaExpressionsandCollections
Intheexamplescreatedsofar,thecollectionsclasseswereusedquiteabit.
However,anumberofnewlambdaexpressionfeatureschangetheway
collectionsareused.Thissectionintroducesafewofthesenewfeatures.
ClassAdditions
Thedrivers,pilots,anddrafteessearchcriteriahavebeenencapsulatedinthe
SearchCriteriaclass.
SearchCriteria.java
SearchCriteria.java
1 package com.example.lambda;
2
3 import java.util.HashMap;
4 import java.util.Map;
5 import java.util.function.Predicate;
6
7 /**
8 *
9 * @author MikeW
10 */
11 public class SearchCriteria {
12
13
private final Map<String, Predicate<Person>> searchMap = new
HashMap<>();
14
15
private SearchCriteria() {
16
super();
17
initSearchMap();
18
}
19
20
private void initSearchMap() {
21
Predicate<Person> allDrivers = p -> p.getAge() >= 16;
22
Predicate<Person> allDraftees = p -> p.getAge() >= 18 &&
p.getAge() <= 25 && p.getGender() == Gender.MALE;
23
Predicate<Person> allPilots = p -> p.getAge() >= 23 &&
p.getAge() <= 65;
24
25
searchMap.put("allDrivers", allDrivers);
26
searchMap.put("allDraftees", allDraftees);
27
searchMap.put("allPilots", allPilots);
28
29
}
30
31
public Predicate<Person> getCriteria(String PredicateName) {
32
Predicate<Person> target;
33
34
target = searchMap.get(PredicateName);
35
36
if (target == null) {
37
38
System.out.println("Search Criteria not found... ");
39
System.exit(1);
40
41
}
42
43
return target;
44
45
}
46
47
public static SearchCriteria getInstance() {
48
return new SearchCriteria();
49
}
50 }
ThePredicatebasedsearchcriteriaarestoredinthisclassandavailablefor
ourtestmethods.
Looping
ThefirstfeaturetolookatisthenewforEachmethodavailabletoany
collectionclass.HereareacoupleofexamplesthatprintoutaPersonlist.
Test01ForEach.java
Thefirstexampleshowsastandardlambdaexpressionwhichcallsthe
printWesternNamemethodtoprintouteachpersoninthelist.Thesecond
exampledemonstratesamethodreference.Inacasewhereamethod
alreadyexiststoperformanoperationontheclass,thissyntaxcanbeused
insteadofthenormallambdaexpressionsyntax.Finally,thelastexample
showshowtheprintCustommethodcanalsobeusedinthissituation.
Noticetheslightvariationinvariablenameswhenonelambdaexpressionis
includedinanother.
Youcaniteratethroughanycollectionthisway.Thebasicstructureissimilar
totheenhancedforloop.However,includinganiterationmechanismwithin
theclassprovidesanumberofbenefits.
ChainingandFilters
Inadditiontoloopingthroughthecontentsofacollection,youcanchain
methodstogether.Thefirstmethodtolookatisfilterwhichtakesa
Predicateinterfaceasaparameter.
ThefollowingexampleloopsthoughaListafterfirstfilteringtheresults.
Test02Filter.java
11
12
13
14
15
16
17
System.out.println("\n=== Western Pilot Phone List ===");
18
19
pl.stream().filter(search.getCriteria("allPilots"))
20
.forEach(Person::printWesternName);
21
22
23
System.out.println("\n=== Eastern Draftee Phone List ===");
24
25
pl.stream().filter(search.getCriteria("allDraftees"))
26
.forEach(Person::printEasternName);
27
28
}
29 }
ThefirstandlastloopsdemonstratehowtheListisfilteredbasedonthe
searchcriteria.Theoutputfromthelastlooplookslikefollowing:
=== Eastern Draftee Phone List ===
Name: Baker Bob
Age: 21 Gender: MALE
EMail: bob.baker@example.com
Phone: 201-121-4678
Address: 44 4th St, Smallville, KS 12333
Name: Doe John
Age: 25 Gender: MALE
EMail: john.doe@example.com
Phone: 202-123-4678
Address: 33 3rd St, Smallville, KS 12333
GettingLazy
Thesefeaturesareuseful,butwhyaddthemtothecollectionsclasseswhen
thereisalreadyaperfectlygoodforloop?Bymovingiterationfeaturesintoa
library,itallowsthedevelopersofJavatodomorecodeoptimizations.To
explainfurther,acoupleoftermsneeddefinitions.
Laziness:Inprogramming,lazinessreferstoprocessingonlythe
objectsthatyouwanttoprocesswhenyouneedtoprocessthem.Inthe
previousexample,thelastloopis"lazy"becauseitloopsonlythrough
thetwoPersonobjectsleftaftertheListisfiltered.Thecodeshouldbe
moreefficientbecausethefinalprocessingstepoccursonlyonthe
selectedobjects.
Eagerness:Codethatperformsoperationsoneveryobjectinalistis
considered"eager".Forexample,anenhancedforloopthatiterates
throughanentirelisttoprocesstwoobjects,isconsideredamore
"eager"approach.
Bymakingloopingpartofthecollectionslibrary,codecanbebetteroptimized
Bymakingloopingpartofthecollectionslibrary,codecanbebetteroptimized
for"lazy"operationswhentheopportunityarises.Whenamoreeager
approachmakessense(forexample,computingasumoranaverage),eager
operationsarestillapplied.Thisapproachisamuchmoreefficientand
flexiblethanalwaysusingeageroperations.
ThestreamMethod
Inthepreviouscodeexample,noticethatthestreammethodiscalledbefore
filteringandloopingbegin.ThismethodtakesaCollectionasinputand
returnsajava.util.stream.Streaminterfaceastheoutput.AStream
representsasequenceofelementsonwhichvariousmethodscanbe
chained.Bydefault,onceelementsareconsumedtheyarenolonger
availablefromthestream.Therefore,achainofoperationscanoccuronly
onceonaparticularStream.Inaddition,aStreamcanbeserial(default)or
paralleldependingonthemethodcalled.Anexampleofaparallelstreamis
includedattheendofthissection.
MutationandResults
Aspreviouslymentioned,aStreamisdisposedofafteritsuse.Therefore,the
elementsinacollectioncannotbechangedormutatedwithaStream.
However,whatifyouwanttokeepelementsreturnedfromyourchained
operations?Youcansavethemtoanewcollection.Thefollowingcode
showshowtodojustthat.
Test03toList.java
10 public class Test03toList {
11
12
public static void main(String[] args) {
13
14
List<Person> pl = Person.createShortList();
15
16
SearchCriteria search = SearchCriteria.getInstance();
17
18
// Make a new list after filtering.
19
List<Person> pilotList = pl
20
.stream()
21
.filter(search.getCriteria("allPilots"))
22
.collect(Collectors.toList());
23
24
System.out.println("\n=== Western Pilot Phone List ===");
25
pilotList.forEach(Person::printWesternName);
26
27
}
28
29 }
Thecollectmethodiscalledwithoneparameter,theCollectorsclass.
TheCollectorsclassisabletoreturnaListorSetbasedontheresultsof
thestream.Theexampleshowshowtheresultofthestreamisassignedtoa
thestream.Theexampleshowshowtheresultofthestreamisassignedtoa
newListwhichisiteratedover.
Calculatingwithmap
Themapmethodiscommonlyusedwithfilter.Themethodtakesaproperty
fromaclassanddoessomethingwithit.Thefollowingexampledemonstrates
thisbyperformingcalculationsbasedonage.
Test04Map.java
10 public class Test04Map {
11
12
public static void main(String[] args) {
13
List<Person> pl = Person.createShortList();
14
15
SearchCriteria search = SearchCriteria.getInstance();
16
17
// Calc average age of pilots old style
18
System.out.println("== Calc Old Style ==");
19
int sum = 0;
20
int count = 0;
21
22
for (Person p:pl){
23
if (p.getAge() >= 23 && p.getAge() <= 65 ){
24
sum = sum + p.getAge();
25
count++;
26
}
27
}
28
29
long average = sum / count;
30
System.out.println("Total Ages: " + sum);
31
System.out.println("Average Age: " + average);
32
33
34
// Get sum of ages
35
System.out.println("\n== Calc New Style ==");
36
long totalAge = pl
37
.stream()
38
.filter(search.getCriteria("allPilots"))
39
.mapToInt(p -> p.getAge())
40
.sum();
41
42
// Get average of ages
43
OptionalDouble averageAge = pl
44
.parallelStream()
45
.filter(search.getCriteria("allPilots"))
46
.mapToDouble(p -> p.getAge())
47
.average();
48
49
System.out.println("Total Ages: " + totalAge);
50
System.out.println("Average Age: " +
averageAge.getAsDouble());
51
52
}
53
54 }
Andtheoutputfromtheclassis:
Theprogramcalculatestheaverageageofpilotsinourlist.Thefirstloop
demonstratestheoldstyleofcalculatingthenumberbyusingaforloop.The
secondloopusesthemapmethodtogettheageofeachpersoninaserial
stream.NoticethattotalAgeisalong.ThemapmethodreturnsanIntSteam
object,whichcontainsasummethodthatreturnsalong.
Note:Tocomputetheaveragethesecondtime,calculatingthesumofages
isunnecessary.However,itisinstructivetoshowanexamplewiththesum
method.
Thelastloopcomputestheaverageagefromthestream.Noticethatthe
parallelStreammethodisusedtogetaparallelstreamsothatthevalues
canbecomputedconcurrently.Thereturntypeisabitdifferenthereaswell.
Resources
TheNetBeansprojectwithsourcecodefortheexamplesisinthefollowing
zipfile.
LambdaCollectionExamples.zip
Summary
Inthistutorial,youlearnedhowtouse:
AnonymousinnerclassesinJava.
LambdaexpressionstoreplaceanonymousinnerclassesinJavaSE8.
Thecorrectsyntaxforlambdaexpressions.
APredicateinterfacetoperformsearchesonalist.
AFunctioninterfacetoprocessanobjectandproduceadifferenttype
ofobject.
NewfeaturesaddedtoCollectionsinJavaSE8thatsupportlambda
expressions.
Resources
ForfurtherinformationonJavaSE8andlambdaexpressions,seethe
following:
Java8
ProjectLambda
ProjectLambda
StateoftheLambda
StateoftheLambdaCollections
JumpStartingLambdaJavaOne2012(YouTube)
TolearnmoreaboutJavaandrelatedtopicscheckouttheOracle
LearningLibrary.
Credits
LeadCurriculumDeveloper:MichaelWilliams
QA:JuanQuesadaNunez