functional programming with javajxs/courses/cs410/note11.pdffunctional programming with java 1...
TRANSCRIPT
FunctionalProgrammingwithJava
1
NotableEnhancementsinJava8• Lambdaexpressions
– AllowyoutodofunctionalprogramminginJava
• Staticanddefaultmethodsininterfaces
2
LambdaExpressionsinJava• Lambdaexpression
– Ablockofcode(orafunction)thatyoucanpasstoa
method.
• BeforeJava8,methodscouldreceiveprimitive
valuesandobjectsonly.
– public void example(int i, String s, ArrayList<String> list)
– Methodscouldreceivenothingelse.
• Youcouldn’tdolikethis:
– foo.example( [if(Math.random()>0.5){System.out.println(...);}
else{System.out.println(...);} ] )
3
HowtoDefineaLambdaExpression?• Alambdaexpressionconsistsof
– Acodeblock
– Asetofparameterstobepassedtothecodeblock
– (String str) -> str.toUpperCase()
– (StringBuffer first, StringBuffer second)-> first.append(second)
– (int first, int second)-> second – first
4
• Noneedtospecifythenameofafunction.
– Lambdaexpression~anonymous function/methodthat
isnotboundtoaclass/interface
– (int first, int second)-> second – first
– public int subtract(int first, int second){return second – first; }
• Noneedtoexplicitlyspecifythereturnvalue’stype.
– YourJavacompilerautomaticallyinfersthat.
• Single-expressioncodeblock
– Doesnotusethe“return”keyword.5
• Alambdaexpressionconsistsof
– Acodeblock
– Asetofparameterstobepassedtothecodeblock
– (double threshold)-> {if(Math.random() > threshold) return true;else return false;
}– () -> {
if(Math.random) > 0.5) return true;else return false;
}
6
• Single-expressioncodeblock
– Doesnotusethe“return”keyword.
• Multi-expressioncodeblock
– Surroundsexpressionswith{and}.Use;intheendof
eachexp.
– Needsthe“return”keywordintheendofeachcontrol
flow.
• Everyconditionalbranchmustreturnavalue.
• () -> {if(Math.random) > 0.5) return true;
// else return false; ß A compilation error occurshere if this line iscommented out.
}
7
HowtoPassaLambdaExpression?• Amethodcanreceivealambdaexpression(s).
• foo.example( (int first, int second) -> second–first )
– Themethodreceivesalambdaexpressionasaparameter.
– Whatisthetypeofthatparameter?
• Functionalinterface!
8
FunctionalInterface• Aspecialtypeofinterface
– Aninterfacethathasasingleabstract(orempty)method.
• Anexamplefunctionalinterface:java.util.Comparator
– Definescompare(),whichistheonlyabstract/emptymethod.
• Anewannotationisavailable:
– @FunctionalInterfacepublic interface Comparator<T>
– AllfunctionalinterfacesinJavaAPIhavethisannotation.
» TheAPIdocumentationsays“Thisisafunctionalinterfaceandcan
thereforebeusedastheassignmenttargetforalambda
expression…”
• Collections.sort(List, Comparator<T>)– Thesecondparametercanacceptalambdaexpression.
– Collections.sort( aList,(Integer first, Integer second)->
second.intValue()–first.intValue() );9
Recap:Comparators• Sorting collection elements:
– ArrayList<Integer> years2 = new ArrayList<Integer>();years2.add(new Integer(2010));years2.add(new Integer(2000));years2.add(new Integer(1997));years2.add(new Integer(2006));Collections.sort(years2);for(Integer y: years2)
System.out.println(y);
– java.util.Collections: a utility class (i.e., a set of static methods) to process collections and collection elements
– sort() orders collection elements in an ascending order.
• 1997 -> 2000 -> 2006 -> 201010
Comparison/OrderingPolicies• Whatifyouwanttosortarray/collectionelementsina
descendingorderoranyspecialized(user-defined)order?
– Arrays.sort() andCollections.sort() implementascending
orderingonly.
• Theydonotimplementanyotherpolicies.
• Defineacustomcomparatorbyimplementing
java.util.Comparator
11
<<interface>>
Comparator
compare(Object, Object)
DescendingOrderComparator …
0..1
Collections
sort(collection)
sort(collection, Comparator)
Arrays
sort(array)
sort(array, Comparator)0..1
Strategy Pattern:
Comparison/ordering
policies/algorithms are “strategized.”
• Arrays.sort()andCollections.sort()aredefinedtosort
array/collectionelementsfrom“smaller”to“bigger”elements.
– Bydefault,“smaller”elementsmeantheelementsthathavelowernumbers.
• Adescendingorderingcanbeimplementedbytreating
“smaller”elementsastheelementsthathavehighernumbers.
• compare()incomparatorclassescandefine(orre-define)what
“small”meansandwhat’s“big”means.
– Returnsanegativeinteger,zero,orapositiveintegerasthefirst
argumentis“smaller”than,“equalto,”or“bigger”thanthe
second.
• public class DescendingOrderComparator implements Comparator{public int compare(Object o1, Object o2){return ((Integer)o2).intValue()-((Integer) o1).intValue();
}}
12
SortingCollectionElementswithaCustomComparator
– ArrayList<Integer> years = new ArrayList<Integer>();years.add(new Integer(2010)); years.add(new Integer(2000));years.add(new Integer(1997)); years.add(new Integer(2006));Collections.sort(years);for(Integer y: years)
System.out.println(y);Collections.sort(years, new DescendingOrderComparator()); for(Integer y: years)
System.out.println(y);
– 1997 -> 2000 -> 2006 -> 2010– 2010 -> 2006 -> 2000 -> 1997
13
• public class DescendingOrderComparator implements Comparator{public int compare(Object o1, Object o2){return ((Integer)o2).intValue()-((Integer) o1).intValue();
}}
• Amoretype-safeoptionisavailable/recommended:
• public class DescendingOrderComparator<Integer>{implements Comparator<Integer>{public int compare(Integer o1, Integer o2){return o2.intValue()-o1.intValue();
}}
14
Okay,soWhat’sthePoint?• Withoutalambdaexpression
– public class DescendingOrderComparator<Integer>{implements Comparator<Integer>{public int compare(Integer o1, Integer o2){return o2.intValue()-o1.intValue();
}}Collections.sort(years, new DescendingOrderComparator());
• Withalambdaexpression
– Collections.sort(years,(Integer o1, Integer o2)->o2.intValue()–o1.intValue());
• Codegetsmoreconcise(shorterandsimpler).
– ThelambdaexpressiondefinesDescendingOrderComparator’scompare() inaconciseway.
– Morereadableandlessuglythanthecodebasedonan
anonymousclass.
• TheLEversionisasyntacticsugarforthenon-LEversion.– Yourcompilerdoesprogramtransformationatcompilationtime.
15
FYI:AnonymousClass• Themostexpressive(default)version
– public class DescendingOrderComparator<Integer>{implements Comparator<Integer>{
public int compare(Integer o1, Integer o2){return o2.intValue()-o1.intValue();
}}Collections.sort(years, new DescendingOrderComparator());
• Withananonymousclass
– Collections.sort(years,new Comparator<Integer>(){
@Overridepublic int compare(Integer o1, Integer o2){
return o2.intValue()-o1.intValue();}
} );
• Withalambdaexpression
– Collections.sort(years,(Integer o1, Integer o2)->o2.intValue()–o1.intValue());
16
HowDoYouKnowWhereYoucanUseaLambdaExpression?
• YouaretryingtouseCollections.sort(List, Comparator<T>)
• CheckoutComparator intheAPIdoc.
• Notice thatComparator isafunctionalinterface.– @FunctionalInterface
public interface Comparator<T>• TheAPIdocsays“Thisisafunctionalinterfaceandcanthereforebeusedasthe
assignmenttargetforalambdaexpression…”
– Thismeansyoucanpassalambdaexpressiontosort().
• Findoutwhichmethodistheonlyabstract/empty(i.e.,non-static,
non-default)method.
– public int compare(T o1, T o2)
• Definealambdaexpressiontorepresentthemethodbodyof
compare() andpassittosort().– Collections.sort( aList,
(Integer first, Integer second)->second.intValue()–first.intValue())
17
AssignmentofaLEtoaFunctionalInterface• Comparator isafunctionalinterface.
– @FunctionalInterfacepublic interface Comparator<T>
• TheAPIdocsays“Thisisafunctionalinterfaceandcanthereforebe
usedastheassignmenttargetforalambdaexpression…”
• Alambdaexpressioncanbeassignedtoavariablethat
istypedwithafunctionalinterface.
– Comparator<Integer> comparator =(Integer o1, Integer o2)-> o2.intValue()–o1.intValue();
Collections.sort(years, comparator);
• Parametertypescanbeomittedthrutypeinference.
– Comparator<Integer> comparator =(o1, o2)-> o2.intValue()–o1.intValue()
– C.f.Typeinferencewiththediamondoperator(introducedinJava7).
18
WhatdoesCollections.sort()do?• class Collections
static ... sort(List<T> list, Comparator<T> c){for each pair (o1 and o2) of elements in list{
int result = c.compare(o1, o2);if(result < 0){
...}else if(result > 0){
...}else if(result==0){
...} } }
• C.f.Runthistwo-linecode.
– Comparator<Integer> comparator =(Integer o1, Integer o2)-> o2.intValue()–o1.intValue();
comparator.compare(1, 10);
– compare()returns9(10- 1).
19
SomeNotes• Alambdaexpressioncanbeassignedtoa
functionalinterface.
– public interface Comparator<T>{public int compare(T o1, T o2)
}Comparator<Integer> comparator =
(Integer o1, Integer o2)-> o2.intValue()–o1.intValue()– Collections.sort(years, comparator);
• ItcannotbeassignedtoObject.– Object comparator =
(Integer o1, Integer o2)-> o2.intValue()–o1.intValue()
20
• Withoutalambdaexpression
– public class DescendingOrderComparator<Integer>{implements Comparator<Integer>{
public int compare(Integer o1, Integer o2){return o2.intValue()-o1.intValue();
}}Collections.sort(years, new DescendingOrderComparator());
• Withalambdaexpression
– Collections.sort(years,(Integer o1, Integer o2)->o2.intValue()–o1.intValue());
• Atypemismatchresultsinacompilationerror.
– Collections.sort(years,(Integer o1, Integer o2)->o2.floatValue()–o1.floatValue());
– Thereturnvaluetypemustbeint,notfloat.
• compare()isexpectedtoreturnanint value.
21
• Alambdaexpressioncannotthrowanexception
– ifitscorrespondingfunctionalinterfacedoesnotspecifythat
fortheabstract/emptymethod.
• Notgood(Compilationfails.)
– public interface Comparator<T>{public int compare(T o1, T o2)
}– Collections.sort(years,(Integer o1, Integer o2)->{
if(...) throw new XYZException;else return ... );
• Good
– public interface Comparator<T>{public int compare(T o1, T o2) throws ZYZException
}– Collections.sort(years,(Integer o1, Integer o2)->{
if(...) throw new XYZException;else return ... );
22
LEsmakeYourCodeConcise,but…• Youstillneedtoclearlyunderstand
– theStrategydesignpattern
• Comparatoranditsimplementationclasses
• Whatcompare() ismeanttodo
– HowCollection.sort() callscompare().
• UsingornotusingLEsjustimpacthowtoexpressyourcode.
– Thisdoesnotimpacthowtodesign yourcode.
23
ABenefitofUsingLambdaExpressions• Yourcodegetsmoreconcise.
– Thismayormaynotmean“easiertounderstand”
dependingonhowmuchyouarefamiliarwithlambda
expressions.
24