• Like
  • Save

Lambda Expressions and Streams in Java 8 (presented by Marty Hall to Google Inc.)

  • 3,885 views
Uploaded on

LOTS more detail at http://www.coreservlets.com/java-8-tutorial/. This is just a quick summary of Java 8 lambdas and streams that was presented at Google in Mountain View and later to the Google NY …

LOTS more detail at http://www.coreservlets.com/java-8-tutorial/. This is just a quick summary of Java 8 lambdas and streams that was presented at Google in Mountain View and later to the Google NY office.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
3,885
On Slideshare
0
From Embeds
0
Number of Embeds
3

Actions

Shares
Downloads
0
Comments
0
Likes
10

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. © 2013 Marty Hall Customized Java EE Training: http://courses.coreservlets.com/ Java, JSF 2, PrimeFaces, HTML5, JSP, Ajax, jQuery, Spring, Hibernate, RESTful Web Services, Hadoop, Android. Developed and taught by well-known author and developer. At public venues or onsite at your location. Lambdas & Streams in Java 8 Marty Hall, hall@coreservlets.com Presented at Google Inc., August 2013 Lots more detail: http://www.coreservlets.com/java-8-tutorial/
  • 2. Agenda • Lambdas: motivation and overview • Lambdas: most basic form • Making lambdas more succinct • Comparing lambdas with Java 7 and with JavaScript • @FunctionalInterface • Method references • Lambda building blocks in java.util.function • Streams overview • Core Stream methods 4
  • 3. © 2013 Marty Hall Customized Java EE Training: http://courses.coreservlets.com/ Java, JSF 2, PrimeFaces, HTML5, JSP, Ajax, jQuery, Spring, Hibernate, RESTful Web Services, Hadoop, Android. Developed and taught by well-known author and developer. At public venues or onsite at your location. Motivation and Overview
  • 4. Many Languages Let You Pass Functions Around • Dynamically (and usually weakly) typed – JavaScript, Lisp, Scheme, etc. • Strongly typed – Ruby, Scala, Clojure, ML, etc. • Functional approach proven concise, useful, and parallelizable – JavaScript sorting • var testStrings = ["one", "two", "three", "four"]; • testStrings.sort(function(s1, s2) { return(s1.length - s2.length);}); • testStrings.sort(function(s1, s2) { return(s1.charCodeAt(s1.length - 1) – s2.charCodeAt(s2.length - 1));});
  • 5. Why Lambdas in Java Now? • Concise syntax – More succinct and clear than anonymous inner classes • Deficiencies with anonymous inner classes – Bulky. Confusion re “this” and naming in general. No non-final vars. Hard to optimize • Convenient for new streams library – shapes.forEach(s -> s.setColor(Color.RED)); • Similar constructs used in other languages – Callbacks. Closures. Map/reduce idiom. • Step toward true functional programming – Real functions and mutable local vars perhaps in future 7
  • 6. Main Advantage of Lambdas: Concise and Expressive • You write what looks like a function Arrays.sort(testStrings, (s1, s2) -> s1.length() - s2.length()); • Result has behavior of anonymous inner class implementing expected interface Arrays.sort(testStrings, new Comparator<String>() { @Override public int compare(String s1, String s2) { return(s1.length() - s2.length()); } }); 8
  • 7. Corollary Advantages: Support New Way of Thinking • Encourage functional programming – When functional programming approach is used, many classes of problems are easier to solve and result in code that is clearer to read and simpler to maintain • Support streams – Streams are wrappers around data sources (arrays, collections, etc.) that use lambdas, support map/reduce, use lazy evaluation, and can be made parallel automatically by compiler. • Cannot be made parallel automatically for(Employee e: employees) { e.giveRaise(1.15); } • Will automatically be run in parallel employees.parallel().forEach(e -> e.giveRaise(1.15)); 9
  • 8. © 2013 Marty Hall Customized Java EE Training: http://courses.coreservlets.com/ Java, JSF 2, PrimeFaces, HTML5, JSP, Ajax, jQuery, Spring, Hibernate, RESTful Web Services, Hadoop, Android. Developed and taught by well-known author and developer. At public venues or onsite at your location. Lambdas: Most Basic Form
  • 9. Big Idea • You write what looks like a function • Arrays.sort(testStrings, (s1, s2) -> s1.length() - s2.length()); • taskList.execute(() -> downloadSomeFile()); • someButton.addActionListener(event -> handleButtonClick()); • double d = MathUtils.integrate(x -> x*x, 0, 100, 1000); • You get an instance of a class that implements the interface that was expected in that place – The expected type must be an interface that has exactly one abstract method • Call “Functional Interface” or “Single Abstract Method (SAM) Interface” – The designation of a single ABSTRACT method is not redundant, because in Java 8, interfaces can have concrete methods, called “default methods”. Java 8 interfaces can also have static methods. Default methods & static methods are covered in coreservlets tutorial.11
  • 10. Most Basic Form: Syntax Summary • Replace this new SomeInterface() { @Override public SomeType someMethod(args) { body } } • With this (args) -> { body } 12
  • 11. Most Basic Form: Example • Old style Arrays.sort(testStrings, new Comparator<String>() { @Override public int compare(String s1, String s2) { return(s1.length() - s2.length()); } }); • New style Arrays.sort(testStrings, (String s1, String s2) -> { return(s1.length() – s2.length()); }); 13
  • 12. Sorting Strings by Length • Old version String[] testStrings = {"one", "two", "three", "four"}; ... Arrays.sort(testStrings, new Comparator<String>() { @Override public int compare(String s1, String s2) { return(s1.length() - s2.length()); } }); ... • New version Arrays.sort(testStrings, (String s1, String s2) -> { return(s1.length() – s2.length()); }); 14 In both cases, resultant array is {"one", "two", "four", "three"}
  • 13. Sorting Strings by Last Char • Old version Arrays.sort(testStrings, new Comparator<String>() { @Override public int compare(String s1, String s2) { return(s1.charAt(s1.length() - 1) – s2.charAt(s2.length() - 1)); } }); • New version Arrays.sort(testStrings, (String s1, String s2) -> { return(s1.charAt(s1.length() - 1) – s2.charAt(s2.length() - 1)); }); 15 In both cases, resultant array is {"one", "three", "two", "four"}
  • 14. © 2013 Marty Hall Customized Java EE Training: http://courses.coreservlets.com/ Java, JSF 2, PrimeFaces, HTML5, JSP, Ajax, jQuery, Spring, Hibernate, RESTful Web Services, Hadoop, Android. Developed and taught by well-known author and developer. At public venues or onsite at your location. Making Lambdas More Succinct
  • 15. Shortening Lambda Syntax • Omit parameter types Arrays.sort(testStrings, (String s1, String s2) -> { return(s1.length() – s2.length()); }); replaced by Arrays.sort(testStrings, (s1, s2) -> { return(s1.length() – s2.length()); }); • Use expressions instead of blocks Arrays.sort(testStrings, (s1, s2) -> { return(s1.length() – s2.length()); }); replaced by Arrays.sort(testStrings, (s1, s2) -> s1.length() – s2.length()); • Omit parens if single argument button1.addActionListener((event) -> setBg(Color.BLUE)); replaced by button1.addActionListener(event -> setBg(Color.BLUE)); 17
  • 16. Java 7 vs. Java 8 • Java 7 taskList.execute(new Runnable() { @Override public void run() { processSomeImage(imageName); } }); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { setBg(Color.GREEN); } }); • Java 8 taskList.execute(() -> processSomeImage(imageName)); button.addActionListener(event -> setBg(Color.GREEN)); 18
  • 17. Sorting Strings by Length & Last Char: Java vs. JavaScript • Java String[] testStrings = {"one", "two", "three", "four"}; Arrays.sort(testStrings, (s1, s2) -> s1.length() - s2.length()); Arrays.sort(testStrings, (s1, s2) -> s1.charAt(s1.length() - 1) – s2.charAt(s2.length() - 1)); • JavaScript var testStrings = ["one", "two", "three", "four"]; testStrings.sort(function(s1, s2) { return(s1.length - s2.length);}); testStrings.sort(function(s1, s2) { return(s1.charCodeAt(s1.length - 1) - s2.charCodeAt(s2.length - 1)); }); 19
  • 18. Sorting: Doing Even Better by Using Higher-Order Function • Last examples – Showed how sorting could be made more succinct simply by using the compact lambda syntax • New example – Uses “comparing” method of Comparator to build lambda that is needed, simply by specifying the key extractor – There are many places in Java 8 that have higher-order functions built in – methods that return lambdas • Java 8 tutorial at coreservlets.com has section on this • Result Arrays.sort(testStrings, comparing((String s) -> s.length())); Arrays.sort(testStrings, comparing((String s) -> s.charAt(s.length() - 1)));20
  • 19. © 2013 Marty Hall Customized Java EE Training: http://courses.coreservlets.com/ Java, JSF 2, PrimeFaces, HTML5, JSP, Ajax, jQuery, Spring, Hibernate, RESTful Web Services, Hadoop, Android. Developed and taught by well-known author and developer. At public venues or onsite at your location. The @FunctionalInterface Annotation
  • 20. Big Idea • @FunctionalInterface – Tells compiler you intend this to be a functional (SAM) interface • One with exactly one abstract method • Thus, for which lambdas can be used – Checks at compile time that you have only a single method, so if a developer later adds a second abstract method, it will give compile-time error – Also informs other developers that lambdas can be used for this interface • Analogous to @Override – Does extra work at compile time, but no difference at run time (assuming it passes the check). • I.e., a correctly formed interface will work as a lambda with or without @FunctionalInterface
  • 21. Example: Numerical Integration • Goals – Simple numerical integration using rectangle (mid-point) rule – Want to use lambdas for function to be integrated. Convenient and succinct. • Define functional (SAM) interface with a “double eval(double x)” method to specify function to be integrated – Want compile-time checking that interface is in right form (exactly one abstract method), and want to alert other developers that lambdas can be used. • Use @FunctionalInterface23 Diagram from http://en.wikipedia.org/wiki/Numerical_integration
  • 22. Interface @FunctionalInterface public interface Integrable { double eval(double x); } 24
  • 23. Numerical Integration Method public static double integrate(Integrable function, double x1, double x2, int numSlices){ if (numSlices < 1) { numSlices = 1; } double delta = (x2 - x1)/numSlices; double start = x1 + delta/2; double sum = 0; for(int i=0; i<numSlices; i++) { sum += delta * function.eval(start + delta * i); } return(sum); } 25
  • 24. Method for Testing public static void integrationTest(Integrable function, double x1, double x2) { for(int i=1; i<7; i++) { int numSlices = (int)Math.pow(10, i); double result = MathUtilities.integrate(function, x1, x2, numSlices); System.out.printf(" For numSlices =%,10d result = %,.8f%n", numSlices, result); } } 26 Also define a simple method for printing out the expected answer based on strings based in. Full code can be downloaded from http://www.coreservlets.com/java-8-tutorial/
  • 25. Testing Results MathUtilities.integrationTest(x -> x*x, 10, 100); MathUtilities.integrationTest(x -> Math.pow(x,3), 50, 500); MathUtilities.integrationTest(x -> Math.sin(x), 0, Math.PI); MathUtilities.integrationTest(x -> Math.exp(x), 2, 20); 27 Output Estimating integral of x^2 from 10.000 to 100.000. Exact answer = 100^3/3 - 10^3/3. ~= 333,000.00000000. For numSlices = 10 result = 332,392.50000000 For numSlices = 100 result = 332,993.92500000 For numSlices = 1,000 result = 332,999.93925000 For numSlices = 10,000 result = 332,999.99939250 For numSlices = 100,000 result = 332,999.99999393 For numSlices = 1,000,000 result = 332,999.99999994 ... // Similar for other three integrals
  • 26. © 2013 Marty Hall Customized Java EE Training: http://courses.coreservlets.com/ Java, JSF 2, PrimeFaces, HTML5, JSP, Ajax, jQuery, Spring, Hibernate, RESTful Web Services, Hadoop, Android. Developed and taught by well-known author and developer. At public venues or onsite at your location. Method References
  • 27. Big Idea • Can use ClassName::staticMethodName or variable::instanceMethodName for lambdas – E.g., Math::cos or myVar::myMethod • Another way of saying this is that if the function you want to describe already has a name, you don’t have to write a lambda for it, but can instead just use the method name. – The function must match signature of method in functional (SAM) interface to which it is assigned • You can also use Class:instanceMethod and Class::new. These are more complicated; details online at coreservlets.com. • The type is found only from the context – The type of a method reference depends on what it is assigned to. This is always true with lambdas, but more obvious here. • E.g., there is no predefined type for Math::cos.
  • 28. Example: Numerical Integration • In previous example, replace these MathUtilities.integrationTest(x -> Math.sin(x), 0, Math.PI); MathUtilities.integrationTest(x -> Math.exp(x), 2, 20); • With these MathUtilities.integrationTest(Math::sin, 0, Math.PI); MathUtilities.integrationTest(Math::exp, 2, 20); People often ask “what is the type of a method reference”? The answer is “this is not known until you try to assign it to a variable, in which case its type is whatever interface that variable expected”. So, for example, Math::sin could be different types in different contexts, but all the types would be single-method interfaces whose method could accept a single double as an argument.
  • 29. © 2013 Marty Hall Customized Java EE Training: http://courses.coreservlets.com/ Java, JSF 2, PrimeFaces, HTML5, JSP, Ajax, jQuery, Spring, Hibernate, RESTful Web Services, Hadoop, Android. Developed and taught by well-known author and developer. At public venues or onsite at your location. Lambda Building Blocks in java.util.function
  • 30. Big Idea • Interfaces like Integrable widely used – So, Java 8 should build in many common cases • Can be used in wide variety of contexts – So need more general name than “Integrable” • java.util.function defines many simple functional (SAM) interfaces – Named according to arguments and return values • E.g., replace my Integrable with builtin DoubleUnaryOperator – You need to look in API for the method names • Although lambdas don’t refer to method names, your code that uses the lambdas will need to call the methods
  • 31. Example: Numerical Integration • In previous example, replace this public static double integrate(Integrable function, …) { … function.eval(…); … } – With this public static double integrate(DoubleUnaryOperator function, … ) {… function.applyAsDouble(…); … } • Then, omit definition of Integrable entirely – Because DoubleUnaryOperator is a functional (SAM) interface containing a method with same signature as the method of the Integrable interface.
  • 32. General Case • If you are tempted to create an interface purely to be used as a target for a lambda – Look through java.util.function and see if one of the functional (SAM) interfaces there can be used instead • DoubleUnaryOperator, IntUnaryOperator, LongUnaryOperator – double/int/long in, same type out • DoubleBinaryOperator, IntBinaryOperator, LongBinaryOperator – Two doubles/ints/longs in, same type out • DoublePredicate, IntPredicate, LongPredicate – double/int/long in, boolean out • DoubleConsumer, IntConsumer, LongConsumer – double/int/long in, void return type • Genericized interfaces: Function, Predicate, Consumer, etc. – Covered in upcoming slides 34
  • 33. Predicate: Big Idea • boolean test(T t) – Lets you make a “function” to test a condition • Benefit – Lets you search collections for entry or entries that match a condition, with much less repeated code than without lambdas • Syntax example Predicate<Employee> matcher = e -> e.getSalary() > 50000; if(matcher.test(someEmployee)) { doSomethingWith(someEmployee); } 35
  • 34. Without Predicate: Finding Employee by First Name public static Employee findEmployeeByFirstName (List<Employee> employees, String firstName) { for(Employee e: employees) { if(e.getFirstName().equals(firstName)) { return(e); } } return(null); } 36
  • 35. Without Predicate: Finding Employee by Salary public static Employee findEmployeeBySalary (List<Employee> employees, double salaryCutoff) { for(Employee e: employees) { if(e.getSalary() >= salaryCutoff) { return(e); } } return(null); } 37 Most of the code from the previous example is repeated. If we searched by last name or employee ID, we would yet again repeat most of the code.
  • 36. Refactor #1: Finding First Employee that Passes Test public static Employee firstMatchingEmployee (List<Employee> candidates, Predicate<Employee> matchFunction) { for(Employee possibleMatch: candidates) { if(matchFunction.test(possibleMatch)) { return(possibleMatch); } } return(null); } 38
  • 37. Refactor #1: Benefits • Now – We can now pass in different match functions to search on different criteria. Succinct and readable. • firstMatchingEmployee(employees, e -> e.getSalary() > 50000); • firstMatchingEmployee(employees, e -> e.getLastName().equals("…")); • firstMatchingEmployee(employees, e -> e.getId() < 10); • Before – Cumbersome interface. • Without lambdas, we could have defined an interface with a “test” method, then instantiated the interface and passed it in, to avoid some of the previously repeated code. But, this approach would be so verbose that it wouldn’t seem worth it in most cases. The method calls above, in contrast, are succinct and readable. • Doing even better: using generic types – The code is still tied to the Employee class, so we can do even better (next slide). 39
  • 38. Refactor #2: Finding First Entry that Passes Test public static <T> T firstMatch (List<T> candidates, Predicate<T> matchFunction) { for(T possibleMatch: candidates) { if(matchFunction.test(possibleMatch)) { return(possibleMatch); } } return(null); } 40 We can now pass in different match functions to search on different criteria as before, but can do so for any type, not just for Employees.
  • 39. Using firstMatch public static Employee findEmployeeWithFirstName (List<Employee> employees, String firstName) { return(firstMatch(employees, e -> e.getFirstName().equals(firstName))); } public static Employee findEmployeeWithSalary (List<Employee> employees, double salaryCutoff) { return(firstMatch(employees, e -> e.getSalary() > salaryCutoff)); } 41 Note that firstName and salaryCutoff were never explicitly declared “final”. Java 8 requires the variables to be “effectively final”, but not explicitly declared final. Full code for Employee class and sample employees at http://www.coreservlets.com/java-8-tutorial/
  • 40. Other Lambda Building Blocks • Function Function<Employee> raise = e -> e.getSalary() + 1000; for(Employee employee: employees) { employee.setSalary(raise.apply(employee)); } – Used for the “map” operation of Stream: take a Stream of one type and produce a Stream of another type by passing each value through the Function. • Consumer Consumer<Employee> raise = e -> e.setSalary(e.getSalary() * 1.1); for(Employee employee: employees) { raise.accept(employee); } – Used for the “forEach” operation of Stream: apply some operation to each element of a Stream • BinaryOperator BinaryOperator<Integer> adder = (n1, n2) -> n1 + n2; int sum = adder.apply(num1, num2); – Used for the “reduce” operation of Stream: combine values two at a time until you have only a single value remaining. 42
  • 41. © 2013 Marty Hall Customized Java EE Training: http://courses.coreservlets.com/ Java, JSF 2, PrimeFaces, HTML5, JSP, Ajax, jQuery, Spring, Hibernate, RESTful Web Services, Hadoop, Android. Developed and taught by well-known author and developer. At public venues or onsite at your location. Overview of Streams
  • 42. Streams • Big idea – Wrappers around data sources such as arrays or lists. Support many convenient and high-performance operations expressed succinctly with lambdas, executed sequentially or in parallel. • Examples shapeList.stream().filter(s -> s.getColor() == Color.BLUE) .forEach(s -> s.setColor(Color.RED)); Stream.of(idArray).map(EmployeeUtils::findById) .filter(e -> e != null) .filter(e -> e.getSalary() > 500000) .findFirst() .orElse(null)); • This appears to say “take the n ids, produce a Stream of n corresponding Employee objects, remove null entries (unknown ids), throw out all except those whose salary is above $500K, find first entry, return it if it exists, otherwise return null”. But, if third id corresponds to someone with salary above $500K, it only calls findById three times, even if the id array has 100 entries. Lazy!44
  • 43. Characteristics of Streams • Not data structures – Streams have no storage. They carry values from a source through a pipeline of operations. • Source can be array, List, other collection, generator function, etc. • Designed for lambdas – All Stream operations take lambdas as arguments • Do not support indexed access – You can ask for the first element, but not the second or third or last element. But, see next bullet. • Can easily be output as arrays or Lists – Simple syntax to build an array or List from a Stream 45
  • 44. Characteristics of Streams (Continued) • Lazy – Many Stream operations are postponed until it is known how much data is eventually needed • E.g., if you do a 10-second-per-item operation on a 100 element list, then select the first entry, it takes 10 seconds, not 1000 seconds. • Parallelizable – If you designate a Stream as parallel, then operations on it will automatically be done in parallel, without having to write explicit multi-threading code. • Can be unbounded – Unlike with collections, you can designate a generator function, and clients can consume entries as long as they want, with values being generated on the fly. 46
  • 45. Making Streams • From individual values – Stream.of(val1, val2, …) • From array – Stream.of(someArray), Arrays.stream(someArray) • From List (and other collections) – someList.stream(), someOtherCollection.stream() • From a “function” – Stream.generate, Stream.iterate • From a StreamBuilder – someBuilder.build() • From String – String.chars, Arrays.stream(someString.split(...)) • From another Stream – distinct, filter, map, limit, sorted, substream 47
  • 46. Turning Streams into Pre-Java-8 Data Structures • Array – strm.toArray(EntryType[]::new) • E.g., employeeStream.toArray(Employee[]::new) – The argument to toArray is normally EntryType[]::new, but in general is a Supplier that takes an int (size) as an argument and returns an empty array that can be filled in. There is also a zero-argument toArray() method, but this returns Object[], not Blah[], and it is illegal to cast Object[] to Blah[], even when all entries in the array are Blahs. • List – strm.collect(Collectors.toList()) • Common to do “import static java.util.stream.Collectors.*;” then to do strm.collect(toList()) • Other collections – strm.collect(Collectors.toSet()) – strm.collect(Collectors.groupingBy(…)), etc. • String – strm.collect(Collectors.joining(delim)).toString()48
  • 47. © 2013 Marty Hall Customized Java EE Training: http://courses.coreservlets.com/ Java, JSF 2, PrimeFaces, HTML5, JSP, Ajax, jQuery, Spring, Hibernate, RESTful Web Services, Hadoop, Android. Developed and taught by well-known author and developer. At public venues or onsite at your location. Core Stream Methods
  • 48. Stream Methods • Big idea – You wrap a Stream around a data source such as an array or List, then you can do operations on each element (forEach), make a new Stream by transforming each element (map), remove elements that don’t match some criterion (filter), combine elements (reduce), etc. • Core methods (covered here) – forEach, map, filter, findFirst, reduce • Methods covered in online tutorial – distinct, limit, substream, noneMatch, allMatch, anyMatch, count, collect, min, max, sum, sorted • See http://www.coreservlets.com/java-8-tutorial/ 50
  • 49. Core Stream Methods • forEach(Consumer) – employees.forEach(e -> e.setSalary(e.getSalary() * 11/10)) • map(Function) – ids.map(EmployeeUtils::findEmployeeById) • filter(Predicate) – employees.filter(e -> e.getSalary() > 100000) • findFirst() – employees.filter(…).findFirst().get() • reduce(starterValue, BinaryOperator) – nums.reduce(Double.MIN_VALUE, Double::max) 51
  • 50. forEach • Big idea – Easy way to loop over Stream elements. – You supply a lambda to forEach, and that lambda is called on each element of the Stream • More precisely, you supply a Consumer to forEach, and each element of the Stream is passed to that Consumer’s accept method. But, few people think of it in these low- level terms. • Quick examples – Print each element Stream.of(someArray).forEach(System.out::println); – Clear all JTextFields fieldList.stream().forEach(field -> field.setText("")); 52
  • 51. forEach vs. for Loops 53 • for List<Employee> employees = getEmployees(); for(Employee e: employees) { e.setSalary(e.getSalary() * 11/10); } • forEach Stream<Employee> employees = getEmployees().stream(); employees.forEach(e -> e.setSalary(e.getSalary() * 11/10)); • Advantages of forEach – More succinct – Designed for lambdas – Can be made parallel with minimal effort • someStream.parallel().forEach(someLambda);
  • 52. map • Big idea – Produces a new Stream that is the result of applying a Function to each element of original Stream • Quick examples – Array of squares Double[] nums = { 1.0, 2.0, 3.0, 4.0, 5.0 }; Double[] squares = Stream.of(nums).map(n -> n * n).toArray(Double[]::new); – List of Employees with given IDs Integer[] ids = { 1, 2, 4, 8 }; List<Employee> matchingEmployees = Stream.of(ids).map(EmployeeUtils::findById) .collect(toList()); 54
  • 53. filter • Big idea – Produces a new Stream that contain only the elements of the original Stream that pass a given test • Quick examples – Even numbers Integer[] nums = { 1, 2, 3, 4, 5, 6 }; Integer[] evens = Stream.of(nums).filter(n -> n%2 == 0).toArray(Integer[]::new); – Even numbers greater than 3 Integer[] evens = Stream.of(nums).filter(n -> n%2 == 0) .filter(n -> n>3) .toArray(Integer[]::new); 55
  • 54. Aside: the Optional Class • Big idea – Optional either stores a T or stores nothing. Useful for methods that may or may not find a value. New in Java 8. • The value of findFirst of Stream is an Optional • Syntax – Making an Optional • Optional<Blah> value = Optional.of(someBlah); • Optional<Blah> value = Optional.empty(); // Missing val – Most common operations on an Optional • value.get() – returns value if present or throws exception • value.orElse(other) – returns val if present or other • value.ifPresent(Consumer) – runs lambda if val is present • value.isPresent() – returns true if val is present 56
  • 55. findFirst • Big idea – Returns an Optional for the first entry in the Stream. Since Streams are often results of filtering, there might not be a first entry, so the Optional could be empty. • There is also a similar findAny method, which might be faster for parallel Streams. – findFirst is faster than it looks when paired with map or filter. More details in slide on lazy evaluation, but idea is that map or filter know to only find a single match and then stop. • Quick examples – When you know there is at least one entry • someStream.map(…).findFirst().get() – When unsure if there are entries or not • someStream.filter(…).findFirst().orElse(otherValue) 57
  • 56. reduce • Big idea – You start with a seed (identity) value, combine this value with the first entry of the Stream, combine the result with the second entry of the Stream, and so forth • Most common version takes starter value and BinaryOperator, and returns result directly. • Alternative version takes BinaryOperator that is associative, and uses no starter. It starts by combining first two values with each other. This returns an Optional. • reduce is particularly useful when combined with earlier map or filter operations • Quick examples – Maximum of numbers • nums.stream().reduce(Double.MIN_VALUE, Double::max) – There is also builtin “max” method, so you can do even better than the above – Product of numbers • nums.stream().reduce(1, (n1, n2) -> n1 * n2)58
  • 57. © 2013 Marty Hall Customized Java EE Training: http://courses.coreservlets.com/ Java, JSF 2, PrimeFaces, HTML5, JSP, Ajax, jQuery, Spring, Hibernate, RESTful Web Services, Hadoop, Android. Developed and taught by well-known author and developer. At public venues or onsite at your location. Cool Stream Properties
  • 58. Test Case: Google Employees • Googlers (first, last, ID, salary) private static Employee[] googlers = { new Employee("Larry", "Page", 1, 9999999), new Employee("Sergey", "Brin", 2, 8888888), new Employee("Eric", "Schmidt", 3, 7777777), new Employee("Nikesh", "Arora", 4, 6666666), new Employee("David", "Drummond", 5, 5555555), new Employee("Patrick", "Pichette", 6, 4444444), new Employee("Susan", "Wojcicki", 7, 3333333), new Employee("Peter", "Norvig", 8, 900000), new Employee("Jeffrey", "Dean", 9, 800000), new Employee("Sanjay", "Ghemawat", 10, 700000), new Employee("Gilad", "Bracha", 11, 600000) }; • findGoogler – Maps an employee ID to an Employee 60
  • 59. Lazy Evaluation • Code (ID 8 – Peter Norvig – is the match) Integer[] ids = { 16, 8, 4, 2, 1 }; Employee person = Stream.of(ids).map(EmployeeSamples::findGoogler) .filter(e -> e != null) .filter(e -> e.getSalary() > 500000) .findFirst().orElse(null); • Questions – How many times is findGoogler called? The null check performed? getSalary called? • Answers – findGoogler: 2 – Check for null: 2 (id 16 has no match) – getSalary: 1 61
  • 60. Parallel Streams • Big idea – By designating that a Stream be parallel, the operations from forEach and similar methods are automatically done in parellel. No explicit multi-threading code is required. • This is easiest to see with methods like forEach (assuming the operation is thread-safe!): the performance should scale linearly with the number of cores. But, even operations like map, filter, reduce, and findAny can get big performance gains. • Quick examples – Do side effects serially • someStream.forEach(someThreadSafeOp) – Do side effects concurrently • someStream.parallel().forEach(someThreadSafeOp) 62
  • 61. Infinite Streams • Stream.generate(valueGenerator) – Stream.generate lets you specify a Supplier. This Supplier is invoked each time the system needs a Stream element. • Particularly powerful when the Supplier maintains state • Stream.iterate(initialValue, valueTransformer) – Stream.iterate lets you specify a seed and a UnaryOperator f. The seed becomes the first element of the Stream, f(seed) becomes the second element, f(second) becomes third element, etc. • Usage – The values are not calculated until they are needed – To avoid unterminated processing, you must eventually use a size- limiting operation like limit or findFirst (but not substream alone) • The point is not really that this is an “infinite” Stream, but that it is an “on the fly” Stream – one with no fixed size, where the values are calculated as you need them. 63
  • 62. Series of Large Prime Numbers • Idea – Generate a series of very large consecutive prime numbers (e.g., 100 or 150 digits or more) – Large primes are used extensively in cryptography • Approach – Start with a prime BigInteger as the seed – Supply a UnaryOperator that finds the first prime number higher than the given one • Core code Stream.iterate(Primes.findPrime(numDigits), Primes::nextPrime) .limit(someCutoff) 64 Due to lazy evaluation, it only builds someCutoff number of elements. I.e., it calls findPrime once and nextPrime someCutoff-1 times.
  • 63. Making Stream of Consecutive Primes public static Stream<BigInteger> makePrimeStream (int numDigits) { return(Stream.iterate(Primes.findPrime(numDigits), Primes::nextPrime)); } public static Stream<BigInteger> makePrimeStream (int numDigits, int numPrimes) { return(makePrimeStream(numDigits).limit(numPrimes)); } public static List<BigInteger> makePrimeList(int numDigits, int numPrimes) { return(makePrimeStream(numDigits, numPrimes) .collect(toList())); } 65
  • 64. Primes: Example • Code System.out.println("10 100-digit primes:"); PrimeStream.makePrimeStream(100, 10) .forEach(System.out::println); • Results 10 100-digit primes: 3484894489805924599033259501599559961057903572743870105972345438458556253531271262848463552867976353 3484894489805924599033259501599559961057903572743870105972345438458556253531271262848463552867976647 3484894489805924599033259501599559961057903572743870105972345438458556253531271262848463552867976663 3484894489805924599033259501599559961057903572743870105972345438458556253531271262848463552867976689 3484894489805924599033259501599559961057903572743870105972345438458556253531271262848463552867977233 3484894489805924599033259501599559961057903572743870105972345438458556253531271262848463552867977859 3484894489805924599033259501599559961057903572743870105972345438458556253531271262848463552867977889 3484894489805924599033259501599559961057903572743870105972345438458556253531271262848463552867977989 3484894489805924599033259501599559961057903572743870105972345438458556253531271262848463552867978031 3484894489805924599033259501599559961057903572743870105972345438458556253531271262848463552867978103 66
  • 65. © 2013 Marty Hall Customized Java EE Training: http://courses.coreservlets.com/ Java, JSF 2, PrimeFaces, HTML5, JSP, Ajax, jQuery, Spring, Hibernate, RESTful Web Services, Hadoop, Android. Developed and taught by well-known author and developer. At public venues or onsite at your location. Wrap-Up
  • 66. Online Resources • https://jdk8.java.net/lambda/ – Lets you download Java 8 code and JavaDoc API. • You can also browse latest version of JavaDoc API at http://download.java.net/jdk8/docs/api/ • http://openjdk.java.net/projects/lambda/ – Info on how to use Eclipse, NetBeans, and IntelliJ IDEA with Java 8 – Technical papers on Java 8 features • http://www.coreservlets.com/java-8-tutorial/ – More details on lambdas and streams. • Includes map/reduce • Covers lazy, infinite, and parallel streams – All source code downloadable for unrestricted use. 68
  • 67. Lambda Syntax Summary • Most basic form (String s1, String s2) -> { return(s1.length() - s2.length()); } • Type inferencing (s1, s2) -> { return(s1.length() - s2.length()); } • Expressions for body (s1, s2) -> s1.length() - s2.length() • Omitting parens event -> setBg(Color.BLUE) • More – Method references (Math::cos) – Mark your interfaces with @FunctionalInterface – Can use “effectively final” local vars – Many builtin functional (SAM) interfaces in java.util.function 69
  • 68. Lambda Building Blocks • Predicate Predicate<Employee> matcher = e -> e.getSalary() > 50000; if(matchFunction.test(someEmployee)) { doSomethingWith(someEmployee); } • Function Function<Employee> raise = e -> e.getSalary() + 1000; for(Employee employee: employees) { employee.setSalary(raise.apply(employee)); } • Consumer Consumer<Employee> raise = e -> e.setSalary(e.getSalary() * 1.1); for(Employee employee: employees) { raise.accept(employee); } • BinaryOperator BinaryOperator<Integer> adder = (n1, n2) -> n1 + n2; int sum = adder.apply(num1, num2); 70
  • 69. Streams • Core Stream methods – forEach [void output] • someStream.forEach(e -> e.setPay(e.getPay() * 11/10)) – map [outputs a Stream] • numStream.map(Math::sqrt) – filter [outputs a Stream] • employeeStream.filter(e -> e.getSalary() > 500000) – findFirst [outputs an Optional] • stream.findFirst().get(), stream.findFirst().orElse(other) – reduce [outputs a single value of the type Stream contains] • numStream.reduce(0, Integer::sum) • Fancy stream properties – strm.filter(…).map(…).map(…).findFirst() is lazy – traverses at most once – stream.parallel().forEach(…) does operations concurrently – Stream.generate, Stream.iterate can build elements on-the-fly 71
  • 70. Summary • Yay: we have lambdas – Concise and succinct – Familiar to developers that know functional programming – Fits well with new streams API – Also have method references – Many functional interfaces built in • Boo: still not real functional programming – Type is class that implements interface, not a “real” function • Must create or find interface 1st, must know method name – Cannot use mutable local variables
  • 71. More Info • Detailed Java 8 tutorial – http://www.coreservlets.com/java-8-tutorial/ • Other free tutorials – http://www.coreservlets.com/ • Java 8, general Java programming, Hadoop, JSF 2, PrimeFaces, Android development, Spring, Hibernate, Ajax/jQuery, GWT, servlets/JSP, RESTful Web Services • Training courses on above topics – Public courses hosted at JHU/Dorsey in Elkridge MD • http://courses.coreservlets.com/public-courses/ – Customized courses available at your company • http://courses.coreservlets.com/ • Contact Marty – hall@coreservlets.com 74
  • 72. © 2013 Marty Hall Customized Java EE Training: http://courses.coreservlets.com/ Java, JSF 2, PrimeFaces, HTML5, JSP, Ajax, jQuery, Spring, Hibernate, RESTful Web Services, Hadoop, Android. Developed and taught by well-known author and developer. At public venues or onsite at your location. Questions? 75 JSF 2, PrimeFaces, Java 7 or 8, Ajax, jQuery, Hadoop, RESTful Web Services, Android, HTML5, Spring, Hibernate, Servlets, JSP, GWT, and other Java EE training.