Статьи

Java 8 лямбда прохождение

Для работы я сделал презентацию о лямбда-проекте Java 8 и, конечно же, о простом коде, иллюстрирующем некоторые моменты. Общие причины для Java 8:

  • Более краткий код (для классов, которые имеют только один метод и коллекции). «Мы хотим, чтобы читатель кода прошел через как можно меньший синтаксис, прежде чем достигнуть« мяса »лямбда-выражения». — Брайан Гетц (http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-4.html)
  • Возможность передавать функциональность, а не только данные
  • Лучшая поддержка многоядерной обработки

Все примеры работают на следующей версии Java 8, загруженной отсюда :

1
2
3
openjdk version "1.8.0-ea"
OpenJDK Runtime Environment (build 1.8.0-ea-lambda-nightly-h3876-20130403-b84-b00)
OpenJDK 64-Bit Server VM (build 25.0-b21, mixed mode)

Самый простой случай:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
public class ThreadA {
 
    public static void main(String[] args) {
 
        new Thread(new Runnable() {
 
            @Override
            public void run() {
                System.err.println("Hello from anonymous class");
            }
        }).start();
 
    }
 
}
01
02
03
04
05
06
07
08
09
10
public class ThreadB {
 
    public static void main(String[] args) {
        new Thread(() -> {
            System.err.println("Hello from lambda");
        }).start();
 
    }
 
}

Обратите внимание на синтаксис, неофициально как

1
()|x|(x,..,z) -> expr|stmt

Стрелка является новым оператором. И обратите внимание на краткость второго фрагмента кода по сравнению с более громоздким первым фрагментом.

Коллекции:

Сначала позвольте мне представить простой домен и несколько помощников

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Something {
 
    private double amount;
 
    public Something(double amount) {
        this.amount = amount;
    }
 
    public double getAmount() {
        return amount;
    }
 
    public String toString() {
        return "Amount: " + amount;
    }
}
 
public class Helper {
 
    public static List<Something> someThings() {
        List<Something> things = new ArrayList<>();
        things.add(new Something(99.9));
        things.add(new Something(199.9));
        things.add(new Something(299.9));
        things.add(new Something(399.9));
        things.add(new Something(1199.9));
        return things;
    }
 
}
 
public interface Doer<T> {
 
    void doSomething(T t);
 
}

Давайте немного отфильтруем и отсортируем стиль Java 7:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class CollectionA {
 
    public static void main(String... args) {
 
        List<Something> things = Helper.someThings();
 
        System.err.println("Filter");
        List<Something> filtered = filter(things);
        System.err.println(filtered);
 
        System.err.println("Sum");
        double sum = sum(filtered);
        System.err.println(sum);
 
    }
 
    public static List<Something> filter(List<Something> things) {
        List<Something> filtered = new ArrayList<>();
        for (Something s : things) {
            if (s.getAmount() > 100.00) {
                if (s.getAmount() < 1000.00) {
                    filtered.add(s);
                }
            }
        }
        return filtered;
    }
 
    public static double sum(List<Something> things) {
        double d = 0.0;
        for (Something s : things) {
            d += s.getAmount();
        }
        return d;
    }
 
}

А теперь стиль Java 8 — потоковое :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
import java.util.stream.Collectors;
 
public class CollectionB {
 
    public static void main(String... args) {
 
        List<Something> things = Helper.someThings();
 
        System.err.println("Filter lambda");
        List<Something> filtered = things.stream().parallel().filter( t -> t.getAmount() > 100.00 && t.getAmount() < 1000.00).collect(Collectors.toList());
        System.err.println(filtered);
 
        System.err.println("Sum lambda");
        double sum = filtered.stream().mapToDouble(t -> t.getAmount()).sum();
        System.err.println(sum);
 
    }
 
}

Импорт java.util.function. * Интерфейсы и ссылки на методы

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class CollectionC {
 
    public static void main(String... args) {
 
        List<Something> things = Helper.someThings();
 
        System.err.println("Do something");
        doSomething(things, new Doer<Something>() {
 
            @Override
            public void doSomething(Something t) {
                System.err.println(t);
            }
        });
    }
 
    public static void doSomething(List<Something> things, Doer<Something> doer) {
        for (Something s : things) {
            doer.doSomething(s);
        }
    }
 
}

Замените наш интерфейс Doer на стандартный интерфейс Consumer (ранее известный как Block)

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import java.util.function.Consumer;
 
public class CollectionD {
 
    public static void main(String... args) {
 
        List<Something> things = Helper.someThings();
 
        System.err.println("Do something functional interfaces");
        consumeSomething(things, new Consumer<Something>() {
 
            @Override
            public void accept(Something t) {
                System.err.println(t);
            }
        });
 
        System.err.println("Do something functional interfaces, using lambda");
        consumeSomething(things, (t) -> System.err.println(t));
 
        System.err.println("Do something functional interfaces, using lambda method reference (new operator ::) ");
        consumeSomething(things, System.err::println);
 
        System.err.println("Do something functional interfaces, using stream");
        things.stream().forEach(new Consumer<Something>() {
 
            @Override
            public void accept(Something t) {
                System.err.println(t);
            }
        });
 
        System.err.println("Do something functional interfaces, using stream and method reference");
        things.stream().forEach(System.err::println);
    }
 
    public static void doSomething(List<Something> things, Doer<Something> doer) {
        for (Something s : things) {
            doer.doSomething(s);
        }
    }
 
    public static void consumeSomething(List<Something> things, Consumer<Something> consumer) {
        for (Something s : things) {
            consumer.accept(s);
        }
    }
 
}

Карта, уменьшить, ленивый и необязательно

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.stream.Collectors;
 
public class Various {
 
    public static void main(String... args) {
 
        List<Something> things = Helper.someThings();
 
        //Map
        System.err.println(things.stream().map((Something t) -> t.getAmount()).collect(Collectors.toList()));
 
        //Reduce
        double d = things.stream().reduce(new Something(0.0), (Something t, Something u) -> new Something(t.getAmount() + u.getAmount())).getAmount();
        System.err.println(d);
 
        //Reduce again
        System.err.println(things.stream().reduce((Something t, Something u) -> new Something(t.getAmount() + u.getAmount())).get());
 
        //Map/reduce
        System.err.println(things.stream().map((Something t) -> t.getAmount()).reduce(0.0, (x, y) -> x + y));
 
        //Lazy
        Optional<Something> findFirst = things.stream().filter(t -> t.getAmount() > 1000).findFirst();
        System.err.println(findFirst.get());
 
        //Lazy no value
        Optional<Something> findFirstNotThere = things.stream().filter(t -> t.getAmount() > 2000).findFirst();
        try {
            System.err.println(findFirstNotThere.get());
        } catch (NoSuchElementException e) {
            System.err.println("Optional was not null, but its value was");
        }
        //Optional one step deeper
        things.stream().filter(t -> t.getAmount() > 1000).findFirst().ifPresent(t -> System.err.println("Here I am"));
 
    }
 
}

Ссылка: Java 8 лямбда-прохождение от нашего партнера JCG