 Functional Extensions in Java 8 Jörn Guy Süß October 2016
Agenda Motivation Basic Principle (API Blocks) Streams Impedance Problems (Nulls, IO) Questions 2 1 2 3 4 5
Why add functional to Java? 1. Syntax Improvement: Inner Classes are a syntactic pain 2. Performance for all: Fork/Join framework is for experts 3. Cloud Languages: „new“ languages have closures 3
An Example  IntStream.iterate(0, n -> (n+1)%2) .distinct() .limit(10) .forEach(System.out::println);  Typical example: stream, closure, terminal operation 4 Create Stream Apply Mapping Export Outcomes Invocation is lazy from the terminal operation
Attaching Functional Constructs to Java Infrastructure • Change the parser • Retrofit collections to work with functional • Type inference and Functions • Method References 5
What can you write Lambda expression Meaning Interface ()->System.out.println() It takes no arguments and displays a single line Consumer<Void> ??? x->System.out.println(x) It takes a single argument and displays it on a line Consumer<T> x->2*x It takes a single argument and returns its double Function<T> (x,y)->x+y It takes two arguments and returns their sum BiFunction<T,U> x -> { int y = 2*x; return y; } It takes a single argument and returns its double using multiple statements Function<T> x -> y -> x + y Curried Function Function<T, Function<U,V>> System.out::println Method Reference Consumer<T> 6 ... Typical Functional Expressions
Retrofit Collections  Collections need to be a source of closures streams with no hassle  We cannot break the collection implementations interface to add methods  Lets add them to the interface then  Interfaces now have default methods …  All collections now have Spliterator that produces the stream 7 Or: How interfaces got implementations
Type Check and Functions  If a Lambda is an inner class, how do we know if that class fits as a parameter to a method?  We can use an interface to describe the requirement.  Ok, but if we try to fit the lambda to the method signatures in the interface, which should we pick if there are several fits?  Well than we have to make that impossible.  Interfaces with only one method?  One functional method. The others can be default remember? Lets call these @FunctionalInterface  Completely clear. 8
Method References  If I just want to invoke a method, does that mean I have to always write a lambda and implicitly produce an inner class?  No, we could use invokeDynamic and Method Handles from Java 7, and you can write something like System.out::println  In fact, we can use invokeDynamic for all lambda expressions when we store the bytecode.  That seems complex. Luckily stack overflow has more details: http://stackoverflow.com/questions/30002380/why-are-java-8- lambdas-invoked-using-invokedynamic 9
API Blocks – Sources and Sinks  Supplier<T>s: Allow you to T get() items for streams  Function<T,U>: You can U apply(T) them to items  Consumers<T>s: Will accept(T) items from streams  Predicate<T>: You can boolean test(T) items  And lots of ...  versions for Primitive Types, like IntSupplier and ObjDoubleConsumer  conversion functions like ToIntFunction 10 These are the essential concepts of stream processing
API Blocks – Special Functions and Constructs  (Unary|Binary)Operator: Functions with homogenous argument types  Bi(Supplier|Function|Consumer|Predicate): Operate on pairs: stream = Arrays.stream(rectangles); total = stream .map(r -> r.scale(0.25)) .mapToInt(Rectangle::getArea) .reduce(0,(r, s) -> r + s); (Pair versions of the conversion functions as seen before) 11
Streams – Creating one 1. Use a .stream() method from some glue code 2. Call of(T ...) and convert the varargs array 3. Call builder(), add items, and pump it out 4. Call generate(Supplier<T>) e.g. for making endless streams 5. Call empty() 12 A stream is a sequential process abstraction for mutable objects that is not reusable
Streams – Consuming one Caveat: Streams are lazy in the functional sense. Unless and until a terminal operation is called, no processing occurs. To terminate your stream you can: 1. Use a forEach(Ordered)() to produce a side-effect 2. Call toArray(T ...) to convert the result to an array 13 Eventually, every stream leaves the functional zone to interface with IO
Stream: Getting a single result  count() the elements  min|max() biggest, smallest element  find(First|Any)() obtain an element  (none|all|any)Match() the logical quantifiers ∄, ∀, ∃  sorted() find out if the stream is sorted  reduce|collect(): aggregate elements (functional fold operation) 14 Streams are often used to „teles- cope fold“ data into a single output
Getting a stream from a stream  filter(): remove anything that does not match  limit()/skip(): take only / skip N elements  map(): apply a transformation function  peek(): run an output on each passing item – Progress bars and loggers!  concat(): append one stream to another  sort() : ensure elements are ordered  distinct(): ensure elements are distinct 15 Streams can be „conveyor belts“ for manipulating items sequentially Do not work on endless streams!
Numeric Streams – First Class API citizens  Suppliers, Consumers, Predicates  Operators on numeric values*  Functions to convert between other types the numeric value: from, to*  Numeric Streams with special functions for boxing  Collectors over streams for Sums, Summaries (Hashes) and Averages * A version with two arguments (BiFunction) is also available 16 int, long and double have ready-made implementations of Stream Interfaces
Stream Collectors  group sort the elements into a number of groups using a function  partition split the elements into disjunct collections using a predicate  joining Strings with prefix, seperator and postfix  Conversion to Collection, List, Set, Map 17 Collectors are SQL-like domain functions to run in collect() calls
Stream, Spliterator and Parallel Processing Each Stream is based on a Spliterator which can  invoke a terminal operation on one (tryAdvance) or all (forEachRemaining) of its contents  attempt to split another Spliterator of (trySplit) for parallel processing  estimate its content size (estimateSize)  provide its Comparator if its source is sorted  Provide its characteristics() based on theses Characteristics the streams framework decides if parallel processing is possible, and enables it if desired and/or opportune. 18 parallel()/sequential() change the parallel stream processing advice
Spliterator Characteristics IMMUTABLE the element source cannot be structurally modified; that is, elements cannot be added, replaced, or removed, so such changes cannot occur during traversal. CONCURRENT the element source may be safely concurrently modified (allowing additions, replacements, and/or removals) by multiple threads without external synchronization. NONNULL the source guarantees that encountered elements will not be null. SIZED the value returned from estimateSize() prior to traversal or splitting represents a finite size that, in the absence of structural source modification, represents an exact count of the number of elements that would be encountered by a complete traversal. SUBSIZED all Spliterators resulting from trySplit() will be both SIZED and SUBSIZED. This means that all child Spliterators, whether direct or indirect, will be SIZED. ORDERED an encounter order is defined for elements. DISTINCT for each pair of encountered elements x, y, !x.equals(y). SORTED encounter order follows a defined sort order. Confidential – Oracle Internal/Restricted/Highly Restricted 19
Impedance Problems (Nulls, IO)  Optional<T> is a monad that works with null Values  empty()  of(Nullable)(T)  boolean isPresent() is used with filter() and T get() is used with map()  Streams are AutoCloseable, create them in try-with-resources if you use IO  Example: Stream<JarItem> JarFile.stream() 20 Facilities to handle exceptional flow and null values

A Brief Conceptual Introduction to Functional Java 8 and its API

  • 1.
     Functional Extensions inJava 8 Jörn Guy Süß October 2016
  • 2.
    Agenda Motivation Basic Principle (APIBlocks) Streams Impedance Problems (Nulls, IO) Questions 2 1 2 3 4 5
  • 3.
    Why add functionalto Java? 1. Syntax Improvement: Inner Classes are a syntactic pain 2. Performance for all: Fork/Join framework is for experts 3. Cloud Languages: „new“ languages have closures 3
  • 4.
    An Example  IntStream.iterate(0,n -> (n+1)%2) .distinct() .limit(10) .forEach(System.out::println);  Typical example: stream, closure, terminal operation 4 Create Stream Apply Mapping Export Outcomes Invocation is lazy from the terminal operation
  • 5.
    Attaching Functional Constructsto Java Infrastructure • Change the parser • Retrofit collections to work with functional • Type inference and Functions • Method References 5
  • 6.
    What can youwrite Lambda expression Meaning Interface ()->System.out.println() It takes no arguments and displays a single line Consumer<Void> ??? x->System.out.println(x) It takes a single argument and displays it on a line Consumer<T> x->2*x It takes a single argument and returns its double Function<T> (x,y)->x+y It takes two arguments and returns their sum BiFunction<T,U> x -> { int y = 2*x; return y; } It takes a single argument and returns its double using multiple statements Function<T> x -> y -> x + y Curried Function Function<T, Function<U,V>> System.out::println Method Reference Consumer<T> 6 ... Typical Functional Expressions
  • 7.
    Retrofit Collections  Collectionsneed to be a source of closures streams with no hassle  We cannot break the collection implementations interface to add methods  Lets add them to the interface then  Interfaces now have default methods …  All collections now have Spliterator that produces the stream 7 Or: How interfaces got implementations
  • 8.
    Type Check andFunctions  If a Lambda is an inner class, how do we know if that class fits as a parameter to a method?  We can use an interface to describe the requirement.  Ok, but if we try to fit the lambda to the method signatures in the interface, which should we pick if there are several fits?  Well than we have to make that impossible.  Interfaces with only one method?  One functional method. The others can be default remember? Lets call these @FunctionalInterface  Completely clear. 8
  • 9.
    Method References  IfI just want to invoke a method, does that mean I have to always write a lambda and implicitly produce an inner class?  No, we could use invokeDynamic and Method Handles from Java 7, and you can write something like System.out::println  In fact, we can use invokeDynamic for all lambda expressions when we store the bytecode.  That seems complex. Luckily stack overflow has more details: http://stackoverflow.com/questions/30002380/why-are-java-8- lambdas-invoked-using-invokedynamic 9
  • 10.
    API Blocks –Sources and Sinks  Supplier<T>s: Allow you to T get() items for streams  Function<T,U>: You can U apply(T) them to items  Consumers<T>s: Will accept(T) items from streams  Predicate<T>: You can boolean test(T) items  And lots of ...  versions for Primitive Types, like IntSupplier and ObjDoubleConsumer  conversion functions like ToIntFunction 10 These are the essential concepts of stream processing
  • 11.
    API Blocks –Special Functions and Constructs  (Unary|Binary)Operator: Functions with homogenous argument types  Bi(Supplier|Function|Consumer|Predicate): Operate on pairs: stream = Arrays.stream(rectangles); total = stream .map(r -> r.scale(0.25)) .mapToInt(Rectangle::getArea) .reduce(0,(r, s) -> r + s); (Pair versions of the conversion functions as seen before) 11
  • 12.
    Streams – Creatingone 1. Use a .stream() method from some glue code 2. Call of(T ...) and convert the varargs array 3. Call builder(), add items, and pump it out 4. Call generate(Supplier<T>) e.g. for making endless streams 5. Call empty() 12 A stream is a sequential process abstraction for mutable objects that is not reusable
  • 13.
    Streams – Consumingone Caveat: Streams are lazy in the functional sense. Unless and until a terminal operation is called, no processing occurs. To terminate your stream you can: 1. Use a forEach(Ordered)() to produce a side-effect 2. Call toArray(T ...) to convert the result to an array 13 Eventually, every stream leaves the functional zone to interface with IO
  • 14.
    Stream: Getting asingle result  count() the elements  min|max() biggest, smallest element  find(First|Any)() obtain an element  (none|all|any)Match() the logical quantifiers ∄, ∀, ∃  sorted() find out if the stream is sorted  reduce|collect(): aggregate elements (functional fold operation) 14 Streams are often used to „teles- cope fold“ data into a single output
  • 15.
    Getting a streamfrom a stream  filter(): remove anything that does not match  limit()/skip(): take only / skip N elements  map(): apply a transformation function  peek(): run an output on each passing item – Progress bars and loggers!  concat(): append one stream to another  sort() : ensure elements are ordered  distinct(): ensure elements are distinct 15 Streams can be „conveyor belts“ for manipulating items sequentially Do not work on endless streams!
  • 16.
    Numeric Streams –First Class API citizens  Suppliers, Consumers, Predicates  Operators on numeric values*  Functions to convert between other types the numeric value: from, to*  Numeric Streams with special functions for boxing  Collectors over streams for Sums, Summaries (Hashes) and Averages * A version with two arguments (BiFunction) is also available 16 int, long and double have ready-made implementations of Stream Interfaces
  • 17.
    Stream Collectors  groupsort the elements into a number of groups using a function  partition split the elements into disjunct collections using a predicate  joining Strings with prefix, seperator and postfix  Conversion to Collection, List, Set, Map 17 Collectors are SQL-like domain functions to run in collect() calls
  • 18.
    Stream, Spliterator andParallel Processing Each Stream is based on a Spliterator which can  invoke a terminal operation on one (tryAdvance) or all (forEachRemaining) of its contents  attempt to split another Spliterator of (trySplit) for parallel processing  estimate its content size (estimateSize)  provide its Comparator if its source is sorted  Provide its characteristics() based on theses Characteristics the streams framework decides if parallel processing is possible, and enables it if desired and/or opportune. 18 parallel()/sequential() change the parallel stream processing advice
  • 19.
    Spliterator Characteristics IMMUTABLE theelement source cannot be structurally modified; that is, elements cannot be added, replaced, or removed, so such changes cannot occur during traversal. CONCURRENT the element source may be safely concurrently modified (allowing additions, replacements, and/or removals) by multiple threads without external synchronization. NONNULL the source guarantees that encountered elements will not be null. SIZED the value returned from estimateSize() prior to traversal or splitting represents a finite size that, in the absence of structural source modification, represents an exact count of the number of elements that would be encountered by a complete traversal. SUBSIZED all Spliterators resulting from trySplit() will be both SIZED and SUBSIZED. This means that all child Spliterators, whether direct or indirect, will be SIZED. ORDERED an encounter order is defined for elements. DISTINCT for each pair of encountered elements x, y, !x.equals(y). SORTED encounter order follows a defined sort order. Confidential – Oracle Internal/Restricted/Highly Restricted 19
  • 20.
    Impedance Problems (Nulls,IO)  Optional<T> is a monad that works with null Values  empty()  of(Nullable)(T)  boolean isPresent() is used with filter() and T get() is used with map()  Streams are AutoCloseable, create them in try-with-resources if you use IO  Example: Stream<JarItem> JarFile.stream() 20 Facilities to handle exceptional flow and null values