SlideShare a Scribd company logo
Functional Programming
With JDK8
Simon Ritter
Head of Java Technology Evangelism
Oracle Corp.
Twitter: @speakjava
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Safe Harbor Statement
The following is intended to outline our general product direction. It is intended for
information purposes only, and may not be incorporated into any contract. It is not a
commitment to deliver any material, code, or functionality, and should not be relied upon
in making purchasing decisions. The development, release, and timing of any features or
functionality described for Oracle’s products remains at the sole discretion of Oracle.
2
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Lambda Expressions
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
1996 … 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014
1.0 5.0 6 7 8
java.lang.Thread
java.util.concurrent
(jsr166)
Fork/Join Framework
(jsr166y)
Project LambdaConcurrency in Java
Phasers, etc
(jsr166)
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
The Problem: External Iteration
List<Student> students = ...
double highestScore = 0.0;
for (Student s : students) {
if (s.getGradYear() == 2011) {
if (s.getScore() > highestScore)
highestScore = s.score;
}
}
• Our code controls iteration
• Inherently serial: iterate from
beginning to end
• Not thread-safe
• Business logic is stateful
• Mutable accumulator variable
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Internal Iteration With Inner Classes
• Iteration handled by the library
• Not inherently serial – traversal may
be done in parallel
• Traversal may be done lazily – so one
pass, rather than three
• Thread safe – client logic is stateless
• High barrier to use
– Syntactically ugly
More Functional
double highestScore = students
.filter(new Predicate<Student>() {
public boolean op(Student s) {
return s.getGradYear() == 2011;
}
})
.map(new Mapper<Student,Double>() {
public Double extract(Student s) {
return s.getScore();
}
})
.max();
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Internal Iteration With Lambdas
List<Student> students = ...
double highestScore = students
.filter(Student s -> s.getGradYear() == 2011)
.map(Student s -> s.getScore())
.max();
• More readable
• More abstract
• Less error-prone
NOTE: This is not JDK8 code
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Lambda Expressions
• Lambda expressions represent anonymous functions
– Same structure as a method
• typed argument list, return type, set of thrown exceptions, and a body
– Not associated with a class
• We now have parameterised behaviour, not just values
Some Details
double highestScore = students
.filter(Student s -> s.getGradYear() == 2011)
.map(Student s -> s.getScore())
.max();
What
How
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Lambda Expression Types
• Single-method interfaces are used extensively in Java
– Definition: a functional interface is an interface with one abstract method
– Functional interfaces are identified structurally
– The type of a lambda expression will be a functional interface
• Lambda expressions provide implementations of the abstract method
interface Comparator<T> { boolean compare(T x, T y); }
interface FileFilter { boolean accept(File x); }
interface Runnable { void run(); }
interface ActionListener { void actionPerformed(…); }
interface Callable<T> { T call(); }
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Local Variable Capture
• Lambda expressions can refer to effectively final local variables from the
surrounding scope
– Effectively final: A variable that meets the requirements for final variables (i.e.,
assigned once), even if not explicitly declared final
– Closures on values, not variables
void expire(File root, long before) {
root.listFiles(File p -> p.lastModified() <= before);
}
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
What Does ‘this’ Mean In A Lambda
• ‘this’ refers to the enclosing object, not the lambda itself
• Think of ‘this’ as a final predefined local
• Remember the Lambda is an anonymous function
– It is not associated with a class
– Therefore there can be no ‘this’ for the Lambda
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Referencing Instance Variables
Which are not final, or effectively final
class DataProcessor {
private int currentValue;
public void process() {
DataSet myData = myFactory.getDataSet();
dataSet.forEach(d -> d.use(currentValue++));
}
}
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Referencing Instance Variables
The compiler helps us out
class DataProcessor {
private int currentValue;
public void process() {
DataSet myData = myFactory.getDataSet();
dataSet.forEach(d -> d.use(this.currentValue++);
}
}
‘this’ (which is effectively final)
inserted by the compiler
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Type Inference
• The compiler can often infer parameter types in a lambda expression
 Inferrence based on the target functional interface’s method signature
• Fully statically typed (no dynamic typing sneaking in)
– More typing with less typing
List<String> list = getList();
Collections.sort(list, (String x, String y) -> x.length() - y.length());
Collections.sort(list, (x, y) -> x.length() - y.length());
static T void sort(List<T> l, Comparator<? super T> c);
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Method References
• Method references let us reuse a method as a lambda expression
FileFilter x = File f -> f.canRead();
FileFilter x = File::canRead;
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Method References
• Format: target_reference::method_name
• Three kinds of method reference
– Static method (e.g. Integer::parseInt)
– Instance method of an arbitary type (e.g. String::length)
– Instance method of an existing object
16
More Detail
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Method References
17
Rules For Construction
Lambda
Method Ref
Lambda
Method Ref
Lambda
Method Ref
(args) -> ClassName.staticMethod(args)
(arg0, rest) -> arg0.instanceMethod(rest)
(args) -> expr.instanceMethod(args)
ClassName::staticMethod
ClassName::instanceMethod
expr::instanceMethod
instanceOf
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Constructor References
• Same concept as a method reference
– For the constructor
Factory<List<String>> f = ArrayList<String>::new;
Factory<List<String>> f = () -> return new ArrayList<String>();
Replace with
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Useful Methods That Can Use Lambdas
• Iterable.forEach(Consumer c)
List<String> myList = ...
myList.forEach(s -> System.out.println(s));
myList.forEach(System.out::println);
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Useful Methods That Can Use Lambdas
• Collection.removeIf(Predicate p)
List<String> myList = ...
myList.removeIf(s -> s.length() == 0)
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Useful Methods That Can Use Lambdas
• List.replaceAll(UnaryOperator o)
List<String> myList = ...
myList.replaceAll(s -> s.toUpperCase());
myList.replaceAll(String::toUpper);
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Useful Methods That Can Use Lambdas
• List.sort(Comparator c)
• Replaces Collections.sort(List l, Comparator c)
List<String> myList = ...
myList.sort((x, y) -> x.length() – y.length());
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Library Evolution
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Library Evolution Goal
• Requirement: aggregate operations on collections
–New methods required on Collections to facilitate this
• This is problematic
– Can’t add new methods to interfaces without modifying all implementations
– Can’t necessarily find or control all implementations
int heaviestBlueBlock = blocks
.filter(b -> b.getColor() == BLUE)
.map(Block::getWeight)
.reduce(0, Integer::max);
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Solution: Default Methods
• Specified in the interface
• From the caller’s perspective, just an ordinary interface method
• Provides a default implementation
• Default only used when implementation classes do not provide a body for the
extension method
• Implementation classes can provide a better version, or not
interface Collection<E> {
default Stream<E> stream() {
return StreamSupport.stream(spliterator());
}
}
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Virtual Extension Methods
• Err, isn’t this implementing multiple inheritance for Java?
• Yes, but Java already has multiple inheritance of types
• This adds multiple inheritance of behavior too
• But not state, which is where most of the trouble is
• Can still be a source of complexity
• Class implements two interfaces, both of which have default methods
• Same signature
• How does the compiler differentiate?
• Static methods also allowed in interfaces in Java SE 8
Stop right there!
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Functional Interface Definition
• An interface
• Must have only one abstract method
– In JDK 7 this would mean only one method (like ActionListener)
• JDK 8 introduced default methods
– Adding multiple inheritance of types to Java
– These are, by definition, not abstract (they have an implementation)
• JDK 8 also now allows interfaces to have static methods
– Again, not abstract
• @FunctionalInterface can be used to have the compiler check
27
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Is This A Functional Interface?
28
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
Yes. There is only
one abstract method
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Is This A Functional Interface?
29
@FunctionalInterface
public interface Predicate<T> {
default Predicate<T> and(Predicate<? super T> p) {…};
default Predicate<T> negate() {…};
default Predicate<T> or(Predicate<? super T> p) {…};
static <T> Predicate<T> isEqual(Object target) {…};
boolean test(T t);
}
Yes. There is still only
one abstract method
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Is This A Functional Interface?
30
@FunctionalInterface
public interface Comparator {
// default and static methods elided
int compare(T o1, T o2);
boolean equals(Object obj);
}
The equals(Object)
method is implicit
from the Object class
Therefore only one
abstract method
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Lambdas In Full Flow:
Streams
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Stream Overview
• Abstraction for specifying aggregate computations
– Not a data structure
– Can be infinite
• Simplifies the description of aggregate computations
– Exposes opportunities for optimisation
– Fusing, laziness and parallelism
At The High Level
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Stream Overview
• A stream pipeline consists of three types of things
– A source
– Zero or more intermediate operations
– A terminal operation
• Producing a result or a side-effect
Pipeline
int total = transactions.stream()
.filter(t -> t.getBuyer().getCity().equals(“London”))
.mapToInt(Transaction::getPrice)
.sum();
Source
Intermediate operation
Terminal operation
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Stream Sources
• From collections and arrays
– Collection.stream()
– Collection.parallelStream()
– Arrays.stream(T array) or Stream.of()
• Static factories
– IntStream.range()
– Files.walk()
• Roll your own
– java.util.Spliterator
Many Ways To Create
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Stream Terminal Operations
• The pipeline is only evaluated when the terminal operation is called
– All operations can execute sequentially or in parallel
– Intermediate operations can be merged
• Avoiding multiple redundant passes on data
• Short-circuit operations (e.g. findFirst)
• Lazy evaluation
– Stream characteristics help identify optimisations
• DISTINT stream passed to distinct() is a no-op
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Maps and FlatMaps
Map Values in a Stream
Map
FlatMap
Input Stream
Input Stream
1-to-1 mapping
1-to-many mapping
Output Stream
Output Stream
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
The Optional Class
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Optional<T>
Reducing NullPointerException Occurrences
String direction = gpsData.getPosition().getLatitude().getDirection();
String direction = “UNKNOWN”;
if (gpsData != null) {
Position p = gpsData.getPosition();
if (p != null) {
Latitude latitude = p.getLatitude();
if (latitude != null)
direction = latitude.getDirection();
}
}
String direction = gpsData.getPosition().getLatitude().getDirection();
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Optional Class
• Terminal operations like min(), max(), etc do not return a direct result
• Suppose the input Stream is empty?
• Optional<T>
– Container for an object reference (null, or real object)
– Think of it like a Stream of 0 or 1 elements
– use get(), ifPresent() and orElse() to access the stored reference
– Can use in more complex ways: filter(), map(), etc
– gpsMaybe.filter(r -> r.lastReading() < 2).ifPresent(GPSData::display);
Helping To Eliminate the NullPointerException
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Optional ifPresent()
Do something when set
if (x != null) {
print(x);
}
opt.ifPresent(x -> print(x));
opt.ifPresent(this::print);
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Optional filter()
Reject certain values of the Optional
if (x != null && x.contains("a")) {
print(x);
}
opt.filter(x -> x.contains("a"))
.ifPresent(this::print);
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Optional map()
Transform value if present
if (x != null) {
String t = x.trim();
if (t.length() > 1)
print(t);
}
opt.map(String::trim)
.filter(t -> t.length() > 1)
.ifPresent(this::print);
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Optional flatMap()
Going deeper
public String findSimilar(String s)
Optional<String> tryFindSimilar(String s)
Optional<Optional<String>> bad = opt.map(this::tryFindSimilar);
Optional<String> similar = opt.flatMap(this::tryFindSimilar);
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Update Our GPS Code
class GPSData {
public Optional<Position> getPosition() { ... }
}
class Position {
public Optional<Latitude> getLatitude() { ... }
}
class Latitude {
public String getString() { ... }
}
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Update Our GPS Code
String direction = Optional.ofNullable(gpsData)
.flatMap(GPSData::getPosition)
.flatMap(Position::getLatitude)
.map(Latitude::getDirection)
.orElse(“None”);
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Stream Examples
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 1
Convert words in list to upper case
List<String> output = wordList
.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 1
Convert words in list to upper case (in parallel)
List<String> output = wordList
.parallelStream()
.map(String::toUpperCase)
.collect(Collectors.toList());
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 2
• BufferedReader has new method
– Stream<String> lines()
Count lines in a file
long count = bufferedReader
.lines()
.count();
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 3
Join lines 3-4 into a single string
String output = bufferedReader
.lines()
.skip(2)
.limit(2)
.collect(Collectors.joining());
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 4
Collect all words in a file into a list
List<String> output = reader
.lines()
.flatMap(line -> Stream.of(line.split(REGEXP)))
.filter(word -> word.length() > 0)
.collect(Collectors.toList());
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 5
List of unique words in lowercase, sorted by length
List<String> output = reader
.lines()
.flatMap(line -> Stream.of(line.split(REGEXP)))
.filter(word -> word.length() > 0)
.map(String::toLowerCase)
.distinct()
.sorted((x, y) -> x.length() - y.length())
.collect(Collectors.toList());
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 6
Create a map: Keys are word length, values are lists of words of that length
Map<Integer, List<String>> result = reader.lines()
.flatMap(line -> Stream.of(line.split(REGEXP)))
.collect(groupingBy(String::length));
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 7
Create a map: Keys are word length, values are how many words of that length
Map<Integer, Long> result = reader.lines()
.flatMap(line -> Stream.of(line.split(REGEXP)))
.collect(groupingBy(String::length, counting()));
Downstream collector
to return count of elements
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 8: Real World
Infinite stream from thermal sensor
private int double currentTemperature;
...
thermalReader
.lines()
.mapToDouble(s ->
Double.parseDouble(s.substring(0, s.length() - 1)))
.map(t -> ((t – 32) * 5 / 9)
.filter(t -> t != currentTemperature)
.peek(t -> listener.ifPresent(l -> l.temperatureChanged(t)))
.forEach(t -> currentTemperature = t);
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 8: Real World
Infinite stream from thermal sensor
private int double currentTemperature;
...
thermalReader
.lines()
.mapToDouble(s ->
Double.parseDouble(s.substring(0, s.length() - )))
.map(t -> ((t – 32) * 5 / 9)
.filter(t -> t != this.currentTemperature)
.peek(t -> listener.ifPresent(l -> l.temperatureChanged(t)))
.forEach(t -> this.currentTemperature = t);
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Advanced Lambdas And Streams
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Exception Handling In
Lambdas
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Exception Handling In Lambda Expressions
• Compiler error: uncaught exception in filter()
Can Be Problematic
public boolean isValid(Object o) throws IOException { ... }
public List<String> processList(List<String> list) throws IOException
{
return list.stream()
.filter(w -> isValid(w))
.collect(Collectors.toList());
}
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Exception Handling In Lambda Expressions
60
Catch the Exception In The Lambda
public double processList(List list) {
return list.stream()
.filter(w -> {
try {
return isValid(w)
} catch (IOException ioe) {
return false;
}
})
.collect(Collectors.toList());
}
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Exception Handling In Lambda Expressions
• Which is great, except you can't use it with Streams
61
Define A New Functional Interface
@FunctionalInterface
public interface PredicateWithException {
public boolean test(String s) throws IOException;
}
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Debugging
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Logging Mid-Stream
The peek() method
List<String> output = reader
.lines()
.flatMap(line -> Stream.of(line.split(REGEXP)))
.filter(word -> word.length() > 5)
.peek(s -> System.out.println(“Word = “ + s))
.collect(Collectors.toList());
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Using peek() To Set A Breakpoint
List<String> output = reader
.lines()
.flatMap(line -> Stream.of(line.split(REGEXP)))
.filter(word -> word.length() > 5)
.peek(s -> s)
.collect(Collectors.toList());
Set breakpoint on peek
Some debuggers don’t like empty bodies
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Streams and Concurrency
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Serial And Parallel Streams
• Collection Stream sources
– stream()
– parallelStream()
• Stream can be made parallel or sequential at any point
– parallel()
– sequential()
• The last call wins
– Whole stream is either sequential or parallel
66
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Parallel Streams
• Implemented underneath using the fork-join framework
• Will default to as many threads for the pool as the OS reports processors
– Which may not be what you want
System.setProperty(
"java.util.concurrent.ForkJoinPool.common.parallelism",
"32767");
• Remember, parallel streams always need more work to process
– But they might finish it more quickly
67
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
When To Use Parallel Streams
• Data set size is important, as is the type of data structure
– ArrayList: GOOD
– HashSet, TreeSet: OK
– LinkedList: BAD
• Operations are also important
– Certain operations decompose to parallel tasks better than others
– filter() and map() are excellent
– sorted() and distinct() do not decompose well
68
Sadly, no simple answer
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
When To Use Parallel Streams
• N = size of the data set
• Q = Cost per element through the Stream pipeline
• N x Q = Total cost of pipeline operations
• The bigger N x Q is the better a parallel stream will perform
• It is easier to know N than Q, but Q can be estimated
• If in doubt, profile
69
Quantative Considerations
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Streams: Pitfalls For The Unwary
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Functional v. Imperative
• For functional programming you should not modify state
• Java supports closures over values, not closures over variables
• But state is really useful…
71
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Counting Methods That Return Streams
72
Still Thinking Imperatively
Set<String> sourceKeySet = streamReturningMethodMap.keySet();
LongAdder sourceCount = new LongAdder();
sourceKeySet.stream()
.forEach(c ->
sourceCount.add(streamReturningMethodMap.get(c).size()));
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Counting Methods That Return Streams
73
Functional Way
sourceKeySet.stream()
.mapToInt(c -> streamReturningMethodMap.get(c).size())
.sum();
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Printing And Counting Functional Interfaces
74
Still Thinking Imperatively
LongAdder newMethodCount = new LongAdder();
functionalParameterMethodMap.get(c).stream()
.forEach(m -> {
output.println(m);
if (isNewMethod(c, m))
newMethodCount.increment();
});
return newMethodCount.intValue();
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Printing And Counting Functional Interfaces
75
More Functional, But Not Pure Functional
int count = functionalParameterMethodMap.get(c).stream()
.mapToInt(m -> {
int newMethod = 0;
output.println(m);
if (isNewMethod(c, m))
newMethod = 1;
return newMethod
})
.sum();
There is still state being
modified in the Lambda
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Printing And Counting Functional Interfaces
76
Even More Functional, But Still Not Pure Functional
int count = functionalParameterMethodMap.get(nameOfClass)
.stream()
.peek(method -> output.println(method))
.mapToInt(m -> isNewMethod(nameOfClass, m) ? 1 : 0)
.sum();
Strictly speaking printing
is a side effect, which is
not purely functional
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
The Art Of Reduction
(Or The Need to Think Differently)
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
A Simple Problem
• Find the length of the longest line in a file
• Hint: BufferedReader has a new method, lines(), that returns a Stream
78
BufferedReader reader = ...
reader.lines()
.mapToInt(String::length)
.max()
.getAsInt();
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Another Simple Problem
• Find the length of the longest line in a file
79
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Naïve Stream Solution
• That works, so job done, right?
• Not really. Big files will take a long time and a lot of resources
• Must be a better approach
80
String longest = reader.lines().
sort((x, y) -> y.length() - x.length()).
findFirst().
get();
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
External Iteration Solution
• Simple, but inherently serial
• Not thread safe due to mutable state
81
String longest = "";
while ((String s = reader.readLine()) != null)
if (s.length() > longest.length())
longest = s;
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Recursive Approach: The Method
82
String findLongestString(String s, int index, List<String> l) {
if (index >= l.size())
return s;
if (index == l.size() - 1) {
if (s.length() > l.get(index).length())
return s;
return l.get(index);
}
String s2 = findLongestString(l.get(start), index + 1, l);
if (s.length() > s2.length())
return s;
return s2;
}
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Recursive Approach: Solving The Problem
• No explicit loop, no mutable state, we’re all good now, right?
• Unfortunately not - larger data sets will generate an OOM exception
83
List<String> lines = new ArrayList<>();
while ((String s = reader.readLine()) != null)
lines.add(s);
String longest = findLongestString("", 0, lines);
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
A Better Stream Solution
• The Stream API uses the well known filter-map-reduce pattern
• For this problem we do not need to filter or map, just reduce
Optional<T> reduce(BinaryOperator<T> accumulator)
• The key is to find the right accumulator
– The accumulator takes a partial result and the next element, and returns a new
partial result
– In essence it does the same as our recursive solution
– Without all the stack frames
• BinaryOperator is a subclass of BiFunction, but all types are the same
• R apply(T t, U u) or T apply(T x, T y)
84
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
A Better Stream Solution
• Use the recursive approach as an accululator for a reduction
85
String longestLine = reader.lines()
.reduce((x, y) -> {
if (x.length() > y.length())
return x;
return y;
})
.get();
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
A Better Stream Solution
• Use the recursive approach as an accululator for a reduction
86
String longestLine = reader.lines()
.reduce((x, y) -> {
if (x.length() > y.length())
return x;
return y;
})
.get();
x in effect maintains state for
us, by always holding the
longest string found so far
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
The Simplest Stream Solution
• Use a specialised form of max()
• One that takes a Comparator as a parameter
• comparingInt() is a static method on Comparator
– Comparator<T> comparingInt(ToIntFunction<? extends T> keyExtractor)
87
reader.lines()
.max(comparingInt(String::length))
.get();
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Conclusions
• Java needs lambda statements
– Significant improvements in existing libraries are required
• Require a mechanism for interface evolution
– Solution: virtual extension methods
• Bulk operations on Collections
– Much simpler with Lambdas
• Java SE 8 evolves the language, libraries, and VM together
Simon Ritter
Oracle Corporartion
Twitter: @speakjava
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.

More Related Content

What's hot (20)

Lambdas and-streams-s ritter-v3
Lambdas and-streams-s ritter-v3Lambdas and-streams-s ritter-v3
Lambdas and-streams-s ritter-v3
Simon Ritter
 
Java: Create The Future Keynote
Java: Create The Future KeynoteJava: Create The Future Keynote
Java: Create The Future Keynote
Simon Ritter
 
Apouc 2014-java-8-create-the-future
Apouc 2014-java-8-create-the-futureApouc 2014-java-8-create-the-future
Apouc 2014-java-8-create-the-future
OUGTH Oracle User Group in Thailand
 
Lambdas and Streams in Java SE 8: Making Bulk Operations simple - Simon Ritter
Lambdas and Streams in Java SE 8: Making Bulk Operations simple - Simon RitterLambdas and Streams in Java SE 8: Making Bulk Operations simple - Simon Ritter
Lambdas and Streams in Java SE 8: Making Bulk Operations simple - Simon Ritter
JAXLondon2014
 
Lessons Learnt With Lambdas and Streams in JDK 8
Lessons Learnt With Lambdas and Streams in JDK 8Lessons Learnt With Lambdas and Streams in JDK 8
Lessons Learnt With Lambdas and Streams in JDK 8
Simon Ritter
 
Java 8 Features
Java 8 FeaturesJava 8 Features
Java 8 Features
Trung Nguyen
 
Lambdas Hands On Lab
Lambdas Hands On LabLambdas Hands On Lab
Lambdas Hands On Lab
Simon Ritter
 
Java SE 8 library design
Java SE 8 library designJava SE 8 library design
Java SE 8 library design
Stephen Colebourne
 
What's New in Java 8
What's New in Java 8What's New in Java 8
What's New in Java 8
javafxpert
 
Introduction to new features in java 8
Introduction to new features in java 8Introduction to new features in java 8
Introduction to new features in java 8
New York City College of Technology Computer Systems Technology Colloquium
 
Java 101
Java 101Java 101
Java 101
javafxpert
 
Whats New in Java 5, 6, & 7 (Webinar Presentation - June 2013)
Whats New in Java 5, 6, & 7 (Webinar Presentation - June 2013)Whats New in Java 5, 6, & 7 (Webinar Presentation - June 2013)
Whats New in Java 5, 6, & 7 (Webinar Presentation - June 2013)
DevelopIntelligence
 
Java 8 features
Java 8 featuresJava 8 features
Java 8 features
Oleg Tsal-Tsalko
 
Java SE 8 best practices
Java SE 8 best practicesJava SE 8 best practices
Java SE 8 best practices
Stephen Colebourne
 
Oracle Keynote from JMagghreb 2014
Oracle Keynote from JMagghreb 2014Oracle Keynote from JMagghreb 2014
Oracle Keynote from JMagghreb 2014
Simon Ritter
 
JDK8 Streams
JDK8 StreamsJDK8 Streams
JDK8 Streams
Bansilal Haudakari
 
Introduction of Java 8 with emphasis on Lambda Expressions and Streams
Introduction of Java 8 with emphasis on Lambda Expressions and StreamsIntroduction of Java 8 with emphasis on Lambda Expressions and Streams
Introduction of Java 8 with emphasis on Lambda Expressions and Streams
Emiel Paasschens
 
New Features Of JDK 7
New Features Of JDK 7New Features Of JDK 7
New Features Of JDK 7
Deniz Oguz
 
Oracle REST Data Services
Oracle REST Data ServicesOracle REST Data Services
Oracle REST Data Services
Chris Muir
 
Java 12 - New features in action
Java 12 -   New features in actionJava 12 -   New features in action
Java 12 - New features in action
Marco Molteni
 
Lambdas and-streams-s ritter-v3
Lambdas and-streams-s ritter-v3Lambdas and-streams-s ritter-v3
Lambdas and-streams-s ritter-v3
Simon Ritter
 
Java: Create The Future Keynote
Java: Create The Future KeynoteJava: Create The Future Keynote
Java: Create The Future Keynote
Simon Ritter
 
Lambdas and Streams in Java SE 8: Making Bulk Operations simple - Simon Ritter
Lambdas and Streams in Java SE 8: Making Bulk Operations simple - Simon RitterLambdas and Streams in Java SE 8: Making Bulk Operations simple - Simon Ritter
Lambdas and Streams in Java SE 8: Making Bulk Operations simple - Simon Ritter
JAXLondon2014
 
Lessons Learnt With Lambdas and Streams in JDK 8
Lessons Learnt With Lambdas and Streams in JDK 8Lessons Learnt With Lambdas and Streams in JDK 8
Lessons Learnt With Lambdas and Streams in JDK 8
Simon Ritter
 
Lambdas Hands On Lab
Lambdas Hands On LabLambdas Hands On Lab
Lambdas Hands On Lab
Simon Ritter
 
What's New in Java 8
What's New in Java 8What's New in Java 8
What's New in Java 8
javafxpert
 
Whats New in Java 5, 6, & 7 (Webinar Presentation - June 2013)
Whats New in Java 5, 6, & 7 (Webinar Presentation - June 2013)Whats New in Java 5, 6, & 7 (Webinar Presentation - June 2013)
Whats New in Java 5, 6, & 7 (Webinar Presentation - June 2013)
DevelopIntelligence
 
Oracle Keynote from JMagghreb 2014
Oracle Keynote from JMagghreb 2014Oracle Keynote from JMagghreb 2014
Oracle Keynote from JMagghreb 2014
Simon Ritter
 
Introduction of Java 8 with emphasis on Lambda Expressions and Streams
Introduction of Java 8 with emphasis on Lambda Expressions and StreamsIntroduction of Java 8 with emphasis on Lambda Expressions and Streams
Introduction of Java 8 with emphasis on Lambda Expressions and Streams
Emiel Paasschens
 
New Features Of JDK 7
New Features Of JDK 7New Features Of JDK 7
New Features Of JDK 7
Deniz Oguz
 
Oracle REST Data Services
Oracle REST Data ServicesOracle REST Data Services
Oracle REST Data Services
Chris Muir
 
Java 12 - New features in action
Java 12 -   New features in actionJava 12 -   New features in action
Java 12 - New features in action
Marco Molteni
 

Similar to Functional programming with_jdk8-s_ritter (20)

Lambdas And Streams in JDK8
Lambdas And Streams in JDK8Lambdas And Streams in JDK8
Lambdas And Streams in JDK8
Simon Ritter
 
Lambdas & Streams
Lambdas & StreamsLambdas & Streams
Lambdas & Streams
C4Media
 
Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...
Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...
Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...
jaxLondonConference
 
Java 8 new features
Java 8 new featuresJava 8 new features
Java 8 new features
Aniket Thakur
 
Java 8
Java 8Java 8
Java 8
vilniusjug
 
Java SE 8
Java SE 8Java SE 8
Java SE 8
Murali Pachiyappan
 
Java8
Java8Java8
Java8
Felipe Mamud
 
Java 8 by example!
Java 8 by example!Java 8 by example!
Java 8 by example!
Mark Harrison
 
Java 8 features
Java 8 featuresJava 8 features
Java 8 features
Maýur Chourasiya
 
Java gets a closure
Java gets a closureJava gets a closure
Java gets a closure
Tomasz Kowalczewski
 
Java 8 Workshop
Java 8 WorkshopJava 8 Workshop
Java 8 Workshop
Mario Fusco
 
Productive Programming in Java 8 - with Lambdas and Streams
Productive Programming in Java 8 - with Lambdas and Streams Productive Programming in Java 8 - with Lambdas and Streams
Productive Programming in Java 8 - with Lambdas and Streams
Ganesh Samarthyam
 
Java 8
Java 8Java 8
Java 8
Sheeban Singaram
 
Lambdas in Java 8
Lambdas in Java 8Lambdas in Java 8
Lambdas in Java 8
Tobias Coetzee
 
Java 8 features
Java 8 featuresJava 8 features
Java 8 features
NexThoughts Technologies
 
Java 8 presentation
Java 8 presentationJava 8 presentation
Java 8 presentation
Van Huong
 
The Road to Lambda - Mike Duigou
The Road to Lambda - Mike DuigouThe Road to Lambda - Mike Duigou
The Road to Lambda - Mike Duigou
jaxconf
 
java8
java8java8
java8
Arik Abulafya
 
java150929145120-lva1-app6892 (2).pptx
java150929145120-lva1-app6892 (2).pptxjava150929145120-lva1-app6892 (2).pptx
java150929145120-lva1-app6892 (2).pptx
BruceLee275640
 
Insight into java 1.8, OOP VS FP
Insight into java 1.8, OOP VS FPInsight into java 1.8, OOP VS FP
Insight into java 1.8, OOP VS FP
Syed Awais Mazhar Bukhari
 
Ad

More from Simon Ritter (20)

Java Pattern Puzzles Java Pattern Puzzles
Java Pattern Puzzles Java Pattern PuzzlesJava Pattern Puzzles Java Pattern Puzzles
Java Pattern Puzzles Java Pattern Puzzles
Simon Ritter
 
Keeping Your Java Hot by Solving the JVM Warmup Problem
Keeping Your Java Hot by Solving the JVM Warmup ProblemKeeping Your Java Hot by Solving the JVM Warmup Problem
Keeping Your Java Hot by Solving the JVM Warmup Problem
Simon Ritter
 
Cloud Native Compiler
Cloud Native CompilerCloud Native Compiler
Cloud Native Compiler
Simon Ritter
 
Java On CRaC
Java On CRaCJava On CRaC
Java On CRaC
Simon Ritter
 
The Art of Java Type Patterns
The Art of Java Type PatternsThe Art of Java Type Patterns
The Art of Java Type Patterns
Simon Ritter
 
Modern Java Workshop
Modern Java WorkshopModern Java Workshop
Modern Java Workshop
Simon Ritter
 
Java performance monitoring
Java performance monitoringJava performance monitoring
Java performance monitoring
Simon Ritter
 
Modern Java Workshop
Modern Java WorkshopModern Java Workshop
Modern Java Workshop
Simon Ritter
 
Getting the Most From Modern Java
Getting the Most From Modern JavaGetting the Most From Modern Java
Getting the Most From Modern Java
Simon Ritter
 
Building a Better JVM
Building a Better JVMBuilding a Better JVM
Building a Better JVM
Simon Ritter
 
JDK 14 Lots of New Features
JDK 14 Lots of New FeaturesJDK 14 Lots of New Features
JDK 14 Lots of New Features
Simon Ritter
 
Java after 8
Java after 8Java after 8
Java after 8
Simon Ritter
 
How to Choose a JDK
How to Choose a JDKHow to Choose a JDK
How to Choose a JDK
Simon Ritter
 
Java Programming
Java ProgrammingJava Programming
Java Programming
Simon Ritter
 
The Latest in Enterprise JavaBeans Technology
The Latest in Enterprise JavaBeans TechnologyThe Latest in Enterprise JavaBeans Technology
The Latest in Enterprise JavaBeans Technology
Simon Ritter
 
Developing Enterprise Applications Using Java Technology
Developing Enterprise Applications Using Java TechnologyDeveloping Enterprise Applications Using Java Technology
Developing Enterprise Applications Using Java Technology
Simon Ritter
 
Is Java Still Free?
Is Java Still Free?Is Java Still Free?
Is Java Still Free?
Simon Ritter
 
Moving Towards JDK 12
Moving Towards JDK 12Moving Towards JDK 12
Moving Towards JDK 12
Simon Ritter
 
JDK 9, 10, 11 and Beyond
JDK 9, 10, 11 and BeyondJDK 9, 10, 11 and Beyond
JDK 9, 10, 11 and Beyond
Simon Ritter
 
Java Is Still Free
Java Is Still FreeJava Is Still Free
Java Is Still Free
Simon Ritter
 
Java Pattern Puzzles Java Pattern Puzzles
Java Pattern Puzzles Java Pattern PuzzlesJava Pattern Puzzles Java Pattern Puzzles
Java Pattern Puzzles Java Pattern Puzzles
Simon Ritter
 
Keeping Your Java Hot by Solving the JVM Warmup Problem
Keeping Your Java Hot by Solving the JVM Warmup ProblemKeeping Your Java Hot by Solving the JVM Warmup Problem
Keeping Your Java Hot by Solving the JVM Warmup Problem
Simon Ritter
 
Cloud Native Compiler
Cloud Native CompilerCloud Native Compiler
Cloud Native Compiler
Simon Ritter
 
The Art of Java Type Patterns
The Art of Java Type PatternsThe Art of Java Type Patterns
The Art of Java Type Patterns
Simon Ritter
 
Modern Java Workshop
Modern Java WorkshopModern Java Workshop
Modern Java Workshop
Simon Ritter
 
Java performance monitoring
Java performance monitoringJava performance monitoring
Java performance monitoring
Simon Ritter
 
Modern Java Workshop
Modern Java WorkshopModern Java Workshop
Modern Java Workshop
Simon Ritter
 
Getting the Most From Modern Java
Getting the Most From Modern JavaGetting the Most From Modern Java
Getting the Most From Modern Java
Simon Ritter
 
Building a Better JVM
Building a Better JVMBuilding a Better JVM
Building a Better JVM
Simon Ritter
 
JDK 14 Lots of New Features
JDK 14 Lots of New FeaturesJDK 14 Lots of New Features
JDK 14 Lots of New Features
Simon Ritter
 
How to Choose a JDK
How to Choose a JDKHow to Choose a JDK
How to Choose a JDK
Simon Ritter
 
The Latest in Enterprise JavaBeans Technology
The Latest in Enterprise JavaBeans TechnologyThe Latest in Enterprise JavaBeans Technology
The Latest in Enterprise JavaBeans Technology
Simon Ritter
 
Developing Enterprise Applications Using Java Technology
Developing Enterprise Applications Using Java TechnologyDeveloping Enterprise Applications Using Java Technology
Developing Enterprise Applications Using Java Technology
Simon Ritter
 
Is Java Still Free?
Is Java Still Free?Is Java Still Free?
Is Java Still Free?
Simon Ritter
 
Moving Towards JDK 12
Moving Towards JDK 12Moving Towards JDK 12
Moving Towards JDK 12
Simon Ritter
 
JDK 9, 10, 11 and Beyond
JDK 9, 10, 11 and BeyondJDK 9, 10, 11 and Beyond
JDK 9, 10, 11 and Beyond
Simon Ritter
 
Java Is Still Free
Java Is Still FreeJava Is Still Free
Java Is Still Free
Simon Ritter
 
Ad

Recently uploaded (20)

AI and Deep Learning with NVIDIA Technologies
AI and Deep Learning with NVIDIA TechnologiesAI and Deep Learning with NVIDIA Technologies
AI and Deep Learning with NVIDIA Technologies
SandeepKS52
 
Marketo & Dynamics can be Most Excellent to Each Other – The Sequel
Marketo & Dynamics can be Most Excellent to Each Other – The SequelMarketo & Dynamics can be Most Excellent to Each Other – The Sequel
Marketo & Dynamics can be Most Excellent to Each Other – The Sequel
BradBedford3
 
IMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptx
IMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptxIMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptx
IMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptx
usmanch7829
 
Top 5 Task Management Software to Boost Productivity in 2025
Top 5 Task Management Software to Boost Productivity in 2025Top 5 Task Management Software to Boost Productivity in 2025
Top 5 Task Management Software to Boost Productivity in 2025
Orangescrum
 
Plooma is a writing platform to plan, write, and shape books your way
Plooma is a writing platform to plan, write, and shape books your wayPlooma is a writing platform to plan, write, and shape books your way
Plooma is a writing platform to plan, write, and shape books your way
Plooma
 
GDG Douglas - Google AI Agents: Your Next Intern?
GDG Douglas - Google AI Agents: Your Next Intern?GDG Douglas - Google AI Agents: Your Next Intern?
GDG Douglas - Google AI Agents: Your Next Intern?
felipeceotto
 
Automating Map Production With FME and Python
Automating Map Production With FME and PythonAutomating Map Production With FME and Python
Automating Map Production With FME and Python
Safe Software
 
IBM Rational Unified Process For Software Engineering - Introduction
IBM Rational Unified Process For Software Engineering - IntroductionIBM Rational Unified Process For Software Engineering - Introduction
IBM Rational Unified Process For Software Engineering - Introduction
Gaurav Sharma
 
Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...
Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...
Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...
WSO2
 
Maximizing Business Value with AWS Consulting Services.pdf
Maximizing Business Value with AWS Consulting Services.pdfMaximizing Business Value with AWS Consulting Services.pdf
Maximizing Business Value with AWS Consulting Services.pdf
Elena Mia
 
DevOps for AI: running LLMs in production with Kubernetes and KubeFlow
DevOps for AI: running LLMs in production with Kubernetes and KubeFlowDevOps for AI: running LLMs in production with Kubernetes and KubeFlow
DevOps for AI: running LLMs in production with Kubernetes and KubeFlow
Aarno Aukia
 
FME for Climate Data: Turning Big Data into Actionable Insights
FME for Climate Data: Turning Big Data into Actionable InsightsFME for Climate Data: Turning Big Data into Actionable Insights
FME for Climate Data: Turning Big Data into Actionable Insights
Safe Software
 
Neuralink Templateeeeeeeeeeeeeeeeeeeeeeeeee
Neuralink TemplateeeeeeeeeeeeeeeeeeeeeeeeeeNeuralink Templateeeeeeeeeeeeeeeeeeeeeeeeee
Neuralink Templateeeeeeeeeeeeeeeeeeeeeeeeee
alexandernoetzold
 
Best Inbound Call Tracking Software for Small Businesses
Best Inbound Call Tracking Software for Small BusinessesBest Inbound Call Tracking Software for Small Businesses
Best Inbound Call Tracking Software for Small Businesses
TheTelephony
 
Migrating to Azure Cosmos DB the Right Way
Migrating to Azure Cosmos DB the Right WayMigrating to Azure Cosmos DB the Right Way
Migrating to Azure Cosmos DB the Right Way
Alexander (Alex) Komyagin
 
Generative Artificial Intelligence and its Applications
Generative Artificial Intelligence and its ApplicationsGenerative Artificial Intelligence and its Applications
Generative Artificial Intelligence and its Applications
SandeepKS52
 
Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...
Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...
Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...
BradBedford3
 
Who will create the languages of the future?
Who will create the languages of the future?Who will create the languages of the future?
Who will create the languages of the future?
Jordi Cabot
 
Leveraging Foundation Models to Infer Intents
Leveraging Foundation Models to Infer IntentsLeveraging Foundation Models to Infer Intents
Leveraging Foundation Models to Infer Intents
Keheliya Gallaba
 
The Future of Open Source Reporting Best Alternatives to Jaspersoft.pdf
The Future of Open Source Reporting Best Alternatives to Jaspersoft.pdfThe Future of Open Source Reporting Best Alternatives to Jaspersoft.pdf
The Future of Open Source Reporting Best Alternatives to Jaspersoft.pdf
Varsha Nayak
 
AI and Deep Learning with NVIDIA Technologies
AI and Deep Learning with NVIDIA TechnologiesAI and Deep Learning with NVIDIA Technologies
AI and Deep Learning with NVIDIA Technologies
SandeepKS52
 
Marketo & Dynamics can be Most Excellent to Each Other – The Sequel
Marketo & Dynamics can be Most Excellent to Each Other – The SequelMarketo & Dynamics can be Most Excellent to Each Other – The Sequel
Marketo & Dynamics can be Most Excellent to Each Other – The Sequel
BradBedford3
 
IMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptx
IMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptxIMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptx
IMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptx
usmanch7829
 
Top 5 Task Management Software to Boost Productivity in 2025
Top 5 Task Management Software to Boost Productivity in 2025Top 5 Task Management Software to Boost Productivity in 2025
Top 5 Task Management Software to Boost Productivity in 2025
Orangescrum
 
Plooma is a writing platform to plan, write, and shape books your way
Plooma is a writing platform to plan, write, and shape books your wayPlooma is a writing platform to plan, write, and shape books your way
Plooma is a writing platform to plan, write, and shape books your way
Plooma
 
GDG Douglas - Google AI Agents: Your Next Intern?
GDG Douglas - Google AI Agents: Your Next Intern?GDG Douglas - Google AI Agents: Your Next Intern?
GDG Douglas - Google AI Agents: Your Next Intern?
felipeceotto
 
Automating Map Production With FME and Python
Automating Map Production With FME and PythonAutomating Map Production With FME and Python
Automating Map Production With FME and Python
Safe Software
 
IBM Rational Unified Process For Software Engineering - Introduction
IBM Rational Unified Process For Software Engineering - IntroductionIBM Rational Unified Process For Software Engineering - Introduction
IBM Rational Unified Process For Software Engineering - Introduction
Gaurav Sharma
 
Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...
Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...
Build Smarter, Deliver Faster with Choreo - An AI Native Internal Developer P...
WSO2
 
Maximizing Business Value with AWS Consulting Services.pdf
Maximizing Business Value with AWS Consulting Services.pdfMaximizing Business Value with AWS Consulting Services.pdf
Maximizing Business Value with AWS Consulting Services.pdf
Elena Mia
 
DevOps for AI: running LLMs in production with Kubernetes and KubeFlow
DevOps for AI: running LLMs in production with Kubernetes and KubeFlowDevOps for AI: running LLMs in production with Kubernetes and KubeFlow
DevOps for AI: running LLMs in production with Kubernetes and KubeFlow
Aarno Aukia
 
FME for Climate Data: Turning Big Data into Actionable Insights
FME for Climate Data: Turning Big Data into Actionable InsightsFME for Climate Data: Turning Big Data into Actionable Insights
FME for Climate Data: Turning Big Data into Actionable Insights
Safe Software
 
Neuralink Templateeeeeeeeeeeeeeeeeeeeeeeeee
Neuralink TemplateeeeeeeeeeeeeeeeeeeeeeeeeeNeuralink Templateeeeeeeeeeeeeeeeeeeeeeeeee
Neuralink Templateeeeeeeeeeeeeeeeeeeeeeeeee
alexandernoetzold
 
Best Inbound Call Tracking Software for Small Businesses
Best Inbound Call Tracking Software for Small BusinessesBest Inbound Call Tracking Software for Small Businesses
Best Inbound Call Tracking Software for Small Businesses
TheTelephony
 
Generative Artificial Intelligence and its Applications
Generative Artificial Intelligence and its ApplicationsGenerative Artificial Intelligence and its Applications
Generative Artificial Intelligence and its Applications
SandeepKS52
 
Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...
Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...
Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...
BradBedford3
 
Who will create the languages of the future?
Who will create the languages of the future?Who will create the languages of the future?
Who will create the languages of the future?
Jordi Cabot
 
Leveraging Foundation Models to Infer Intents
Leveraging Foundation Models to Infer IntentsLeveraging Foundation Models to Infer Intents
Leveraging Foundation Models to Infer Intents
Keheliya Gallaba
 
The Future of Open Source Reporting Best Alternatives to Jaspersoft.pdf
The Future of Open Source Reporting Best Alternatives to Jaspersoft.pdfThe Future of Open Source Reporting Best Alternatives to Jaspersoft.pdf
The Future of Open Source Reporting Best Alternatives to Jaspersoft.pdf
Varsha Nayak
 

Functional programming with_jdk8-s_ritter

  • 1. Functional Programming With JDK8 Simon Ritter Head of Java Technology Evangelism Oracle Corp. Twitter: @speakjava Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
  • 2. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Safe Harbor Statement The following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle. 2
  • 3. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Lambda Expressions
  • 4. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. 1996 … 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 1.0 5.0 6 7 8 java.lang.Thread java.util.concurrent (jsr166) Fork/Join Framework (jsr166y) Project LambdaConcurrency in Java Phasers, etc (jsr166)
  • 5. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. The Problem: External Iteration List<Student> students = ... double highestScore = 0.0; for (Student s : students) { if (s.getGradYear() == 2011) { if (s.getScore() > highestScore) highestScore = s.score; } } • Our code controls iteration • Inherently serial: iterate from beginning to end • Not thread-safe • Business logic is stateful • Mutable accumulator variable
  • 6. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Internal Iteration With Inner Classes • Iteration handled by the library • Not inherently serial – traversal may be done in parallel • Traversal may be done lazily – so one pass, rather than three • Thread safe – client logic is stateless • High barrier to use – Syntactically ugly More Functional double highestScore = students .filter(new Predicate<Student>() { public boolean op(Student s) { return s.getGradYear() == 2011; } }) .map(new Mapper<Student,Double>() { public Double extract(Student s) { return s.getScore(); } }) .max();
  • 7. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Internal Iteration With Lambdas List<Student> students = ... double highestScore = students .filter(Student s -> s.getGradYear() == 2011) .map(Student s -> s.getScore()) .max(); • More readable • More abstract • Less error-prone NOTE: This is not JDK8 code
  • 8. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Lambda Expressions • Lambda expressions represent anonymous functions – Same structure as a method • typed argument list, return type, set of thrown exceptions, and a body – Not associated with a class • We now have parameterised behaviour, not just values Some Details double highestScore = students .filter(Student s -> s.getGradYear() == 2011) .map(Student s -> s.getScore()) .max(); What How
  • 9. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Lambda Expression Types • Single-method interfaces are used extensively in Java – Definition: a functional interface is an interface with one abstract method – Functional interfaces are identified structurally – The type of a lambda expression will be a functional interface • Lambda expressions provide implementations of the abstract method interface Comparator<T> { boolean compare(T x, T y); } interface FileFilter { boolean accept(File x); } interface Runnable { void run(); } interface ActionListener { void actionPerformed(…); } interface Callable<T> { T call(); }
  • 10. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Local Variable Capture • Lambda expressions can refer to effectively final local variables from the surrounding scope – Effectively final: A variable that meets the requirements for final variables (i.e., assigned once), even if not explicitly declared final – Closures on values, not variables void expire(File root, long before) { root.listFiles(File p -> p.lastModified() <= before); }
  • 11. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. What Does ‘this’ Mean In A Lambda • ‘this’ refers to the enclosing object, not the lambda itself • Think of ‘this’ as a final predefined local • Remember the Lambda is an anonymous function – It is not associated with a class – Therefore there can be no ‘this’ for the Lambda
  • 12. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Referencing Instance Variables Which are not final, or effectively final class DataProcessor { private int currentValue; public void process() { DataSet myData = myFactory.getDataSet(); dataSet.forEach(d -> d.use(currentValue++)); } }
  • 13. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Referencing Instance Variables The compiler helps us out class DataProcessor { private int currentValue; public void process() { DataSet myData = myFactory.getDataSet(); dataSet.forEach(d -> d.use(this.currentValue++); } } ‘this’ (which is effectively final) inserted by the compiler
  • 14. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Type Inference • The compiler can often infer parameter types in a lambda expression  Inferrence based on the target functional interface’s method signature • Fully statically typed (no dynamic typing sneaking in) – More typing with less typing List<String> list = getList(); Collections.sort(list, (String x, String y) -> x.length() - y.length()); Collections.sort(list, (x, y) -> x.length() - y.length()); static T void sort(List<T> l, Comparator<? super T> c);
  • 15. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Method References • Method references let us reuse a method as a lambda expression FileFilter x = File f -> f.canRead(); FileFilter x = File::canRead;
  • 16. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Method References • Format: target_reference::method_name • Three kinds of method reference – Static method (e.g. Integer::parseInt) – Instance method of an arbitary type (e.g. String::length) – Instance method of an existing object 16 More Detail
  • 17. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Method References 17 Rules For Construction Lambda Method Ref Lambda Method Ref Lambda Method Ref (args) -> ClassName.staticMethod(args) (arg0, rest) -> arg0.instanceMethod(rest) (args) -> expr.instanceMethod(args) ClassName::staticMethod ClassName::instanceMethod expr::instanceMethod instanceOf
  • 18. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Constructor References • Same concept as a method reference – For the constructor Factory<List<String>> f = ArrayList<String>::new; Factory<List<String>> f = () -> return new ArrayList<String>(); Replace with
  • 19. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Useful Methods That Can Use Lambdas • Iterable.forEach(Consumer c) List<String> myList = ... myList.forEach(s -> System.out.println(s)); myList.forEach(System.out::println);
  • 20. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Useful Methods That Can Use Lambdas • Collection.removeIf(Predicate p) List<String> myList = ... myList.removeIf(s -> s.length() == 0)
  • 21. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Useful Methods That Can Use Lambdas • List.replaceAll(UnaryOperator o) List<String> myList = ... myList.replaceAll(s -> s.toUpperCase()); myList.replaceAll(String::toUpper);
  • 22. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Useful Methods That Can Use Lambdas • List.sort(Comparator c) • Replaces Collections.sort(List l, Comparator c) List<String> myList = ... myList.sort((x, y) -> x.length() – y.length());
  • 23. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Library Evolution
  • 24. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Library Evolution Goal • Requirement: aggregate operations on collections –New methods required on Collections to facilitate this • This is problematic – Can’t add new methods to interfaces without modifying all implementations – Can’t necessarily find or control all implementations int heaviestBlueBlock = blocks .filter(b -> b.getColor() == BLUE) .map(Block::getWeight) .reduce(0, Integer::max);
  • 25. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Solution: Default Methods • Specified in the interface • From the caller’s perspective, just an ordinary interface method • Provides a default implementation • Default only used when implementation classes do not provide a body for the extension method • Implementation classes can provide a better version, or not interface Collection<E> { default Stream<E> stream() { return StreamSupport.stream(spliterator()); } }
  • 26. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Virtual Extension Methods • Err, isn’t this implementing multiple inheritance for Java? • Yes, but Java already has multiple inheritance of types • This adds multiple inheritance of behavior too • But not state, which is where most of the trouble is • Can still be a source of complexity • Class implements two interfaces, both of which have default methods • Same signature • How does the compiler differentiate? • Static methods also allowed in interfaces in Java SE 8 Stop right there!
  • 27. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Functional Interface Definition • An interface • Must have only one abstract method – In JDK 7 this would mean only one method (like ActionListener) • JDK 8 introduced default methods – Adding multiple inheritance of types to Java – These are, by definition, not abstract (they have an implementation) • JDK 8 also now allows interfaces to have static methods – Again, not abstract • @FunctionalInterface can be used to have the compiler check 27
  • 28. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Is This A Functional Interface? 28 @FunctionalInterface public interface Runnable { public abstract void run(); } Yes. There is only one abstract method
  • 29. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Is This A Functional Interface? 29 @FunctionalInterface public interface Predicate<T> { default Predicate<T> and(Predicate<? super T> p) {…}; default Predicate<T> negate() {…}; default Predicate<T> or(Predicate<? super T> p) {…}; static <T> Predicate<T> isEqual(Object target) {…}; boolean test(T t); } Yes. There is still only one abstract method
  • 30. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Is This A Functional Interface? 30 @FunctionalInterface public interface Comparator { // default and static methods elided int compare(T o1, T o2); boolean equals(Object obj); } The equals(Object) method is implicit from the Object class Therefore only one abstract method
  • 31. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Lambdas In Full Flow: Streams
  • 32. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Stream Overview • Abstraction for specifying aggregate computations – Not a data structure – Can be infinite • Simplifies the description of aggregate computations – Exposes opportunities for optimisation – Fusing, laziness and parallelism At The High Level
  • 33. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Stream Overview • A stream pipeline consists of three types of things – A source – Zero or more intermediate operations – A terminal operation • Producing a result or a side-effect Pipeline int total = transactions.stream() .filter(t -> t.getBuyer().getCity().equals(“London”)) .mapToInt(Transaction::getPrice) .sum(); Source Intermediate operation Terminal operation
  • 34. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Stream Sources • From collections and arrays – Collection.stream() – Collection.parallelStream() – Arrays.stream(T array) or Stream.of() • Static factories – IntStream.range() – Files.walk() • Roll your own – java.util.Spliterator Many Ways To Create
  • 35. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Stream Terminal Operations • The pipeline is only evaluated when the terminal operation is called – All operations can execute sequentially or in parallel – Intermediate operations can be merged • Avoiding multiple redundant passes on data • Short-circuit operations (e.g. findFirst) • Lazy evaluation – Stream characteristics help identify optimisations • DISTINT stream passed to distinct() is a no-op
  • 36. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Maps and FlatMaps Map Values in a Stream Map FlatMap Input Stream Input Stream 1-to-1 mapping 1-to-many mapping Output Stream Output Stream
  • 37. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. The Optional Class
  • 38. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Optional<T> Reducing NullPointerException Occurrences String direction = gpsData.getPosition().getLatitude().getDirection(); String direction = “UNKNOWN”; if (gpsData != null) { Position p = gpsData.getPosition(); if (p != null) { Latitude latitude = p.getLatitude(); if (latitude != null) direction = latitude.getDirection(); } } String direction = gpsData.getPosition().getLatitude().getDirection();
  • 39. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Optional Class • Terminal operations like min(), max(), etc do not return a direct result • Suppose the input Stream is empty? • Optional<T> – Container for an object reference (null, or real object) – Think of it like a Stream of 0 or 1 elements – use get(), ifPresent() and orElse() to access the stored reference – Can use in more complex ways: filter(), map(), etc – gpsMaybe.filter(r -> r.lastReading() < 2).ifPresent(GPSData::display); Helping To Eliminate the NullPointerException
  • 40. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Optional ifPresent() Do something when set if (x != null) { print(x); } opt.ifPresent(x -> print(x)); opt.ifPresent(this::print);
  • 41. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Optional filter() Reject certain values of the Optional if (x != null && x.contains("a")) { print(x); } opt.filter(x -> x.contains("a")) .ifPresent(this::print);
  • 42. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Optional map() Transform value if present if (x != null) { String t = x.trim(); if (t.length() > 1) print(t); } opt.map(String::trim) .filter(t -> t.length() > 1) .ifPresent(this::print);
  • 43. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Optional flatMap() Going deeper public String findSimilar(String s) Optional<String> tryFindSimilar(String s) Optional<Optional<String>> bad = opt.map(this::tryFindSimilar); Optional<String> similar = opt.flatMap(this::tryFindSimilar);
  • 44. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Update Our GPS Code class GPSData { public Optional<Position> getPosition() { ... } } class Position { public Optional<Latitude> getLatitude() { ... } } class Latitude { public String getString() { ... } }
  • 45. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Update Our GPS Code String direction = Optional.ofNullable(gpsData) .flatMap(GPSData::getPosition) .flatMap(Position::getLatitude) .map(Latitude::getDirection) .orElse(“None”);
  • 46. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Stream Examples
  • 47. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example 1 Convert words in list to upper case List<String> output = wordList .stream() .map(String::toUpperCase) .collect(Collectors.toList());
  • 48. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example 1 Convert words in list to upper case (in parallel) List<String> output = wordList .parallelStream() .map(String::toUpperCase) .collect(Collectors.toList());
  • 49. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example 2 • BufferedReader has new method – Stream<String> lines() Count lines in a file long count = bufferedReader .lines() .count();
  • 50. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example 3 Join lines 3-4 into a single string String output = bufferedReader .lines() .skip(2) .limit(2) .collect(Collectors.joining());
  • 51. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example 4 Collect all words in a file into a list List<String> output = reader .lines() .flatMap(line -> Stream.of(line.split(REGEXP))) .filter(word -> word.length() > 0) .collect(Collectors.toList());
  • 52. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example 5 List of unique words in lowercase, sorted by length List<String> output = reader .lines() .flatMap(line -> Stream.of(line.split(REGEXP))) .filter(word -> word.length() > 0) .map(String::toLowerCase) .distinct() .sorted((x, y) -> x.length() - y.length()) .collect(Collectors.toList());
  • 53. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example 6 Create a map: Keys are word length, values are lists of words of that length Map<Integer, List<String>> result = reader.lines() .flatMap(line -> Stream.of(line.split(REGEXP))) .collect(groupingBy(String::length));
  • 54. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example 7 Create a map: Keys are word length, values are how many words of that length Map<Integer, Long> result = reader.lines() .flatMap(line -> Stream.of(line.split(REGEXP))) .collect(groupingBy(String::length, counting())); Downstream collector to return count of elements
  • 55. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example 8: Real World Infinite stream from thermal sensor private int double currentTemperature; ... thermalReader .lines() .mapToDouble(s -> Double.parseDouble(s.substring(0, s.length() - 1))) .map(t -> ((t – 32) * 5 / 9) .filter(t -> t != currentTemperature) .peek(t -> listener.ifPresent(l -> l.temperatureChanged(t))) .forEach(t -> currentTemperature = t);
  • 56. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example 8: Real World Infinite stream from thermal sensor private int double currentTemperature; ... thermalReader .lines() .mapToDouble(s -> Double.parseDouble(s.substring(0, s.length() - ))) .map(t -> ((t – 32) * 5 / 9) .filter(t -> t != this.currentTemperature) .peek(t -> listener.ifPresent(l -> l.temperatureChanged(t))) .forEach(t -> this.currentTemperature = t);
  • 57. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Advanced Lambdas And Streams
  • 58. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Exception Handling In Lambdas
  • 59. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Exception Handling In Lambda Expressions • Compiler error: uncaught exception in filter() Can Be Problematic public boolean isValid(Object o) throws IOException { ... } public List<String> processList(List<String> list) throws IOException { return list.stream() .filter(w -> isValid(w)) .collect(Collectors.toList()); }
  • 60. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Exception Handling In Lambda Expressions 60 Catch the Exception In The Lambda public double processList(List list) { return list.stream() .filter(w -> { try { return isValid(w) } catch (IOException ioe) { return false; } }) .collect(Collectors.toList()); }
  • 61. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Exception Handling In Lambda Expressions • Which is great, except you can't use it with Streams 61 Define A New Functional Interface @FunctionalInterface public interface PredicateWithException { public boolean test(String s) throws IOException; }
  • 62. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Debugging
  • 63. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Logging Mid-Stream The peek() method List<String> output = reader .lines() .flatMap(line -> Stream.of(line.split(REGEXP))) .filter(word -> word.length() > 5) .peek(s -> System.out.println(“Word = “ + s)) .collect(Collectors.toList());
  • 64. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Using peek() To Set A Breakpoint List<String> output = reader .lines() .flatMap(line -> Stream.of(line.split(REGEXP))) .filter(word -> word.length() > 5) .peek(s -> s) .collect(Collectors.toList()); Set breakpoint on peek Some debuggers don’t like empty bodies
  • 65. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Streams and Concurrency
  • 66. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Serial And Parallel Streams • Collection Stream sources – stream() – parallelStream() • Stream can be made parallel or sequential at any point – parallel() – sequential() • The last call wins – Whole stream is either sequential or parallel 66
  • 67. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Parallel Streams • Implemented underneath using the fork-join framework • Will default to as many threads for the pool as the OS reports processors – Which may not be what you want System.setProperty( "java.util.concurrent.ForkJoinPool.common.parallelism", "32767"); • Remember, parallel streams always need more work to process – But they might finish it more quickly 67
  • 68. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. When To Use Parallel Streams • Data set size is important, as is the type of data structure – ArrayList: GOOD – HashSet, TreeSet: OK – LinkedList: BAD • Operations are also important – Certain operations decompose to parallel tasks better than others – filter() and map() are excellent – sorted() and distinct() do not decompose well 68 Sadly, no simple answer
  • 69. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. When To Use Parallel Streams • N = size of the data set • Q = Cost per element through the Stream pipeline • N x Q = Total cost of pipeline operations • The bigger N x Q is the better a parallel stream will perform • It is easier to know N than Q, but Q can be estimated • If in doubt, profile 69 Quantative Considerations
  • 70. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Streams: Pitfalls For The Unwary
  • 71. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Functional v. Imperative • For functional programming you should not modify state • Java supports closures over values, not closures over variables • But state is really useful… 71
  • 72. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Counting Methods That Return Streams 72 Still Thinking Imperatively Set<String> sourceKeySet = streamReturningMethodMap.keySet(); LongAdder sourceCount = new LongAdder(); sourceKeySet.stream() .forEach(c -> sourceCount.add(streamReturningMethodMap.get(c).size()));
  • 73. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Counting Methods That Return Streams 73 Functional Way sourceKeySet.stream() .mapToInt(c -> streamReturningMethodMap.get(c).size()) .sum();
  • 74. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Printing And Counting Functional Interfaces 74 Still Thinking Imperatively LongAdder newMethodCount = new LongAdder(); functionalParameterMethodMap.get(c).stream() .forEach(m -> { output.println(m); if (isNewMethod(c, m)) newMethodCount.increment(); }); return newMethodCount.intValue();
  • 75. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Printing And Counting Functional Interfaces 75 More Functional, But Not Pure Functional int count = functionalParameterMethodMap.get(c).stream() .mapToInt(m -> { int newMethod = 0; output.println(m); if (isNewMethod(c, m)) newMethod = 1; return newMethod }) .sum(); There is still state being modified in the Lambda
  • 76. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Printing And Counting Functional Interfaces 76 Even More Functional, But Still Not Pure Functional int count = functionalParameterMethodMap.get(nameOfClass) .stream() .peek(method -> output.println(method)) .mapToInt(m -> isNewMethod(nameOfClass, m) ? 1 : 0) .sum(); Strictly speaking printing is a side effect, which is not purely functional
  • 77. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. The Art Of Reduction (Or The Need to Think Differently)
  • 78. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. A Simple Problem • Find the length of the longest line in a file • Hint: BufferedReader has a new method, lines(), that returns a Stream 78 BufferedReader reader = ... reader.lines() .mapToInt(String::length) .max() .getAsInt();
  • 79. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Another Simple Problem • Find the length of the longest line in a file 79
  • 80. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Naïve Stream Solution • That works, so job done, right? • Not really. Big files will take a long time and a lot of resources • Must be a better approach 80 String longest = reader.lines(). sort((x, y) -> y.length() - x.length()). findFirst(). get();
  • 81. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. External Iteration Solution • Simple, but inherently serial • Not thread safe due to mutable state 81 String longest = ""; while ((String s = reader.readLine()) != null) if (s.length() > longest.length()) longest = s;
  • 82. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Recursive Approach: The Method 82 String findLongestString(String s, int index, List<String> l) { if (index >= l.size()) return s; if (index == l.size() - 1) { if (s.length() > l.get(index).length()) return s; return l.get(index); } String s2 = findLongestString(l.get(start), index + 1, l); if (s.length() > s2.length()) return s; return s2; }
  • 83. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Recursive Approach: Solving The Problem • No explicit loop, no mutable state, we’re all good now, right? • Unfortunately not - larger data sets will generate an OOM exception 83 List<String> lines = new ArrayList<>(); while ((String s = reader.readLine()) != null) lines.add(s); String longest = findLongestString("", 0, lines);
  • 84. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. A Better Stream Solution • The Stream API uses the well known filter-map-reduce pattern • For this problem we do not need to filter or map, just reduce Optional<T> reduce(BinaryOperator<T> accumulator) • The key is to find the right accumulator – The accumulator takes a partial result and the next element, and returns a new partial result – In essence it does the same as our recursive solution – Without all the stack frames • BinaryOperator is a subclass of BiFunction, but all types are the same • R apply(T t, U u) or T apply(T x, T y) 84
  • 85. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. A Better Stream Solution • Use the recursive approach as an accululator for a reduction 85 String longestLine = reader.lines() .reduce((x, y) -> { if (x.length() > y.length()) return x; return y; }) .get();
  • 86. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. A Better Stream Solution • Use the recursive approach as an accululator for a reduction 86 String longestLine = reader.lines() .reduce((x, y) -> { if (x.length() > y.length()) return x; return y; }) .get(); x in effect maintains state for us, by always holding the longest string found so far
  • 87. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. The Simplest Stream Solution • Use a specialised form of max() • One that takes a Comparator as a parameter • comparingInt() is a static method on Comparator – Comparator<T> comparingInt(ToIntFunction<? extends T> keyExtractor) 87 reader.lines() .max(comparingInt(String::length)) .get();
  • 88. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Conclusions • Java needs lambda statements – Significant improvements in existing libraries are required • Require a mechanism for interface evolution – Solution: virtual extension methods • Bulk operations on Collections – Much simpler with Lambdas • Java SE 8 evolves the language, libraries, and VM together
  • 89. Simon Ritter Oracle Corporartion Twitter: @speakjava Copyright © 2014, Oracle and/or its affiliates. All rights reserved.