Недавно я прочитал « Состояние лямбды» Брайана Гетца, и после прочтения этой статьи я хотел попробовать использовать лямбда-выражения Java 8. В своей статье Брайан продолжает описывать интерфейсы, которые имеют один метод, как «функциональные» интерфейсы. Функциональные интерфейсы почти всегда используются в качестве анонимных классов, причем каноническим примером является ActionListener. Эти «функциональные» интерфейсы являются исходной целью для лямбда-выражений, главной целью которых является удаление большей части шаблонного или церемония вокруг их использования. Когда я писал серию статей для библиотеки Guava, интерфейс Function сразу же пришел мне на ум в качестве основного кандидата для использования лямбда-выражений.
Моя цель проста: взять модульный тест из моего блога Guava Futures (он интенсивно использует интерфейс Function) и преобразовать его в лямбда-выражения. Хотя я опишу структуру выражения lamba, поскольку оно относится к представленному примеру, этот пост не является руководством по лямбда-выражениям Java 8. Скорее это документирует мои первые попытки использования лямбда-выражений в Java.
Лямбда-выражения
Первый пример — тест для метода Futures.chain, который принимает функцию в качестве одного из аргументов:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
 | 
Function<List<String>, ListenableFuture<List<Person>>> queryFunction =      new Function<List<String>, ListenableFuture<List<Person>>>() {            @Override            public ListenableFuture<List<Person>> apply(final List<String> ids) {                 return dbService.getPersonsByIdAsync(ids);            }        };ListenableFuture<List<String>> indexSearch =       luceneSearcher.searchAsync('firstName:martin');ListenableFuture<List<Person>> results =       Futures.chain(indexSearch,queryFunction,executorService); | 
Используя выражения lamba, теперь это будет выглядеть так:
| 
 1 
2 
3 
4 
5 
6 
7 
 | 
Function<List<String>, ListenableFuture<List<Person>>> queryFunction =      ids ->(dbService.getPersonsByIdAsync(ids));  ListenableFuture<List<String>> indexSearch =       luceneSearcher.searchAsync('firstName:martin');  ListenableFuture<List<Person>>results =       Futures.chain(indexSearch, queryFunction,executorService); | 
Имейте в виду, что из приведенных выше примеров кода два выделенных раздела эквивалентны. Давайте посмотрим на строку 2 и объясним, как это совпадает со строками 1-7 из первого примера кода.
-  
ids— это входные данные для метода apply и соответствуетfinal List<String> idsпараметруfinal List<String> idsв строке 4 в первом примере кода. Типы выражения lamba выводятся из контекста, в котором оно используется, поэтому нам не нужно повторять их для параметраids. - Затем есть маркер стрелки (->), который является частью общего синтаксиса лямбда-выражений Java 8 в их текущей форме.
 - Затем у нас есть тело лямбды (dbService.getPersonsByIdAsync (ids)), которое является вызовом метода, который возвращает ListenableFuture, который в свою очередь выдает объекты List of Person. Обратите внимание, что нам не нужно было помещать оператор return, так как это одно выражение, которое вычисляется и возвращается.
 
Следующий пример — это служебный метод из теста, который возвратил ListenableFutures, передав анонимные экземпляры Callable в ExecutorService:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
 | 
private ListenableFuture<List<Person>> getPersonsByFirstNameFuture(final String firstName, final boolean error) {return executorService.submit(new Callable<List<Person>>() {            @Override            public List<Person> call() throws Exception {                startSignal.await();                if (error) {                    throw new RuntimeException('Ooops!');                }                List<String> ids = luceneSearcher.search('firstName:' + firstName);                return dbService.getPersonsById(ids);            }        });} | 
А вот эквивалент с использованием лямбда-выражения:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
private ListenableFuture<List<Person>> getPersonsByFirstNameFuture(final String firstName, final boolean error) { return executorService.submit(() -> {startSignal.await();                                       if (error) {                                        throw new RuntimeException('Ooops!');                                       }                                     List<String> ids = luceneSearcher.search('firstName:' + firstName);                                     return dbService.getPersonsById(ids);                                  });} | 
В этом примере нет входных аргументов, поэтому выражение начинается с пустых скобок () в строке 2. Существует токен ->, но в этом примере тело содержит несколько операторов, окруженных {…}. Поскольку существует несколько операторов, в строке 7 требуется явный оператор возврата.
Среда для запуска Java 8
Мой текущий ноутбук — MacBook Pro, поэтому мне нужно было настроить среду для запуска Java 8 с поддержкой лямбды. Вот шаги, которые я предпринял:
- Установил LinuxMint 12 на VirtualBox.
 - Создал каталог и поделился им с гостем LinuxMint
 - Установленный разработчиком предварительный просмотр java 8.
 -   Чтобы получить исходный код и исходный текст теста из существующего проекта maven, я запустил 
mvn jar:jar jar:test-jarи поместил полученные файлы jar в общую директорию - Поместил все зависимости в общий каталог (guava, lucene, h2 и junit)
 - Переписал модульный тест для использования лямбд и запустил новый тест из командной строки
 
Вывод
Хотя до выхода Java 8 с поддержкой лямбды пройдет некоторое время, то, что доступно в предварительной версии для разработчиков, выглядит многообещающе. Спасибо за ваше время и, как всегда, приветствуются комментарии и предложения.
Ресурсы
- Состояние лямбда, часть 4
 - Предварительный просмотр разработчика Java 8
 - Исходный код этого поста
 - Гуава Проект Главная
 - Исходный код для серии блогов Guava
 
Справка: функции Guava и Java 8 Lambdas от нашего партнера по JCG Билла Бекака в блоге Randomечет о кодировании .
