Top Banner
© Copyright Azul Systems 2016 © Copyright Azul Systems 2015 @speakjava azul.co m Lessons Learnt With Lambdas and Streams in JDK 8 Simon Ritter Deputy CTO, Azul Systems 1
28

JDK8: Lessons Learnt with Lambdas and Streams

Jan 07, 2017

Download

Technology

Spring IO
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

© Copyright Azul Systems 2015

@speakjavaazul.com

Lessons Learnt With Lambdas and Streams

in JDK 8

Simon RitterDeputy CTO, Azul Systems

1

Page 2: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

A clever man learns from his mistakes...

...a wise man learns from other people’s

Page 3: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

Lambda Expressions And Delayed Execution

Page 4: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

Performance Impact For Logging Heisenberg’s uncertainty principle

Setting log level to INFO still has a performance impact Since Logger determines whether to log the message the

parameter must be evaluated even when not used

4

logger.finest(getSomeStatusData());

Always executed

Page 5: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

Supplier<T> Represents a supplier of results All relevant logging methods now have a version that takes

a Supplier

Pass a description of how to create the log message– Not the message

If the Logger doesn’t need the value it doesn’t invoke the Lambda

Can be used for other conditional activities5

logger.finest(getSomeStatusData());logger.finest(() -> getSomeStatusData());

Page 6: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

Avoiding Loops In Streams

Page 7: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

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…

7

Page 8: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016 8

Counting Methods That Return StreamsStill Thinking Imperatively

Set<String> sourceKeySet = streamReturningMethodMap.keySet();

LongAdder sourceCount = new LongAdder();

sourceKeySet.stream() .forEach(c -> sourceCount .add(streamReturningMethodMap.get(c).size()));

Page 9: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016 9

Counting Methods That Return StreamsFunctional Way

sourceKeySet.stream() .mapToInt(c -> streamReturningMethodMap.get(c).size()) .sum();

Page 10: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016 10

Printing And CountingStill Thinking Imperatively

LongAdder newMethodCount = new LongAdder();

functionalParameterMethodMap.get(c).stream() .forEach(m -> { output.println(m);

if (isNewMethod(c, m)) newMethodCount.increment(); });

Page 11: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016 11

Printing And CountingMore 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

Page 12: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016 12

Printing And CountingEven 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

Page 13: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

The Art Of Reduction(Or The Need to Think Differently)

Page 14: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

A Simple Problem Find the length of the longest line in a file Hint: BufferedReader has a new method, lines(), that

returns a Stream

14

BufferedReader reader = ...

int longest = reader.lines() .mapToInt(String::length) .max() .getAsInt();

Page 15: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

Another Simple Problem Find the length of the longest line in a file

15

Page 16: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

Another Simple Problem Find the length of the longest line in a file

16

Page 17: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

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

17

String longest = reader.lines(). sort((x, y) -> y.length() - x.length()). findFirst(). get();

Page 18: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

External Iteration Solution

Simple, but inherently serial Not thread safe due to mutable state

18

String longest = "";

while ((String s = reader.readLine()) != null) if (s.length() > longest.length()) longest = s;

Page 19: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

Recursive Approach

19

String findLongestString(String longest, BufferedReader reader) { String next = reader.readLine();

if (next == null) return longest;

if (next.length() > longest.length()) longest = next; return findLongestString(longest, reader);}

Page 20: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

Recursion: 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– Too many stack frames

20

String longest = findLongestString("", reader);

Page 21: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

A Better Stream Solution 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)

BinaryOperator is a subclass of BiFunction– R apply(T t, U u)

For BinaryOperator all types are the same– T apply(T x, T y)

21

Page 22: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

A Better Stream Solution 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– But without all the stack frames

22

Page 23: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

A Better Stream Solution Use the recursive approach as an accululator for a

reduction

23

String longestLine = reader.lines() .reduce((x, y) -> { if (x.length() > y.length()) return x; return y; }) .get();

Page 24: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

A Better Stream Solution Use the recursive approach as an accululator for a

reduction

24

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 providing the partial result, which is the longest string found so far

Page 25: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

The Simplest Stream Solution Use a specialised form of max() One that takes a Comparator as a parameter

comparingInt() is a static method on ComparatorComparator<T> comparingInt( ToIntFunction<? extends T> keyExtractor)

25

reader.lines() .max(comparingInt(String::length)) .get();

Page 26: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

Conclusions

Page 27: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

Conclusions Lambdas and Stream are a very powerful combination Does require developers to think differently

– Avoid loops, even non-obvious ones!– Reductions

Be careful with parallel streams More to come in JDK 9 (and 10)

Join the Zulu.org community– www.zulu.org

27

Page 28: JDK8: Lessons Learnt with Lambdas and Streams

© Copyright Azul Systems 2016

© Copyright Azul Systems 2015

@speakjavaazul.com

Q & A

Simon RitterDeputy CTO, Azul Systems

28