3. 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
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 Constructs to Java Infrastructure
• Change the parser
• Retrofit collections to work with functional
• Type inference and Functions
• Method References
5
6. 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
7. 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
8. 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
9. 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
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 – 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
13. 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
14. 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
15. 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!
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
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
18. 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
19. 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
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