Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Functional Programming With Lambdas and Streams in JDK8
Simon Ritter
Head of Java Technology Evangelism
Oracle Corporation...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Safe Harbor Statement
The following is intended to ou...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
1996 … 2003 2004 2005 2006 2007 2008 2009 2010 2011 2...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Lambdas In Java
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
The Problem: External Iteration
List<Student> student...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Internal Iteration With Inner Classes
• Iteration han...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Internal Iteration With Lambdas
List<Student> student...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Lambda Expressions
• Lambda expressions represent ano...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Lambda Expression Types
• Single-method interfaces ar...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Local Variable Capture
• Lambda expressions can refer...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
What Does ‘this’ Mean For Lambdas?
• ‘this’ refers to...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Referencing Instance Variables
Which are not final, o...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Referencing Instance Variables
The compiler helps us ...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Type Inference
• The compiler can often infer paramet...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Method References
• Method references let us reuse a ...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Constructor References
• Same concept as a method ref...
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 opera...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Solution: Default Methods
• Specified in the interfac...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Virtual Extension Methods
• Err, isn’t this implement...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Functional Interface Definition
• Single Abstract Met...
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 aggregat...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Stream Overview
• A stream pipeline consists of three...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Stream Sources
• From collections and arrays
– Collec...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Stream Terminal Operations
• The pipeline is only eva...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Maps and FlatMaps
Map Values in a Stream
Map
FlatMap
...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Optional Class
• Terminal operations like min(), max(...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 1
Convert words in list to upper case
List<St...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 1
Convert words in list to upper case (in par...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 2
• BufferedReader has new method
– Stream<St...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 3
Join lines 3-4 into a single string
String ...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 4
Collect all words in a file into a list
Lis...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 5
List of unique words in lowercase, sorted b...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 6: Real World
Infinite stream from thermal se...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Example 6: Real World
Infinite stream from thermal se...
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Conclusions
• Java needs lambda statements
– Signific...
Simon Ritter
Oracle Corporartion
Twitter: @speakjava
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Upcoming SlideShare
Loading in …5
×

Functional Programming With Lambdas and Streams in JDK8

1,269 views

Published on



The significant new language feature in Java SE 8 is the introduction of Lambda expressions, a way of defining and using anonymous functions. On its own this provides a great way to simplify situations where we would typically use an inner class today. However, Java SE 8 also introduces a range of new classes in the standard libraries that are designed specifically to take advantage of Lambdas. These are primarily included in two new packages: java.util.stream and java.util.function.

After a brief discussion of the syntax and use of Lambda expressions this session will focus on how to use Streams to greatly simplify the way bulk and aggregate operations are handled in Java. We will look at examples of how a more functional approach can be taken in Java using sources, intermediate operations and terminators. We will also discuss how this can lead to improvements in performance for many operations through the lazy evaluation of Streams and how code can easily be made parallel by changing the way the Stream is created.

Session at the IndicThreads.com Confence held in Pune, India on 27-28 Feb 2015

http://www.indicthreads.com
http://pune15.indicthreads.com

Published in: Software
  • Be the first to comment

  • Be the first to like this

Functional Programming With Lambdas and Streams in JDK8

  1. 1. Functional Programming With Lambdas and Streams in JDK8 Simon Ritter Head of Java Technology Evangelism Oracle Corporation Twitter: @speakjava
  2. 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. 3. 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)
  4. 4. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Lambdas In Java
  5. 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. 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. 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. 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. 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. 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 enclosing 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. 11. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. What Does ‘this’ Mean For Lambdas? • ‘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. 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. 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. 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. 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. 16. 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
  17. 17. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Library Evolution
  18. 18. 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);
  19. 19. 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()); } }
  20. 20. 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!
  21. 21. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Functional Interface Definition • Single Abstract Method (SAM) type • A functional interface is an interface that has one abstract method – Represents a single function contract – Doesn’t mean it only has one method • @FunctionalInterface annotation – Helps ensure the functional interface contract is honoured – Compiler error if not a SAM
  22. 22. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Lambdas In Full Flow: Streams
  23. 23. 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
  24. 24. 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
  25. 25. 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
  26. 26. 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
  27. 27. 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
  28. 28. 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 Helping To Eliminate the NullPointerException
  29. 29. 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());
  30. 30. 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());
  31. 31. 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();
  32. 32. 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());
  33. 33. 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());
  34. 34. 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());
  35. 35. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example 6: 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);
  36. 36. Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example 6: 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);
  37. 37. 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
  38. 38. Simon Ritter Oracle Corporartion Twitter: @speakjava Copyright © 2014, Oracle and/or its affiliates. All rights reserved.

×