Question? Leave a message!




What is a Lambda Expression

What is a Lambda Expression 3
The Road To Lambda Java 8 Day, EclipseCon 2014 Alex Buckley, Oracle lambdadevopenjdk.java.net 1 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. 2 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Modernizing Java  Java SE 8 is a big step forward for the Java Language – Lambda Expressions for better abstraction – Default Methods for interface evolution  Java SE 8 is a big step forward for the Java Libraries – Bulk data operations on Collections – More library support for parallelism  Together, perhaps the biggest upgrade ever to the Java programming model  Why did we choose the features we did  How do we evolve a mature language 3 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. The Language 4 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. What is a Lambda Expression  A lambda expression is an anonymous method – Has a parameter list, a return type, and a body (Object o) o.toString() – Body can refer to effectively final variables in the enclosing lexical scope (Person p) p.getName().equals(name)  A method reference is a reference to an existing method Object::toString  Allow you to treat code as data – Behavior can be expressed succinctly, stored in variables, and passed to methods – A huge deal because of the impact on library design 5 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. What is the Type of a Lambda Expression  Many languages have some notion of a function type – “Function from long to int” – Seemed reasonable (at first) to consider adding them to Java  But… – JVM has no native representation of function type in VM type signatures – Obvious tool for representing function types is generics  But then function types would be erased (and boxed) – Is there a simpler alternative 6 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Functional Interfaces  Historically we used singlemethod interfaces to represent functions – Runnable, Comparator, ActionListener, FileFilter, … – Let’s call them functional interfaces – And add some new ones like PredicateT, ConsumerT, SupplierT  A lambda expression evaluates to an instance of a functional interface PredicateString isEmpty = s s.isEmpty(); PredicateString isEmpty = String::isEmpty; Runnable r = () System.out.println(“Boo”); ;  We define functional interfaces structurally – No syntax or optin needed – Existing libraries are forwardcompatible with lambda expressions 7 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Times Change  In 1995, most popular languages did not support lambda expressions  By 2013, Java was just about the last holdout – C added them in 2007, ObjectiveC in 2010, C++ in 2011 – New languages being designed today all do "In another thirty years people will laugh at anyone who tries to invent a language without closures, just as they'll laugh now at anyone who tries to invent a language without recursion." Mark Jason Dominus 8 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Lambdas for Java – a long and winding road  1997 – Odersky / Wadler experimental “Pizza” work – “IMHO Pizza makes finally a usefull language out of java” comp.lang.java 3/6/97  1997 – Java 1.1 added inner classes – Too bulky, complex name resolution rules, many limitations  20062008 – vigorous community debate – Multiple proposals, including BGGA and CICE – Each had a different orientation  BGGA – facilitating control abstraction in libraries  CICE – reducing syntactic overhead of inner classes – Things ran aground at this point… 9 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Lambdas for Java – a long and winding road  2009Dec – OpenJDK Project Lambda formed  2010May – First prototype  2010Nov – JSR335 filed  2011Nov – Early Draft Review 1  2011Nov – Developer Preview binaries on java.net  2012Jun – Early Draft Review 2  2013Feb – Early Draft Review 3  2014Jan – Proposed Final Draft 10 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Evolving a Mature Language – Key Forces  Encouraging change – Adapting to change  Everything changes: hardware, attitudes, fashions, problems, demographics – Righting what’s wrong  Inconsistencies, holes, poor user experience  Discouraging change – Maintaining compatibility  Low tolerance for change that will break anything – Preserving the “feel of Java”  Can’t alienate user base in quest for “something better”  Easy to focus on cool new stuff, but there’s lots of cool old stuff too 11 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Lambdas: Adapting to Change  In 1995, pervasive sequentiality infected programming language design – forloops are sequential and impose a specific order  Why wouldn’t they be Why invite nondeterminism  Determinism is convenient – when free  This sequentiality assumption propagated into libraries (e.g., Iterator) – Pervasive mutability  Mutability is convenient – when free  Object creation was expensive and mutation was cheap  In today’s multicore world, these are the wrong defaults – Can’t just outlaw forloops and mutability – Instead, gently encourage something better  Lambda expressions are that gentle push 12 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Problem: External Iteration  Snippet takes the red blocks and colors them blue  Uses foreach loop for (Shape s : shapes) – Loop is inherently sequential if (s.getColor() == RED) s.setColor(BLUE); – Client has to manage iteration – This is called external iteration  foreach loop hides complex interaction between library and client – Iterable, iterator(), Iterator.next(), Iterator.hasNext()  What’s the problem Conflates the what with the how.  A language construct that is inherently sequential is a significant problem. 13 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Solution: Internal Iteration  Rewritten to use lambda and Collection.forEach – Not just a syntactic change shapes.forEach(s – Now the library is in control if (s.getColor() == RED) s.setColor(BLUE); – This is internal iteration ) – More what, less how  Library is free to use parallelism / outoforder execution / laziness  Client passes behavior (lambda) into the API as data  Enables API designers to build more powerful, expressive APIs – Greater power to abstract over behavior 14 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Lambdas Libraries 15 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Lambdas Enable Better APIs  Lambda expressions enable delivery of more powerful APIs  The clientlibrary boundary is more permeable – Client can provide bits of functionality to be mixed into execution – Client determines the what – Library remains in control of the how  Safer: less state management in the client  Faster: exposes more opportunities for optimization 16 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example: Sorting  If we want to sort a List today, we’d write a Comparator Collections.sort(people, new ComparatorPerson() public int compare(Person x, Person y) return x.getLastName().compareTo(y.getLastName()); );  Could replace Comparator with a lambda, but only gets us so far  Comparator conflates extraction of sort key with ordering of that key – Better to separate the two aspects 17 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example: Sorting  Added static method Comparator.comparing(f) – Takes a “key extractor” function from T to some Comparable key – Returns a ComparatorT – This is a higherorder function – functions in, functions out interface ComparatorT public static T, U extends Comparable super U ComparatorT comparing(FunctionT, U f) return (x, y) f.apply(x).compareTo(f.apply(y)); ComparatorPerson byLastName = Comparator.comparing(Person::getLastName); 18 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Lambdas Enable Better APIs  The comparing() method is one built for lambdas – Consumes an “extractor” function and produces a “comparator” function – Factors key extraction (client concern) from comparison (library concern) – Eliminates redundancy, boilerplate  Key effect on APIs is: more composability – Centralize generation of Comparators in one place – Leads to better factoring, more regular client code, more reuse  Lambdas in the language → can write better libraries → more readable, less errorprone user code 19 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Lambdas Enable Better APIs  Generally, we prefer to evolve the programming model through libraries – Time to market – can evolve libraries faster than language – Decentralized – more library designers than language designers – Risk – easier to change libraries, more practical to experiment – Impact – language changes require coordinated changes to multiple compilers, IDEs, and other tools  But sometimes we reach the limits of what is practical to express in libraries, and need a little help from the language – But a little help, in the right places, can go a long way 20 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Problem: Interface Evolution  The example used a new Collection method – forEach() – If Java had lambdas in 1997, our Collections would surely look different  Interfaces are a doubleedged sword – Cannot compatibly evolve them unless you control all implementations – Reality: APIs age  As we add cool new language features, existing APIs look even older – Lots of bad options for dealing with aging APIs  Let the API stagnate  Replace it in entirety (every few years)  Nail bags on the side (e.g., Collections.sort()) 21 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Default Methods  Need a proper mechanism for compatibly evolving APIs  New feature: default methods interface CollectionT default void forEach(ConsumerT action) – Virtual interface method with for (T t : this) action.apply(t); default implementation – “default” is the dual of “abstract”  Lets us compatibly evolve libraries over time – Default implementation provided in the interface – Subclasses can override with better implementations – Adding a default method is binarycompatible and sourcecompatible 22 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Default Methods  Is this multiple inheritance in Java – Java always had multiple inheritance of abstract methods – This adds multiple inheritance of behavior – But not of state, where most of the trouble comes from  Compared to C extension methods: Java’s default methods are virtual and declarationsite, not static and usesite  Compared to Scala’s Traits: Java interfaces are stateless (more like Fortress’ Traits)  How do we resolve conflicts between declarations in multiple supertypes – Three simple rules 23 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Rule 1: Class Wins  If a class can inherit a method from a superclass and a superinterface, prefer the superclass method – Defaults only considered if no method declared in superclass chain – True for both concrete and abstract superclass methods  Ensures compatibility with preSE 8 inheritance – Any call site that linked under previous rules links to the same target  Otherwise… 24 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Rule 2: Subtypes Win  If a class can inherit a method from two interfaces, and one is more specific than (a subtype of) the other, prefer the more specific – An implementation in List would take precedence over one in Collection  The shape of the inheritance tree doesn’t matter – Only consider the set of supertypes, not order in which they are inherited  Otherwise… 25 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Rule 3: There is No Rule 3  If rule 1 does not apply, and rule 2 does not yield a unique, most specific defaultproviding interface… – Explicitly reabstract it – Implement the method yourself interface A – Implementation can delegate to default void m() ... noninherited implementation with interface B new construct X.super.m() default void m() ... class C implements A, B // Must implement/reabstract m() void m() A.super.m(); 26 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Diamonds – No Problem  Diamonds do not pose a problem for behavior inheritance – More problematic for state inheritance  For D, there is a unique mostspecific defaultproviding interface – A – D inherits m() from A, via two paths – “Redundant” inheritance does not affect the resolution interface A default void m() ... interface B extends A interface C extends A class D implements B, C 27 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example – Evolving Interfaces  Adding a new method with default is source and binarycompatible  Default methods are instance methods – Type of ‘this’ is the declaring interface – Default implementation can invoke methods from enclosing interface, e.g. iterator() interface CollectionE default boolean removeIf(Predicate super E filter) boolean removed = false; IteratorE it = iterator(); while (it.hasNext()) … return removed; 28 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example – “Optional” Methods  Adding a default to an existing method is source and binarycompatible  Default methods can reduce implementation burden – Most implementations of Iterator don’t provide a useful remove() – So why make implementers write one that just throws interface IteratorT boolean hasNext(); T next(); default void remove() throw new UnsupportedOperationException(); 29 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Example – Combinators  Comparator.reversed() – reverses sort order of a Comparator – Default method on Comparator, just invokes compare() interface ComparatorT default ComparatorT reversed() return (o1, o2) compare(o2, o1); ComparatorPerson byLastNameDescending = Comparator.comparing(Person::getLastName).reversed(); 30 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. The Java Libraries 31 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Bulk operations on Collections  “Color the red blocks blue” can be decomposed into filter+forEach shapes.forEach(s if (s.getColor() == RED) s.setColor(BLUE); ) shapes.stream() .filter(s s.getColor() == RED) .forEach(s s.setColor(BLUE); );  Why is this code better Each part does one thing, and is clearly labeled. 32 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Bulk operations on Collections  Collect the blue Shapes into a List ListShape blueBlocks = shapes.stream() .filter(s s.getColor() == BLUE) .collect(Collectors.toList());  If each Shape lives in a Box, find Boxes containing a blue shape SetBox hasBlueBlock = shapes.stream() .filter(s s.getColor() == BLUE) .map(Shape::getContainingBox) .collect(Collectors.toSet()); 33 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Bulk operations on Collections  The new bulk operations are expressive and composable – Compose compound operations from basic building blocks (lambdas) – Each stage does one thing – Client code reads more like the problem statement – Structure of client code is less brittle (antifragile)  Small changes to the problem small changes to the code – Less extraneous “noise” from intermediate results  No ‘accumulator’ or state variables 34 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Which do you prefer SetSeller sellers = new HashSet(); for ( Txn t : txns) if (t.getBuyer().getAge() = 65) sellers.add(t.getSeller()); ListSeller sorted = new ArrayList(sellers); Collections.sort(sorted, new ComparatorGroup() public int compare(Seller a, Seller b) return a.getName().compareTo(b.getName()); ); for (Seller s : sorted) System.out.println(s.getName()); txns.stream()  Or… .filter(t t.getBuyer().getAge() = 65) .map(Txn::getSeller) .distinct() .sort(comparing(Seller::getName)) .forEach(s System.out.println(s.getName()); 35 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. From Collections to Streams  To add bulk operations, we create a new abstraction: Stream – Represents a stream of values – Not a data structure – doesn’t store the values – Source can be a Collection, array, generating function, I/O…  Operations that produce new streams are lazy – Encourages a “fluent” usage style – Efficient – does a single pass on the data collection.stream() .filter(f::isBlue) .map(f::getBar) .forEach(System.out::println); 36 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Comparing Approaches Collections Streams Code deals with individual data items Code deals with data set Focused on how Focused on what Code doesn’t read like the problem statement Code reads like the problem statement Steps mashed together Wellfactored Leaks extraneous details No “garbage variables” Inherently sequential Same code can be sequential or parallel 37 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Parallelism 38 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Parallelism  Goal: Handle parallelism in the libraries, not the language – Libraries can hide a host of complex concerns (task scheduling, thread management, load balancing)  Goal: Reduce conceptual and syntactic gap between sequential and parallel forms of the same computation – Historically, sequential and parallel code for a given computation don’t look anything like each other 39 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Obtrusive Parallelism  Java SE 7 has a generalpurpose Fork/Join framework – Powerful and efficient, but not so easy to program to – Based on recursive decomposition  Divide problem into subproblems, solve in parallel, combine results  Keep dividing until small enough to solve sequentially – Tends to be efficient across a wide range of processor counts – Generates reasonable load balancing with no central coordination 40 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Parallel Sum with Fork/Join (SE 7) ForkJoinPool pool = new ForkJoinPool(nThreads); SumFinder finder = new SumFinder(new SumProblem()); pool.invoke(finder); class SumProblem final ListShape shapes; class SumFinder extends RecursiveAction final int size; private final SumProblem problem; int sum; SumProblem(ListShape ls) this.shapes = ls; protected void compute() size = ls.size(); if (problem.size THRESHOLD) sum = problem.solveSequentially(); else public int solveSequentially() int m = problem.size / 2; int sum = 0; SumFinder left, right; for (Shape s : shapes) left = new SumFinder(problem.subproblem(0, m)) if (s.getColor() == BLUE) right = new SumFinder(problem.subproblem(m, problem.size)); sum += s.getWeight(); forkJoin(left, right); sum = left.sum + right.sum; return sum; public SumProblem subproblem(int start, int end) return new SumProblem(shapes.subList(start, end)); 41 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Parallel Sum with Streams (SE 8) int sumOfWeight  Sequential sumofweights: = shapes.stream() .filter(s s.getColor() == BLUE) .mapToInt(Shape::getWeight) .sum(); int sumOfWeight  Parallel sumofweights: = shapes.parallelStream() .filter(s s.getColor() == BLUE) .mapToInt(Shape::getWeight) .sum();  Explicit but unobtrusive parallelism  All three operations fused into a single parallel pass 42 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. So … Why Lambda  It’s about time – Java was the lone holdout among mainstream OO languages over lambdas – Adding them to Java is no longer a radical idea  Lambdas provide libraries with a path to multicore – Parallelfriendly APIs need internal iteration – Internal iteration needs a concise codeasdata mechanism  Lambdas empower library developers – More powerful, flexible libraries – Higher degree of cooperation between libraries and client code – Better libraries means more expressive, less errorprone code for users 43 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Modernizing Java  Java SE 8 is a big step forward for the Java Language – Lambda Expressions for better abstraction – Default Methods for interface evolution  Java SE 8 is a big step forward for the Java Libraries – java.util.stream. + java.util.function. – Upgrades throughout java.util.  Together, perhaps the biggest upgrade ever to the Java programming model  Shipping today 44 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. Books  “Java SE 8 for the Really Impatient” (Horstmann)  “Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions” (Subramaniam)  “Mastering Lambdas: Java Programming in a Multicore World” (Naftalin)  “Java 8 in Action: Lambdas, Streams, and functionalstyle programming” (Urma, Fusco, Mycroft)  “Java 8 Lambdas: Pragmatic Functional Programming” (Warburton)  “Java in a Nutshell” (Evans, Flanagan) 45 Copyright © 2014, Oracle and/or its affiliates. All rights reserved. The preceding 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. 46 Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Website URL
Comment