You are on page 1of 43

Lambda in Java

Olena Syrota, Kyiv Pre-production Java Lab Lead

Java 8
Issue is planned for summer of 2013 Java 8 will contain the most significant changes and innovation in Java
lambda (closures) Interface evolution (default methods) Evolution of Collections library (bulk operations) Simplified syntax of parallel computation with libraries

How to try it
OpenJDK 8

Times change
1995 (when Java was born)
No support of lambda in most popular languages

Today:
++ has lambda C# has lambda Any new language has lambda

Lambda-calculus
Mathematical definition of mapping (function)
square : REAL REAL "+": [REAL REAL] REAL

Lambda calculus introduces definition of function:


square x: REAL | x * x
means apply function (square) to argument (x) This expression has function body This expression has return type Other function may be arguments (x)
Definition of function for computation

Anonymous form x x*x

Until Java 8 anonymous classes were used

Anonymous class example


interface ActionListener { void actionPerformed(ActionEvent a); } public class Controller { public init() { button.addActionListener( new ActionListener() { public void actionPerfored(ActionEvent e) { // do something. } }); }

Anonymous class example


interface Runnable { void run(); }

Thread t = new Thread (new Runnable() { void run () { System.out.println("hello"); } }); t.start();

What is lambda-expression
Lambda-expression is anonymous method with arguments and body Example
(Object o) -> o.toString() s -> s.length()

(int x, int y) -> x+y


() -> 42 (x, y, z) -> { if (z) return x; else return y; }

How to invoke lambda-expression


Intuitively it is expected something like this
{ int x -> x + 1 }.invoke(10)

int sum = { int x, int y -> x + y }.invoke(3, 4);

Wrong, in Java 8 it is done in other way

How to invoke lambda-expression in Java


Via functional interface Functional interface interface with one method Invoke lambda-expression means to instantiate functional interface Functional interface example:
interface Runnable { void run(); }

Example of lambda-expression invoking


Runnable r = () -> { System.out.println("hello"); }; Thread t = new Thread (r); t.start();

Functional interface examples


Functional interface
interface ActionListener { void onEvent(Event e); }

Instantiate lambda-expression and pass to function:


ActionListener listenr = e -> System.out.println(e.getWhen()); button.addActionListener(listener);

Short syntax:
button.addActionListener(e -> System.out.println(e.getWhen()));

Functional interface examples


Functional interface interface Sum { int sum(int x, int y); } Instantiate lambda-expression: Sum sm = (x, y)-> x+y;

Invoke lambda-expression: int z = sm.sum(2, 3);

Code as data
Code (behavior) may be passed as an argument
List<String> list = new ArrayList<String>(); list.add("first"); list.add("second"); list.add("third"); list.forEach((String s)->{System.out.println(s);});

What is good in lambda


Control is transferred from client to library No need to change language library can be changed

See examples on next slides

External iteration
for (Shape s: shapes) { if (s.getColor() == RED) s.setColor(BLUE); } Client control iteration - external iteration Sequential iteration In this code - what and how
When client controls iteration

Internal iteration
shapes.forEach(s->{ if (s.getColor() == RED) s.setColor(BLUE); }); Iteration controlled by library More what, less how Library can use
parallelism custom order of iterating lazy calculation
When iteration is controlled by iterator

Interface evolution
Interface Collection has new method forEach interface Collection<T> { forEach(Block<T> action) default { for (T t: this) { Default method new feature of action.apply(t); language. } Virtual method can have default implementation. } This allows to transfer control } over iteration to library. Block<T>, Predicate<T> - functional interface from Java 8

Multiple inheritance?
Dafault-methods allow to add behavior to interface (not state) Is this multiple inheritance?
Java has multiple type inheritance Java will have multiple behavior inheritance No multiple inheritance of state. Ever.

There are resolution rules for multiple behavior inheritance

Resolution rules for multiple behavior inheritance


Prefer superclass methods to interface methods Prefer more specific interface to less If conflict, concrete class must provide implementation

Conflict resolution example


interface A { String foo() default {return "A";} } interface B { String foo() default {return "B";} } interface C1 extends A, B { } // compile error

interface C2 extends A, B { // ok String foo() default { return A.super.foo();} }

Collection, default-methods
With lambda Java Collection Framework became stale. It needed to change. Interface Collection has new methods:
forEach removeAll retailAll
interface Collection<T> { forEach(Block<T> action) default { for (T t: this) { action.apply(t); } }

You can replace implementation in subclasses.


} }

boolean removeAll default ( Predicate <? Super T> filter) { boolean removed = false; Iterator<E> each = this.iterator(); while(each.hasNext()) { if(filter.test(each.next())) { each.remove(); removed = true; } } return removed;

Bulk operations on Collections


operations:
filter map into

Bulk operations on Collections (cont.)


Example with Shapes lets apply lambda
shapes.forEach(s-> { if (s.getColor() == RED) s.setColor(BLUE); }
shapes.filter(s->s.getColor()==RED) .forEach(s->{s.setColor(BLUE);});

Bulk operations on Collections (cont.)


Select blue shapes to list List<Shapes> blueBlocks = shapes.filter(s->s.getColor()==RED) .into(new ArrayList()); Let every shape to be in container (Box). Select those containers that contain blue shapes Set<Box> hasBlueBlock = shapes.filter(s->s.getColor()==RED) .map (s->s.getContainer()) .into(new HashSet<Box> ());

Bulk operations on Collections (cont.)


Calculate sum of blue shape weight int sumOfWeight = shapes .filter(s->s.getColor()==BLUE) .map(s->getWeight()) .sum();

Advantages of bulk operations


We can build complex operation from simple blocks of code Readable code More what, less how Libraries can apply
parallelism, Custom order iteration, laziness

Iterable
collection.filter(f->f.isBlue()) .map (f->g.getContainer()) .foreach(s->System.out.println(s))

Lambda-style Interface Iterable was widen Java-style


Iterable<Foo> fooIter = collection; Iterable<Foo> filtered = fooIter.filter(f->f.isBlue()); Iterable<Foo> mapped = filtered.map(f->g.getContainer()); mapped.forEach(s->System.out.println(s));

It is possible to pass behavior to these methods because of functional interfaces Predicate<T>, Mapper <T,U>, Block<T> defined in Java 8

Predicate
public interface Predicate<T> { boolean test(T t);

Predicate<T> and(Predicate<? super T> p) default { return t -> this.test(t) && p.test(t); }
Predicate<T> negate() default { return t -> !this.test(t); } Predicate<T> or(Predicate<? super T> p) default { return t -> this.test(t) || p.test(t); } Predicate<T> xor(Predicate<? super T> p) default { return t -> this.test(t) ^ p.test(t); }

Code outlined schematically, see JDK 8

Mapper
public interface Mapper<T, U> { U map(T t); public <V> Mapper<T, V> compose( Mapper<? super U, ? extends V> after) default { return Mappers.chain(this, after); } }

Block
public interface Block<T> { void apply(T t); }

Example of Predicate functional interface and default-methods


Predicate<String> pr1 = f -> f==null; Predicate<String> pr2 = f -> f.isEmpty();

List<String> list = new ArrayList<String>(); // ... add elements to list List<String> listRes = new ArrayList<String>(); list.filter(pr1.or(pr2).negate()) .into(listRes);

Task filter non-empty strings with complex predicate.

Iterable (cont.)
filter map forEach into sorted aggregate (eg. max, sum ) groupBy mapReduce

Example
Select author, sum(pages) from documents group by author
Map<String, Integer> map = new HashMap(); for (Document d: document) { String author = d.getAuthor(); Integer sum = map.get(author); if (sum==null) sum=0; map.put(author, sum+d.getPageCount()); } Map <String, Integer> map = documents.aggregateBy(d->d.getAuthor(), ()->0, (sum, d) ->sum+d.getPageCount());

Method Reference ::
Method reference :: introduced both for static and instance methods Facility to convert from one interface to another
Task t = () -> System.out.println("hi"); Runnable r = t::invoke;

Equivalent
Runnable r1 = System.out::println; Runnable r2 = () -> { System.out.println(); }

Parallelism
Libraries can hide syntactic and semantic complexity of parallelism Code for sequential and parallel execution should be more similar in syntax
At this moment syntaxes are completely different Code for sequential execution looks very simple Code for parallel execution looks supercompex the complexity of code hides semantic of what we want to calculate

Example
int sumOfWeight = shapes .parallel() .filter(s->s.getColor()==BLUE) .map(s->getWeight()) .sum();

Lambda advantages
Lambda helps to develop more expressive API Delegate to library to control infrastructure flow
Analogy like inversion of control between client code and library

More possibilities for optimization More readable code

Sorting (Java-style)
Collections.sort(list, new Comparator() { public int compare(Person x, Person y) return x.getLastName().compareTo(y.getLastName()); })

Default-methods - Combinators
public interface Comparator<T> { int compare (T o1, T o2);

Reversing of comparison order

Comparator<T> reverse () default { Combining return (o1, o2)->compare (o2, o1); comparison } functions Comparator<T> compose (Comparator<T> other) default { 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> byLastDesc = byLast.reverse();

Sorting with lambda


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)); }

Usage: Comparator<Person> byLastName = Comparators.comparing(p->p.getLastName()); Collections.sort(people, byLastName);

people.sort(Comparators.comparing(p->p.getLastName())) people.sort(Comparators.comparing(p->p.getLastName()).reverse())

What had been solved to introduce lambda in Java


What is the type of lambda-expressions in Java?
No functional type in Java

How to represent lambda in bytecode?


No functional type presentation in method signature in JVM

JVM translation
http://cr.openjdk.java.net/~briangoetz/lambda/la mbda-translation.html

Bibliography
http://tronicek.blogspot.com/2007/12/closur es-closure-is-form-of-anonymous_28.html Brian Goetz, The Road to Lambda, https://oracleus.activeevents.com/connect/se ssionDetail.ww?SESSION_ID=4862 http://www.jcp.org/en/jsr/summary?id=335 http://cr.openjdk.java.net/~briangoetz/lambd a/lambda-translation.html

You might also like