SlideShare a Scribd company logo
<Insert Picture Here>
JSR-335 Update
Lambda expressions for the Java Language
Brian Goetz
Java Language Architect
Oracle Corporation
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.
JSR-335
•  JSR 335 is a coordinated co-evolution of the Java
platform
•  Language – lambda expressions (closures), interface
evolution, better type inference
•  Libraries – Bulk parallel operations on collections
•  VM – support for default methods and lambda conversion
•  Major step forward for the Java programming model
•  More parallel-friendly
•  Enable delivery of more powerful libraries
•  Enable developers to write more concise,
less error-prone code
Closures for Java – a long and winding road
•  1997 – Java 1.1 added inner classes – a weak form
of closures
•  Too bulky, complex name resolution rules, many limitations
•  In 2006-2008, a vigorous community debate about
closures
•  Multiple proposals, including BGGA and CICE
•  Each had a different orientation
•  BGGA – creating control abstraction in libraries
•  CICE – reducing syntactic overhead of inner classes
•  Things ran aground at this point…
•  Little evolution from Java SE 5 (2004) until now
•  Project Coin (Small Language Changes) in Java SE 7
Closures for Java – a long and winding road
Closures for Java – a long and winding road
•  Dec 2009 – OpenJDK Project Lambda formed
•  November 2010 – JSR-335 filed
•  Current status
•  EDR #3 filed
•  Prototype RI (source and binary) available on OpenJDK
•  Component of Java SE 8
•  JSR-335 = Lambda Expressions
+ Interface Evolution
+ Bulk Collection Operations
Evolving a major language
•  Key evolutionary forces
•  Adapting to change
•  Everything changes: hardware, attitudes, fashions,
problems, demographics
•  Righting what’s wrong
•  Inconsistencies, holes, poor user experience
•  Maintaining compatibility
•  Low tolerance for change that will break anything
•  Preserving the core
•  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
Adapting to Change
•  In 1995, most mainstream languages did not support
closures
•  Perceived to be “too hard” for ordinary developers
•  Today, Java is just about the last holdout that doesn’t
•  C++ added them recently
•  C# added them in 3.0
•  New languages being designed today all do
Adapting to Change
•  Language design is influenced by the dominant hardware
•  Which changes over time
•  In 1995, pervasive sequentiality infected programming
language design
•  For loops are sequential
•  Why wouldn’t they be? Why invite nondeterminism?
•  Determinism is convenient – when free
•  Similarly, Iterator/Iterable is sequential
•  Pervasive mutability
•  Mutability is convenient – when free
•  Object creation was expensive and mutation cheap
•  In today’s world, these are just the wrong defaults!
•  Can’t just outlaw for loops and mutability
•  Instead, gently encourage something better
Problem – External Iteration
•  “Take the red blocks and colors them blue”
•  Typical solution with foreach loop
•  Loop is inherently sequential
•  Wasn’t a big problem 20 years ago, but times change
•  Client has to manage iteration
•  Conflates “what” with “how”
•  This is called external iteration
•  Hides complex interaction between library and client
for (Shape s : shapes) {
if (s.getColor() == RED)
s.setColor(BLUE);
}
Internal Iteration
•  Re-written to use lambda and Collection.forEach
•  Not just a syntactic change!
•  Now the library is in control
•  Internal iteration – More what, less how
•  Client passes behavior into the API as data
•  Library can use parallelism, out-of-order, laziness
•  Also enable more powerful, expressive APIs
•  Greater power to abstract over behavior
shapes.forEach(s -> {
if (s.getColor() == RED)
s.setColor(BLUE);
})
Lambda Expressions
•  A lambda expression is an anonymous method
•  Has an argument list, a return type, and a body
(Object o) -> o.toString()
•  Can refer to values from the enclosing lexical scope
(Person p) -> p.getName().equals(name)
•  Compiler can often infer parameter types from context
p -> p.getName().equals(name)
•  A method reference is a reference to an existing
method
Object::toString
•  All of these forms allow you to treat code as data
•  Behavior can be stored in variables and passed to methods
What is the type of a lambda?
•  Most languages with lambdas have some notion of a
function type
•  Java language has no concept of function type
•  JVM has no native (unerased) representation of function
type in VM type signatures
•  Adding function types would create many questions
•  How do we represent functions in VM type signatures?
•  How do we create instances of function types?
•  Want to avoid significant VM changes
•  Obvious tool for representing function types is generics
•  But then function types would be … erased
Functional Interfaces
•  Historically used single-method interfaces to model
functions
•  Runnable, Comparator, ActionListener
•  Let’s just give these a name: functional interfaces
•  And add some new ones like Predicate<T>, Block<T>
•  A lambda expression evaluates to an instance of a
functional interface
Predicate<String> isEmpty = s -> s.isEmpty();
Predicate<String> isEmpty = String::isEmpty;
Runnable r = () -> { System.out.println(“Boo!”) };
Functional Interfaces
•  “Just add function types” was obvious … and wrong
•  Would have introduced complexity and corner cases
•  Would have bifurcated libraries into “old” and “new” styles
•  Would have created interoperability challenges
•  Preserve the Core
•  Stodgy old approach may be better than shiny new one
•  Bonus: existing libraries are now forward-compatible
to lambdas
•  Libraries that never imagined lambdas still work with them!
•  Maintains significant investment in existing libraries
•  Fewer new concepts
Problem – Interface Evolution
•  Example used a new Collection method – forEach()
•  I thought you couldn’t add new methods to interfaces?
•  Interfaces are a double-edged 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())
Interface Evolution
•  Libraries need to evolve, or they stagnate
•  Need a mechanism for compatibly evolving APIs
•  New feature: default methods
•  Virtual interface method with default implementation
•  “default” is the dual of “abstract”
•  Three simple rules for resolving inheritance conflicts
•  Superclasses win over superinterfaces
•  More specific interfaces win over less specific
•  After that, concrete classes
must override
interface Collection<T> {
default void forEach(Block<T> action) {
for (T t : this)
action.apply(t);
}
}
Default Methods
•  Similar to, but different from, C# extension methods
•  Java’s default methods are virtual and declaration-site
•  Core principle: API owners should control their APIs
•  Primary goal is API evolution
•  Inheritance rules directed at this primary goal
•  But very useful as an inheritance mechanism on its own!
•  Wait, is this multiple inheritance in Java?
•  Java always had multiple inheritance of types
•  This adds multiple inheritance of behavior
•  But not of state, where most of the trouble comes from
It’s All About The Libraries
•  Generally, we prefer to evolve the programming
model through libraries
•  Time to market – can evolve libraries faster than language
•  Decentralized – more library developers than language
developers
•  Risk – easier to change libraries, more practical to
experiment
•  Impact – language changes require coordinated changes to
multiple compilers, IDEs, and other tools
•  Sometimes we reach the limits of what is practical to
express in libraries, and need a little help from the
language
•  A little help, in the right places, can go a long way!
Lambdas Enable Better APIs
•  Lambda expressions enable more powerful APIs
•  Boundary between client and library is more permeable
•  Client provides bits of behavior to be mixed into execution
(“what”)
•  Library remains in control of the computation (“how”)
•  Safer, exposes more opportunities for optimization
•  Key effect on APIs is: more composability
•  Leads to better factoring, more regular client code, more
reuse
•  Lambdas in the language
→ can write better libraries
→ more readable, less error-prone user code
Example – Sorting
•  Default methods can enhance composability
•  Comparator.reverse(), Comparator.compose()
•  Default methods
offer a “right place”
to put certain code
interface Comparator<T> {
int compare(T o1, T o2);
default Comparator<T> reverse() {
return (o1, o2) -> –(compare(o1, o2));
}
default Comparator<T> compose(Comparator<T> other) {
return (o1, o2) -> {
int cmp = compare(o1, o2);
return (cmp != 0) ? cmp : other.compare(o1, o2);
}
}
}
Comparator<Person> byFirst = ...
Comparator<Person> byLast = ...
Comparator<Person> byFirstLast = byFirst.compose(byLast);
Comparator<Person> byLastDescending = byLast.reverse();
Example – Sorting
•  If we want to sort a List today, we write a Comparator
•  Many layers of nastiness here!
•  Conflates extraction of sort key with ordering of that key
•  Collections class required for helper methods
•  Syntactically verbose
•  Could replace with a lambda, but only gets us so far
•  Better to untangle the intertwined aspects
•  Fewer opportunities for reuse
Collections.sort(people, new Comparator<Person>() {
public int compare(Person x, Person y) {
return x.getLastName().compareTo(y.getLastName());
}
});
Example – Sorting
•  Lambdas encourage finer-grained APIs
•  We add a method that takes a “key extractor” and returns
Comparator
•  The comparing() method is one built for lambdas
•  Higher-order function
•  Eliminates redundancy, boilerplate
Comparator<Person> byLastName
= Comparators.comparing(p -> p.getLastName());
Class Comparators {
public static<T, U extends Comparable<? super U>>
Comparator<T> comparing(Mapper<T, U> m) {
return (x, y) -> m.map(x).compareTo(m.map(y));
}
}
Example – Sorting
Comparator<Person> byLastName
= Comparators.comparing(p -> p.getLastName());
Collections.sort(people, byLastName);
Collections.sort(people,
comparing(p -> p.getLastName());
people.sort(comparing(p -> p.getLastName());
people.sort(comparing(Person::getLastName));
people.sort(comparing(Person::getLastName).reverse());
people.sort(comparing(Person::getLastName)
.compose(comparing(Person::getFirstName)));
Bulk operations on Collections
•  Compute sum of weights of blue shapes
•  Compose compound operations from basic building blocks
•  Each stage does one thing
•  Client code reads more like the problem statement
•  Structure of client code is less brittle
•  Less extraneous “noise” from intermediate results
•  No “garbage variables”
•  Library can use parallelism, out-of-order, laziness for
performance
int sumOfWeight
= shapes.stream()
.filter(s -> s.getColor() == BLUE)
.map(s -> s.getWeight())
.sum();
int sumOfWeight
= shapes.stream()
.filter(s -> s.getColor() == BLUE)
.map(Shape::getWeight)
.sum();
Streams
•  To add bulk operations, we create a new abstraction,
Stream (in package java.util.stream)
•  Key new library abstraction for JSR-335
•  Represents a stream of values
•  Not a data structure – doesn’t store the values
•  Source can be a Collection, array, generating function, IO
•  Encourages a “fluent” usage style
•  Supports operations like filter(), map(), reduce()
•  Retrofit stream() method on Collection
•  As well as: Reader.lines(), Random.ints(),
String.chars(), etc
•  Easy to adapt any aggregate to be a Stream source
Streams
•  What does this code do?
Set<Group> groups = new HashSet<>();
for (Person p : people) {
if (p.getAge() >= 65)
groups.add(p.getGroup());
}
List<Group> sorted = new ArrayList<>(groups);
Collections.sort(sorted, new Comparator<Group>() {
public int compare(Group a, Group b) {
return Integer.compare(a.getSize(), b.getSize())
}
});
for (Group g : sorted)
System.out.println(g.getName());
people.stream()
.filter(p -> p.getAge() > 65)
.map(p -> p.getGroup())
.removeDuplicates()
.sorted(comparing(g -> g.getSize())
.forEach(g -> System.out.println(g.getName());
Parallelism
•  Goal: easy-to-use parallel libraries for Java
•  Libraries can hide a host of complex concerns (task
scheduling, thread management, load balancing)
•  Goal: reduce conceptual and syntactic gap between
serial and parallel expressions of the same
computation
•  Right now, the serial code and the parallel code for a given
computation don’t look anything like each other
•  Fork-join (added in Java SE 7) is a good start, but not
enough
•  Goal: parallelism should be explicit, but unobtrusive
Fork/Join Parallelism
•  JDK7 added general-purpose 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
Parallel Sum with Fork/Join
class SumProblem {
final List<Shape> shapes;
final int size;
SumProblem(List<Shape> ls) {
this.shapes = ls;
size = ls.size();
}
public int solveSequentially() {
int sum = 0;
for (Shape s : shapes) {
if (s.getColor() == BLUE)
sum += s.getWeight();
}
return sum;
}
public SumProblem subproblem(int start, int end) {
return new SumProblem(shapes.subList(start, end));
}
}
ForkJoinExecutor pool = new ForkJoinPool(nThreads);
SumProblem finder = new SumProblem(problem);
pool.invoke(finder);
class SumFinder extends RecursiveAction {
private final SumProblem problem;
int sum;
protected void compute() {
if (problem.size < THRESHOLD)
sum = problem.solveSequentially();
else {
int m = problem.size / 2;
SumFinder left, right;
left = new SumFinder(problem.subproblem(0, m))
right = new SumFinder(problem.subproblem(m, problem.size));
forkJoin(left, right);
sum = left.sum + right.sum;
}
}
}
Parallel Sum with Streams
•  Explicit but unobtrusive parallelism
•  All three operations fused into a single parallel pass
•  Works with ordinary, non-thread-safe collections
•  Extensible mechanism to work with any bulk container
int sumOfWeight
= shapes.stream()
.filter(s -> s.getColor() == BLUE)
.map(s -> s.getWeight())
.sum();
int sumOfWeight
= shapes.stream()
.filter(s -> s.getColor() == BLUE)
.map(Shape::getWeight)
.sum();
int sumOfWeight
= shapes.parallelStream()
.filter(s -> s.getColor() == BLUE)
.map(Shape::getWeight)
.sum();
So … Why Lambda?
•  It’s about time!
•  Java is the lone holdout among mainstream OO languages at
this point to not have closures
•  Adding closures to Java is no longer a radical idea
•  Provide libraries a path to multicore
•  Parallel-friendly APIs need internal iteration
•  Internal iteration needs a concise code-as-data mechanism
•  Empower library developers
•  More powerful, flexible libraries
•  Higher degree of cooperation between libraries and client code
•  Encourage better idioms
•  Gentle push towards a more functional style of programming
<Insert Picture Here>
JSR-335 Update
Lambda expressions for the Java Language
Brian Goetz
Java Language Architect
Oracle Corporation

More Related Content

PDF
PHP, the GraphQL ecosystem and GraphQLite
PDF
Software Engineering Thailand: Programming with Scala
PPT
Writing DSL's in Scala
PDF
Using Scala for building DSLs
PPTX
Scala-Ls1
PPT
WorkinOnTheRailsRoad
PPT
Workin ontherailsroad
PDF
Scala introduction
PHP, the GraphQL ecosystem and GraphQLite
Software Engineering Thailand: Programming with Scala
Writing DSL's in Scala
Using Scala for building DSLs
Scala-Ls1
WorkinOnTheRailsRoad
Workin ontherailsroad
Scala introduction

What's hot (19)

PPTX
Zend Products and PHP for IBMi
PDF
The View - Leveraging Lotuscript for Database Connectivity
PDF
Ruby and Rails short motivation
PDF
Preparing for Scala 3
PPTX
Introduction to Scala
PPTX
Overview of CoffeeScript
PPT
Functional OOP, Clojure style
PDF
A Field Guide to DSL Design in Scala
PPTX
A-Brief-Introduction-To-JAVA8_By_Srimanta_Sahu
PDF
Lessons learned from building Eclipse-based add-ons for commercial modeling t...
PPTX
2018 12-kube con-ballerinacon
PDF
Refactoring to Java 8 (Devoxx UK)
PPTX
Building Your Own DSL with Xtext
ZIP
Why Scala for Web 2.0?
PPTX
Introduction to functional programming, with Elixir
PDF
RepreZen DSL: Pushing the limits of language usability with XText
PDF
RAPID - Building a highly usable API Design language with XText
PPTX
Week 8 intro to python
PDF
Domain specific languages and Scala
Zend Products and PHP for IBMi
The View - Leveraging Lotuscript for Database Connectivity
Ruby and Rails short motivation
Preparing for Scala 3
Introduction to Scala
Overview of CoffeeScript
Functional OOP, Clojure style
A Field Guide to DSL Design in Scala
A-Brief-Introduction-To-JAVA8_By_Srimanta_Sahu
Lessons learned from building Eclipse-based add-ons for commercial modeling t...
2018 12-kube con-ballerinacon
Refactoring to Java 8 (Devoxx UK)
Building Your Own DSL with Xtext
Why Scala for Web 2.0?
Introduction to functional programming, with Elixir
RepreZen DSL: Pushing the limits of language usability with XText
RAPID - Building a highly usable API Design language with XText
Week 8 intro to python
Domain specific languages and Scala
Ad

Similar to JSR 335 / java 8 - update reference (20)

PPTX
The Road to Lambda - Mike Duigou
KEY
Java Closures
KEY
Why ruby and rails
PDF
Service-Oriented Design and Implement with Rails3
PDF
Frontend as a first class citizen
PDF
Java 8 Lambda Expressions & Streams
PDF
Experience Converting from Ruby to Scala
KEY
Polyglot and functional (Devoxx Nov/2011)
PDF
JOSA TechTalks - Compilers, Transpilers, and Why You Should Care
PPTX
Iterator - a powerful but underappreciated design pattern
KEY
Polyglot and Functional Programming (OSCON 2012)
PPTX
Lambda Expressions Java 8 Features usage
PPTX
Java9to19Final.pptx
PDF
Whitepages Practical Experience Converting from Ruby to Reactive
PPTX
Scaling with swagger
PDF
Metamorphic Domain-Specific Languages
PDF
Change data capture with MongoDB and Kafka.
The Road to Lambda - Mike Duigou
Java Closures
Why ruby and rails
Service-Oriented Design and Implement with Rails3
Frontend as a first class citizen
Java 8 Lambda Expressions & Streams
Experience Converting from Ruby to Scala
Polyglot and functional (Devoxx Nov/2011)
JOSA TechTalks - Compilers, Transpilers, and Why You Should Care
Iterator - a powerful but underappreciated design pattern
Polyglot and Functional Programming (OSCON 2012)
Lambda Expressions Java 8 Features usage
Java9to19Final.pptx
Whitepages Practical Experience Converting from Ruby to Reactive
Scaling with swagger
Metamorphic Domain-Specific Languages
Change data capture with MongoDB and Kafka.
Ad

Recently uploaded (20)

PDF
A comparative analysis of optical character recognition models for extracting...
PPTX
Big Data Technologies - Introduction.pptx
PDF
Accuracy of neural networks in brain wave diagnosis of schizophrenia
PPTX
Spectroscopy.pptx food analysis technology
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Electronic commerce courselecture one. Pdf
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PPTX
SOPHOS-XG Firewall Administrator PPT.pptx
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Video forgery: An extensive analysis of inter-and intra-frame manipulation al...
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PPTX
1. Introduction to Computer Programming.pptx
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Encapsulation theory and applications.pdf
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
cuic standard and advanced reporting.pdf
PDF
Unlocking AI with Model Context Protocol (MCP)
A comparative analysis of optical character recognition models for extracting...
Big Data Technologies - Introduction.pptx
Accuracy of neural networks in brain wave diagnosis of schizophrenia
Spectroscopy.pptx food analysis technology
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Assigned Numbers - 2025 - Bluetooth® Document
Per capita expenditure prediction using model stacking based on satellite ima...
Electronic commerce courselecture one. Pdf
Building Integrated photovoltaic BIPV_UPV.pdf
SOPHOS-XG Firewall Administrator PPT.pptx
MYSQL Presentation for SQL database connectivity
Video forgery: An extensive analysis of inter-and intra-frame manipulation al...
Agricultural_Statistics_at_a_Glance_2022_0.pdf
1. Introduction to Computer Programming.pptx
Digital-Transformation-Roadmap-for-Companies.pptx
Encapsulation theory and applications.pdf
Network Security Unit 5.pdf for BCA BBA.
Mobile App Security Testing_ A Comprehensive Guide.pdf
cuic standard and advanced reporting.pdf
Unlocking AI with Model Context Protocol (MCP)

JSR 335 / java 8 - update reference

  • 1. <Insert Picture Here> JSR-335 Update Lambda expressions for the Java Language Brian Goetz Java Language Architect Oracle Corporation
  • 2. 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.
  • 3. JSR-335 •  JSR 335 is a coordinated co-evolution of the Java platform •  Language – lambda expressions (closures), interface evolution, better type inference •  Libraries – Bulk parallel operations on collections •  VM – support for default methods and lambda conversion •  Major step forward for the Java programming model •  More parallel-friendly •  Enable delivery of more powerful libraries •  Enable developers to write more concise, less error-prone code
  • 4. Closures for Java – a long and winding road •  1997 – Java 1.1 added inner classes – a weak form of closures •  Too bulky, complex name resolution rules, many limitations •  In 2006-2008, a vigorous community debate about closures •  Multiple proposals, including BGGA and CICE •  Each had a different orientation •  BGGA – creating control abstraction in libraries •  CICE – reducing syntactic overhead of inner classes •  Things ran aground at this point… •  Little evolution from Java SE 5 (2004) until now •  Project Coin (Small Language Changes) in Java SE 7
  • 5. Closures for Java – a long and winding road
  • 6. Closures for Java – a long and winding road •  Dec 2009 – OpenJDK Project Lambda formed •  November 2010 – JSR-335 filed •  Current status •  EDR #3 filed •  Prototype RI (source and binary) available on OpenJDK •  Component of Java SE 8 •  JSR-335 = Lambda Expressions + Interface Evolution + Bulk Collection Operations
  • 7. Evolving a major language •  Key evolutionary forces •  Adapting to change •  Everything changes: hardware, attitudes, fashions, problems, demographics •  Righting what’s wrong •  Inconsistencies, holes, poor user experience •  Maintaining compatibility •  Low tolerance for change that will break anything •  Preserving the core •  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
  • 8. Adapting to Change •  In 1995, most mainstream languages did not support closures •  Perceived to be “too hard” for ordinary developers •  Today, Java is just about the last holdout that doesn’t •  C++ added them recently •  C# added them in 3.0 •  New languages being designed today all do
  • 9. Adapting to Change •  Language design is influenced by the dominant hardware •  Which changes over time •  In 1995, pervasive sequentiality infected programming language design •  For loops are sequential •  Why wouldn’t they be? Why invite nondeterminism? •  Determinism is convenient – when free •  Similarly, Iterator/Iterable is sequential •  Pervasive mutability •  Mutability is convenient – when free •  Object creation was expensive and mutation cheap •  In today’s world, these are just the wrong defaults! •  Can’t just outlaw for loops and mutability •  Instead, gently encourage something better
  • 10. Problem – External Iteration •  “Take the red blocks and colors them blue” •  Typical solution with foreach loop •  Loop is inherently sequential •  Wasn’t a big problem 20 years ago, but times change •  Client has to manage iteration •  Conflates “what” with “how” •  This is called external iteration •  Hides complex interaction between library and client for (Shape s : shapes) { if (s.getColor() == RED) s.setColor(BLUE); }
  • 11. Internal Iteration •  Re-written to use lambda and Collection.forEach •  Not just a syntactic change! •  Now the library is in control •  Internal iteration – More what, less how •  Client passes behavior into the API as data •  Library can use parallelism, out-of-order, laziness •  Also enable more powerful, expressive APIs •  Greater power to abstract over behavior shapes.forEach(s -> { if (s.getColor() == RED) s.setColor(BLUE); })
  • 12. Lambda Expressions •  A lambda expression is an anonymous method •  Has an argument list, a return type, and a body (Object o) -> o.toString() •  Can refer to values from the enclosing lexical scope (Person p) -> p.getName().equals(name) •  Compiler can often infer parameter types from context p -> p.getName().equals(name) •  A method reference is a reference to an existing method Object::toString •  All of these forms allow you to treat code as data •  Behavior can be stored in variables and passed to methods
  • 13. What is the type of a lambda? •  Most languages with lambdas have some notion of a function type •  Java language has no concept of function type •  JVM has no native (unerased) representation of function type in VM type signatures •  Adding function types would create many questions •  How do we represent functions in VM type signatures? •  How do we create instances of function types? •  Want to avoid significant VM changes •  Obvious tool for representing function types is generics •  But then function types would be … erased
  • 14. Functional Interfaces •  Historically used single-method interfaces to model functions •  Runnable, Comparator, ActionListener •  Let’s just give these a name: functional interfaces •  And add some new ones like Predicate<T>, Block<T> •  A lambda expression evaluates to an instance of a functional interface Predicate<String> isEmpty = s -> s.isEmpty(); Predicate<String> isEmpty = String::isEmpty; Runnable r = () -> { System.out.println(“Boo!”) };
  • 15. Functional Interfaces •  “Just add function types” was obvious … and wrong •  Would have introduced complexity and corner cases •  Would have bifurcated libraries into “old” and “new” styles •  Would have created interoperability challenges •  Preserve the Core •  Stodgy old approach may be better than shiny new one •  Bonus: existing libraries are now forward-compatible to lambdas •  Libraries that never imagined lambdas still work with them! •  Maintains significant investment in existing libraries •  Fewer new concepts
  • 16. Problem – Interface Evolution •  Example used a new Collection method – forEach() •  I thought you couldn’t add new methods to interfaces? •  Interfaces are a double-edged 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())
  • 17. Interface Evolution •  Libraries need to evolve, or they stagnate •  Need a mechanism for compatibly evolving APIs •  New feature: default methods •  Virtual interface method with default implementation •  “default” is the dual of “abstract” •  Three simple rules for resolving inheritance conflicts •  Superclasses win over superinterfaces •  More specific interfaces win over less specific •  After that, concrete classes must override interface Collection<T> { default void forEach(Block<T> action) { for (T t : this) action.apply(t); } }
  • 18. Default Methods •  Similar to, but different from, C# extension methods •  Java’s default methods are virtual and declaration-site •  Core principle: API owners should control their APIs •  Primary goal is API evolution •  Inheritance rules directed at this primary goal •  But very useful as an inheritance mechanism on its own! •  Wait, is this multiple inheritance in Java? •  Java always had multiple inheritance of types •  This adds multiple inheritance of behavior •  But not of state, where most of the trouble comes from
  • 19. It’s All About The Libraries •  Generally, we prefer to evolve the programming model through libraries •  Time to market – can evolve libraries faster than language •  Decentralized – more library developers than language developers •  Risk – easier to change libraries, more practical to experiment •  Impact – language changes require coordinated changes to multiple compilers, IDEs, and other tools •  Sometimes we reach the limits of what is practical to express in libraries, and need a little help from the language •  A little help, in the right places, can go a long way!
  • 20. Lambdas Enable Better APIs •  Lambda expressions enable more powerful APIs •  Boundary between client and library is more permeable •  Client provides bits of behavior to be mixed into execution (“what”) •  Library remains in control of the computation (“how”) •  Safer, exposes more opportunities for optimization •  Key effect on APIs is: more composability •  Leads to better factoring, more regular client code, more reuse •  Lambdas in the language → can write better libraries → more readable, less error-prone user code
  • 21. Example – Sorting •  Default methods can enhance composability •  Comparator.reverse(), Comparator.compose() •  Default methods offer a “right place” to put certain code interface Comparator<T> { int compare(T o1, T o2); default Comparator<T> reverse() { return (o1, o2) -> –(compare(o1, o2)); } default Comparator<T> compose(Comparator<T> other) { return (o1, o2) -> { int cmp = compare(o1, o2); return (cmp != 0) ? cmp : other.compare(o1, o2); } } } Comparator<Person> byFirst = ... Comparator<Person> byLast = ... Comparator<Person> byFirstLast = byFirst.compose(byLast); Comparator<Person> byLastDescending = byLast.reverse();
  • 22. Example – Sorting •  If we want to sort a List today, we write a Comparator •  Many layers of nastiness here! •  Conflates extraction of sort key with ordering of that key •  Collections class required for helper methods •  Syntactically verbose •  Could replace with a lambda, but only gets us so far •  Better to untangle the intertwined aspects •  Fewer opportunities for reuse Collections.sort(people, new Comparator<Person>() { public int compare(Person x, Person y) { return x.getLastName().compareTo(y.getLastName()); } });
  • 23. Example – Sorting •  Lambdas encourage finer-grained APIs •  We add a method that takes a “key extractor” and returns Comparator •  The comparing() method is one built for lambdas •  Higher-order function •  Eliminates redundancy, boilerplate Comparator<Person> byLastName = Comparators.comparing(p -> p.getLastName()); Class Comparators { public static<T, U extends Comparable<? super U>> Comparator<T> comparing(Mapper<T, U> m) { return (x, y) -> m.map(x).compareTo(m.map(y)); } }
  • 24. Example – Sorting Comparator<Person> byLastName = Comparators.comparing(p -> p.getLastName()); Collections.sort(people, byLastName); Collections.sort(people, comparing(p -> p.getLastName()); people.sort(comparing(p -> p.getLastName()); people.sort(comparing(Person::getLastName)); people.sort(comparing(Person::getLastName).reverse()); people.sort(comparing(Person::getLastName) .compose(comparing(Person::getFirstName)));
  • 25. Bulk operations on Collections •  Compute sum of weights of blue shapes •  Compose compound operations from basic building blocks •  Each stage does one thing •  Client code reads more like the problem statement •  Structure of client code is less brittle •  Less extraneous “noise” from intermediate results •  No “garbage variables” •  Library can use parallelism, out-of-order, laziness for performance int sumOfWeight = shapes.stream() .filter(s -> s.getColor() == BLUE) .map(s -> s.getWeight()) .sum(); int sumOfWeight = shapes.stream() .filter(s -> s.getColor() == BLUE) .map(Shape::getWeight) .sum();
  • 26. Streams •  To add bulk operations, we create a new abstraction, Stream (in package java.util.stream) •  Key new library abstraction for JSR-335 •  Represents a stream of values •  Not a data structure – doesn’t store the values •  Source can be a Collection, array, generating function, IO •  Encourages a “fluent” usage style •  Supports operations like filter(), map(), reduce() •  Retrofit stream() method on Collection •  As well as: Reader.lines(), Random.ints(), String.chars(), etc •  Easy to adapt any aggregate to be a Stream source
  • 27. Streams •  What does this code do? Set<Group> groups = new HashSet<>(); for (Person p : people) { if (p.getAge() >= 65) groups.add(p.getGroup()); } List<Group> sorted = new ArrayList<>(groups); Collections.sort(sorted, new Comparator<Group>() { public int compare(Group a, Group b) { return Integer.compare(a.getSize(), b.getSize()) } }); for (Group g : sorted) System.out.println(g.getName()); people.stream() .filter(p -> p.getAge() > 65) .map(p -> p.getGroup()) .removeDuplicates() .sorted(comparing(g -> g.getSize()) .forEach(g -> System.out.println(g.getName());
  • 28. Parallelism •  Goal: easy-to-use parallel libraries for Java •  Libraries can hide a host of complex concerns (task scheduling, thread management, load balancing) •  Goal: reduce conceptual and syntactic gap between serial and parallel expressions of the same computation •  Right now, the serial code and the parallel code for a given computation don’t look anything like each other •  Fork-join (added in Java SE 7) is a good start, but not enough •  Goal: parallelism should be explicit, but unobtrusive
  • 29. Fork/Join Parallelism •  JDK7 added general-purpose 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
  • 30. Parallel Sum with Fork/Join class SumProblem { final List<Shape> shapes; final int size; SumProblem(List<Shape> ls) { this.shapes = ls; size = ls.size(); } public int solveSequentially() { int sum = 0; for (Shape s : shapes) { if (s.getColor() == BLUE) sum += s.getWeight(); } return sum; } public SumProblem subproblem(int start, int end) { return new SumProblem(shapes.subList(start, end)); } } ForkJoinExecutor pool = new ForkJoinPool(nThreads); SumProblem finder = new SumProblem(problem); pool.invoke(finder); class SumFinder extends RecursiveAction { private final SumProblem problem; int sum; protected void compute() { if (problem.size < THRESHOLD) sum = problem.solveSequentially(); else { int m = problem.size / 2; SumFinder left, right; left = new SumFinder(problem.subproblem(0, m)) right = new SumFinder(problem.subproblem(m, problem.size)); forkJoin(left, right); sum = left.sum + right.sum; } } }
  • 31. Parallel Sum with Streams •  Explicit but unobtrusive parallelism •  All three operations fused into a single parallel pass •  Works with ordinary, non-thread-safe collections •  Extensible mechanism to work with any bulk container int sumOfWeight = shapes.stream() .filter(s -> s.getColor() == BLUE) .map(s -> s.getWeight()) .sum(); int sumOfWeight = shapes.stream() .filter(s -> s.getColor() == BLUE) .map(Shape::getWeight) .sum(); int sumOfWeight = shapes.parallelStream() .filter(s -> s.getColor() == BLUE) .map(Shape::getWeight) .sum();
  • 32. So … Why Lambda? •  It’s about time! •  Java is the lone holdout among mainstream OO languages at this point to not have closures •  Adding closures to Java is no longer a radical idea •  Provide libraries a path to multicore •  Parallel-friendly APIs need internal iteration •  Internal iteration needs a concise code-as-data mechanism •  Empower library developers •  More powerful, flexible libraries •  Higher degree of cooperation between libraries and client code •  Encourage better idioms •  Gentle push towards a more functional style of programming
  • 33. <Insert Picture Here> JSR-335 Update Lambda expressions for the Java Language Brian Goetz Java Language Architect Oracle Corporation