Java 8 Lambdas

Author: Vassil Dichev
Date: 11.03.2014

Who am I

Java 8 lambdas history

Survey

images/survey3.png

Evolution of paradigms

Functional programming

Java before 1.4

int sum = 0;
for (int i = 0;
     i < employees.length;
     i++) {
  sum += employees[i].getSalary();
}

images/chain.jpg

Enhanced for loop

int sum = 0;
for (Employee employee: employees) {
  sum += employee.getSalary();
}

Enhanced loop decompiled

int sum = 0;
for (Iterator<Employee> iter =
       employees.iterator();
     iter.hasNext();) {
  Employee employee = iter.next();
  sum += employee.getSalary();
}

Internal/External Iteration

images/internal_external_iteration.png

Lambdas

(int x, int y) -> { return x + y; };
(int x, int y) -> { x + y; };
(x, y) -> x + y;
x -> 2 * x;
() -> out.println("hey")

Functional interfaces

interface Runnable {
  void run();
}
interface Callable<V> {
  V call();
}
interface Comparator<T> {
  int compare(T o1, T o2);
}
interface FileFilter {
  boolean accept(File path);
}
interface ActionListener {
  void actionPerformed(ActionEvent e);
}

Concurrent

// Anonymous Runnable
Runnable r1 = new Runnable(){

  @Override
  public void run(){
    out.println("Hello 1!");
  }
};

// Lambda Runnable
Runnable r2 = () -> out.println("Hello 2!");
//            ↓          ↓
//    parameters        body

Method references

Runnable r =
  () -> out.println("Hey!");
Callable<Void> c =
  () -> out.println("Hey!");
class Message {
  static void hey() {
    out.println("Hey");
  }
}
Runnable r = Message::hey;
Callable<Void> c = Message::hey;

Method reference types

GUI

button.addActionListener(new ActionListener(){
  @Override
  public void actionPerformed(ActionEvent ae){
    out.println("Anon Class");
  }
});

button.addActionListener(
    e -> out.println("Lambda Listener"));
//  ↓          ↓
// parameters body

Variable capture

int sum = 0;
employees.stream().
          forEach(e -> sum += e.getSalary());
// COMPILER SAYS NO!

Common patterns

Filter

images/filter.png

Map

images/map.png

Reduce

images/reduce.png

Streams

Loop with streams

employees.stream().
          filter(e -> e.getAge() > 30).
          map(Employee::getSalary).
          reduce(Integer::sum)

Parallel streams

employees.parallelStream().
          filter(e -> e.getAge() > 30).
          map(Employee::getSalary).
          reduce(Integer::sum)

Intermediate methods

Terminal

Default methods

default void sort(Comparator<? super E> c){
  Collections.sort(this, c);
}

Default methods resolution

Scala

List(1, 2, 3).filter(_ % 2 == 0)
List(1, 2, 3).map(_ * 2)
List(1, 2, 3).reduce(_ + _)

Clojure

(filter #(= (mod % 2) 0) '(1 2 3))
(map #(* 2 %) '(1 2 3))
(reduce + '(1 2 3))

Groovy

[1, 2, 3].findAll { it % 2 == 0 }
[1, 2, 3].collect { it * 2}
[1, 2, 3].inject { acc, val -> acc + val }

Ruby/JRuby

[1, 2, 3].select { |num| num.even? }
[1, 2, 3].collect { |num| num * 2 }
[1, 2, 3].inject(:+)

Python/Jython

list(filter(lambda x: x % 2 == 0, [1, 2, 3]))
list(map(lambda x: x * 2, [1, 2, 3]))
reduce(lambda x, y: x + y, [1, 2, 3])

JavaScript

[1, 2, 3].filter(function (el) {
  return el % 2 == 0;
});
[1, 2, 3].map(function (el) {
  return 2 * el;
});
[1, 2, 3].reduce(function (prev, curr) {
  return prev + curr;
});

Where to next?

images/urma_cover150.jpg

Evolution?

Every C# developer should really try #Scala. You won't look back. I promise.

—Erik Meijer