Principles of Programming...

28
Principles of Programming Languages h"p://www.di.unipi.it/~andrea/Dida2ca/PLP-16/ Prof. Andrea Corradini Department of Computer Science, Pisa Lambdas and streams in Java 8 Lesson 26 – Java 8 1

Transcript of Principles of Programming...

PrinciplesofProgrammingLanguagesh"p://www.di.unipi.it/~andrea/Dida2ca/PLP-16/

Prof.AndreaCorradiniDepartmentofComputerScience,Pisa

•  LambdasandstreamsinJava8

Lesson 26 – Java 8!

1

Java8:languageextensions

Java8isthebiggestchangetoJavasincetheincepBonofthelanguage.Mainnewfeatures:•  Lambdaexpressions– Methodreferences– Defaultmethodsininterfaces–  Improvedtypeinference

•  StreamAPIAbigchallengewastointroducelambdaswithoutrequiringrecompilaBonofexisBngbinaries

2

BenefitsofLambdasinJava8

•  EnablingfuncBonalprogramming– BeingabletopassbehaviorsaswellasdatatofuncBons

–  IntroducBonoflazyevaluaBonwithstreamprocessing

•  WriBngcleanerandmorecompactcode•  FacilitaBngparallelprogramming•  Developingmoregeneric,flexibleandreusableAPIs

3

Lambdaexpressionsyntax:Printalistofintegerswithalambda

•  x -> System.out.println(x) isalambdaexpressionthatdefinesananonymousfunc+on(method)withoneparameternamedxoftypeInteger

4

List<Integer> intSeq = Arrays.asList(1,2,3); intSeq.forEach(x -> System.out.println(x));

// equivalent syntax intSeq.forEach((Integer x) -> System.out.println(x)); intSeq.forEach(x -> {System.out.println(x);}); intSeq.forEach(System.out::println); //method reference

•  Typeofparameterinferredbythecompilerifmissing

MulBlinelambda,localvariables,variablecapture,nonewscope

5

List<Integer> intSeq = Arrays.asList(1,2,3); // multiline: curly brackets necessary intSeq.forEach(x -> { x += 2; System.out.println(x); }); // local variable declaration intSeq.forEach(x -> { int y = x + 2; System.out.println(y); }); // variable capture [final] int y = 2; // must be [effectively] final intSeq.forEach(x -> {

System.out.println(x + y); }); // no new scope!!! int x = 0; intSeq.forEach(x -> { //error: x already defined

System.out.println(x + 2); });

ImplementaBonofJava8Lambdas•  TheJava8compilerfirstconvertsalambdaexpression

intoafuncBon,compilingitscode•  ThenitgeneratescodetocallthecompiledfuncBon

whereneeded•  Forexample,x -> System.out.println(x) couldbe

convertedintoageneratedstaBcfuncBonpublic static void genName(Integer x) { System.out.println(x); }

•  ButwhattypeshouldbegeneratedforthisfuncBon?Howshoulditbecalled?Whatclassshoulditgoin?

6

FuncBonalInterfaces•  Designdecision:Java8lambdasareinstancesoffunc+onalinterfaces.

•  Afunc<onalinterfaceisaJavainterfacewithexactlyoneabstractmethod.E.g.,

7

public interface Comparator<T> { //java.util int compare(T o1, T o2); } public interface Runnable { //java.lang void run(); } public interface Callable<V> {//java.util.concurrent V call() throws Exception; }

FuncBonalinterfacesandlambdas•  FuncBonalInterfacescanbeusedastargettypeoflambda

expressions,i.e.–  Astypeofvariabletowhichthelambdaisassigned–  Astypeofformalparametertowhichthelambdaispassed

•  Thecompilerusestypeinferencebasedontargettype•  Argumentsandresulttypesofthelambdamustmatch

thoseoftheuniqueabstractmethodofthefuncBonalinterface

•  LambdascanbeinterpretedasinstancesofanonymousinnerclassesimplemenBngthefuncBonalinterface

•  ThelambdaisinvokedbycallingtheonlyabstractmethodofthefuncBonalinterface

8

Anexample:Frominnerclasses...

9

public class Calculator1 { // Pre Java 8 interface IntegerMath { // (inner) functional interface int operation(int a, int b); } public int operateBinary(int a, int b, IntegerMath op) { return op.operation(a, b); } // parameter type is functional interface // inner class implementing the interface

static class IntMath$Add implements IntegerMath{ public int operation(int a, int b){ return a + b; }}

public static void main(String... args) { Calculator1 myApp = new Calculator1();

System.out.println("40 + 2 = " + myApp.operateBinary(40, 2, new IntMath$Add())); // anonymous inner class implementing the interface

IntegerMath subtraction = new IntegerMath(){ public int operation(int a, int b){ return a - b; }; };

System.out.println("20 - 10 = " + myApp.operateBinary(20, 10, subtraction));

}}

…tolambdaexpressions

10

public class Calculator { interface IntegerMath { // (inner) functional interface int operation(int a, int b); } public int operateBinary(int a, int b, IntegerMath op) { return op.operation(a, b); } // parameter type is functional interface public static void main(String... args) { Calculator myApp = new Calculator();

// lambda assigned to functional interface variables IntegerMath addition = (a, b) -> a + b; System.out.println("40 + 2 = " + myApp.operateBinary(40, 2, addition));

// lambda passed to functional interface formal parameter System.out.println("20 - 10 = " +

myApp.operateBinary(20, 10, (a, b) -> a - b)); } }

Otherexamplesoflambdas:Runnable

11

public class ThreadTest {// using functional interface Runnable public static void main(String[] args) { Runnable r1 = new Runnable() { // anonymous inner class @Override public void run() { System.out.println("Old Java Way"); } }; Runnable r2 = () -> { System.out.println("New Java Way"); }; new Thread(r1).start(); new Thread(r2).start(); } }

// constructor of class Thread public Thread(Runnable target)

Otherexamplesoflambdas:Listener

12

JButton button = new JButton("Click Me!"); // pre Java 8 button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { System.out.println("Handled by anonymous class listener"); } }); // Java 8 button.addActionListener(

e -> System.out.println("Handled by Lambda listener"));

NewFuncBonalInterfacesinpackagejava.uBl.funcBon

13

public interface Consumer<T> { //java.util.function void accept(T t); } public interface Supplier<T> { //java.util.function T get(); } public interface Predicate<T> { //java.util.function boolean test(T t); } public interface Function <T,R> { //java.util.function R apply(T t); }

Otherexamplesoflambdas

14

List<Integer> intSeq = new ArrayList<>(Arrays.asList(1,2,3)); // sort list in descending order using Comparator<Integer> intSeq.sort((x,z) -> z - x); // lambda with two arguments intSeq.forEach(System.out::println); // remove odd numbers using a Predicate<Integer> intSeq.removeIf(x -> x%2 == 1); intSeq.forEach(System.out::println); // prints only ‘2’

// default method of Interface List<E> default void sort(Comparator<? super E> c) // default method of Interface Collection<E> default boolean removeIf(Predicate<? super E> filter) // default method of Interface Iterable<T> default void forEach(Consumer<? super T> action)

DefaultMethods

AddingnewabstractmethodstoaninterfacebreaksexisBngimplementaBonsoftheinterfaceJava8allowsinterfacetoinclude•  Abstract(instance)methods,asusual•  Sta<cmethods•  Defaultmethods,definedintermsofotherpossibly

abstractmethodsJava8useslambdaexpressionsanddefaultmethodsinconjuncBonwiththeJavacollecBonsframeworktoachievebackwardcompa+bilitywithexisBngpublishedinterfaces

15

MethodReferences

MethodReferenceType

Syntax Example

staBc ClassName::StaBcMethodName String::valueOfconstructor ClassName::new ArrayList::newspecificobjectinstance

objectReference::MethodName x::toString

arbitraryobjectofagiventype

ClassName::InstanceMethodName Object::toString

16

•  MethodreferencescanbeusedtopassanexisBngfuncBoninplaceswherealambdaisexpected

•  ThesignatureofthereferencedmethodneedstomatchthesignatureofthefuncBonalinterfacemethod

StreamsinJava8Thenewjava.u<l.streampackageprovidesuBliBestosupportfuncBonal-styleoperaBonsonstreamsofvalues.Streamsdifferfromcollec%onsinseveralways:•  Nostorage.Astreamisnotadatastructurethatstoreselements;instead,itconveyselementsfromasource(adatastructure,anarray,ageneratorfuncBon,anI/Ochannel,…)throughapipelineofcomputaBonaloperaBons.

•  Func<onalinnature.AnoperaBononastreamproducesaresult,butdoesnotmodifyitssource.

17

StreamsinJava8(cont’d)•  Laziness-seeking.ManystreamoperaBons,suchasfiltering,

mapping,orduplicateremoval,canbeimplementedlazily,exposingopportuniBesforopBmizaBon.StreamoperaBonsaredividedintointermediate(stream-producing)operaBonsandterminal(value-orside-effect-producing)operaBons.Intermediateopera%onsarealwayslazy.

•  Possiblyunbounded.WhilecollecBonshaveafinitesize,streamsneednot.Short-circuiBngoperaBonssuchaslimit(n)orfindFirst()canallowcomputaBonsoninfinitestreamstocompleteinfiniteBme.

•  Consumable.Theelementsofastreamareonlyvisitedonceduringthelifeofastream.LikeanIterator,anewstreammustbegeneratedtorevisitthesameelementsofthesource.

18

Pipelines

•  Atypicalpipelinecontains–  Asource,producing(byneed)theelementsofthestream–  Zeroormoreintermediateopera+ons,producingstreams–  Aterminalopera+on,producingside-effectsornon-streamvalues

•  Exampleoftypicalpahern:filter/map/reduce

19

double average = listing // collection of Person .stream() // stream wrapper over a collection .filter(p -> p.getGender() == Person.Sex.MALE) // filter .mapToInt(Person::getAge) // extracts stream of ages .average() // computes average (reduce/fold) .getAsDouble(); // extracts result from OptionalDouble

AnatomyoftheStreamPipeline•  AStreamisprocessedthroughapipelineofoperaBons•  AStreamstartswithasource•  IntermediatemethodsareperformedontheStream

elements.ThesemethodsproduceStreamsandarenotprocessedunBltheterminalmethodiscalled.

•  TheStreamisconsideredconsumedwhenaterminaloperaBonisinvoked.NootheroperaBoncanbeperformedontheStreamelementsaierwards

•  AStreampipelinecontainssomeshort-circuitmethods(whichcouldbeintermediateorterminalmethods)thatcausetheearlierintermediatemethodstobeprocessedonlyunBltheshort-circuitmethodcanbeevaluated.

StreamsourcesStreamscanbeobtainedinanumberofways.Someexamplesinclude:•  FromaCollec<onviathestream()andparallelStream()methods;•  FromanarrayviaArrays.stream(Object[]);•  FromstaBcfactorymethodsonthestreamclasses,suchas

Stream.of(Object[]),IntStream.range(int,int)orStream.iterate(Object,UnaryOperator);

•  ThelinesofafilecanbeobtainedfromBufferedReader.lines();•  StreamsoffilepathscanbeobtainedfrommethodsinFiles;•  StreamsofrandomnumberscanbeobtainedfromRandom.ints();•  Numerousotherstream-bearingmethodsintheJDK…

21

IntermediateOperaBons•  AnintermediateoperaBonkeepsastreamopenforfurtheroperaBons.

IntermediateoperaBonsarelazy.•  SeveralintermediateoperaBonshaveargumentsoffunc%onalinterfaces,

thuslambdascanbeused

22

Stream<T> filter(Predicate<? super T> predicate) // filter IntStream mapToInt(ToIntFunction<? super T> mapper) // map f:T -> int <R> Stream<R> map(Function<? super T,? extends R> mapper) // map f:T->R Stream<T> peek(Consumer<? super T> action) //performs action on elements Stream<T> distinct() // remove duplicates – stateful Stream<T> sorted() // sort elements of the stream – stateful Stream<T> limit(long maxSize) // truncate Stream<T> skip(long n) // skips first n elements

TerminalOperaBons•  Aterminalopera<onmustbethefinaloperaBononastream.

OnceaterminaloperaBonisinvoked,thestreamisconsumedandisnolongerusable.

•  Typical:collectvaluesinadatastructure,reducetoavalue,printorothersideeffects.

23

void forEach(Consumer<? super T> action) Object[] toArray() T reduce(T identity, BinaryOperator<T> accumulator) // fold Optional<T> reduce(BinaryOperator<T> accumulator) // fold Optional<T> min(Comparator<? super T> comparator) boolean allMatch(Predicate<? super T> predicate) // short-circuiting boolean anyMatch(Predicate<? super T> predicate) // short-circuiting Optional<T> findAny() // short-circuiting

InfiniteStreams•  StreamswrappingcollecBonsarefinite•  Infinitestreamscanbegeneratedwith:–  iterate– generate

24

static <T> Stream<T> iterate(T seed, UnaryOperator<T> f) // Example: summing first 10 elements of an infinite stream int sum = Stream.iterate(0,x -> x+1).limit(10).reduce(0,(x,s) -> x+s); static <T> Stream<T> generate(Supplier<T> s) // Example: printing 10 random mumbers Stream.generate(Math::random).limit(10).forEach(System.out::println); <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)

Parallelism&StreamsfromCollecBons

•  StreamsfacilitateparallelexecuBon•  StreamoperaBonscanexecuteeitherinserial(default)orinparallel

•  AstreamwrappingacollecBonusesaSplititeratoroverthecollecBon

•  Doesnotprovidemethodsforreturningelementsbut–  Forapplyinganac%ontothenextortoallremainingelements

–  Forspli=ng:Ifparallel,thesplit()methodcreatesanewSpliBteratorandparBBonsthestream

25

CriBcalissues•  Non-interference–  Behaviouralparameters(likelambdas)ofstreamoperaBonsshouldnotaffectthesource(non-interferingbehaviour)

–  RiskofConcurrentModificaBonExcepBons,evenifinsinglethread

•  Statelessbehaviours–  StatlessbehaviourforintermediateoperaBonsisencouraged,asitfacilitatesparallelism,andfuncBonalstyle,thusmaintenance

•  Parallelismandthreadsafety–  Forparallelstreams,ensuringthreadsafetyistheprogrammers’responsibility

26

MonadsinJava:OpBonalandStream

27

static <T> Stream<T> of(T t) // Returns a sequential Stream containing a single element. <R> Stream<R> flatMap( Function<? super T,? extends Stream<? extends R>> mapper) /* Returns a stream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element. */

public static <T> Optional<T> of(T value) // Returns an Optional with the specified present non-null value. <U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper) /* If a value is present, apply the provided Optional-bearing mapping function to it, return that result, otherwise return an empty Optional. */

References

•  TheJavaTutorials,hhp://docs.oracle.com/javase/tutorial/java/index.html

•  LambdaExpressions,hhp://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

•  AdibSaikali,Java8LambdaExpressionsandStreams,hhps://www.youtube.com/watch?v=8pDm_kH4YKY

•  BrianGoetz,LambdasinJava:Apeekunderthehood.hhps://www.youtube.com/watch?v=MLksirK9nnE

28