Я пытался вписать лямбда-выражения в код, который я пишу, и этот простой пример является следствием того же самого. Для тех, кто не знает о лямбда-выражениях в Java, я бы порекомендовал им сначала прочитать это, прежде чем приступать к этой статье.
Хорошо, теперь, когда вы знакомы с лямбда-выражениями (после прочтения вводного поста), давайте перейдем к простому примеру, который я считаю хорошим использованием лямбда-выражений.
Рассмотрим следующий сценарий: определенная операция окружена некоторой предварительной обработкой и некоторой последующей обработкой. И выполняемая операция может варьироваться в зависимости от
ожидаемое поведение. Код предварительной обработки извлекает необходимые параметры для операции, а последующая обработка выполняет необходимую очистку.
Давайте посмотрим, как это можно сделать с использованием интерфейсов и их реализаций через классы Anonymous Inner.
Использование анонимных внутренних классов
Интерфейс, который должен быть реализован для обеспечения требуемого поведения:
1
2
3
|
interface OldPerformer { public void performTask(String id, int status); } |
И давайте посмотрим на метод, который выполняет предварительную обработку, выполняет требуемую операцию и затем последующую обработку:
1
2
3
4
5
6
7
8
9
|
public class PrePostDemo { static void performTask(String id, OldPerformer performer) { System.out.println( "Pre-Processing..." ); System.out.println( "Fetching the status for id: " + id); int status = 3 ; //Some status value fetched performer.performTask(id, status); System.out.println( "Post-processing..." ); } } |
Нам нужно передать 2 вещи — идентификатор для выполнения предварительной обработки и реализацию операции, что можно сделать, как показано ниже:
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 PrePostDemo { public static void main(String[] args) { //has to be declared final to be accessed within //the anonymous inner class. final String outsideOfImpl = "Common Value" ; performTask( "1234" , new OldPerformer() { @Override public void performTask(String id, int status) { System.out.println( "Finding data based on id..." ); System.out.println(outsideOfImpl); System.out.println( "Asserting that the status matches" ); } }); performTask( "4567" , new OldPerformer() { @Override public void performTask(String id, int status) { System.out.println( "Finding data based on id..." ); System.out.println(outsideOfImpl); System.out.println( "Update status of the data found" ); } }); } } |
Как видно выше, переменные, объявленные вне внутреннего класса Anonymous, должны быть объявлены как final, чтобы они были доступны в методах внутреннего анонимного класса. Вывод приведенного выше кода будет:
01
02
03
04
05
06
07
08
09
10
11
12
|
Pre-Processing... Fetching the status for id : 1234 Finding data based on id ... Common Value Asserting that the status matches Post-processing... Pre-Processing... Fetching the status for id : 4567 Finding data based on id ... Common Value Update the status of the data found Post-processing... |
Использование лямбда-выражения
Давайте посмотрим, как написанное выше можно написать с помощью лямбда-выражения:
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
|
public class PrePostLambdaDemo { public static void main(String[] args) { //Need not be declared as final for use within a //lambda expression, but has to be eventually final. String outsideOfImpl = "Common Value" ; doSomeProcessing( "123" , (String id, int status) -> { System.out.println( "Finding some data based on" +id); System.out.println(outsideOfImpl); System.out.println( "Assert that the status is " +status ); }); doSomeProcessing( "456" , (String id, int status) -> { System.out.print( "Finding data based on id: " +id); System.out.println(outsideOfImpl); System.out.println( "And updating the status: " +status); }); } static void doSomeProcessing(String id, Performer performer ){ System.out.println( "Pre-Processing..." ); System.out.println( "Finding status for given id: " +id); int status = 2 ; performer.performTask(id, status); System.out.println( "Post-processing..." ); } } interface Performer{ public void performTask(String id, int status); } |
Помимо интересного синтаксиса лямбда-выражения, переменная вне области лямбда-выражения не объявляется как окончательная. Но он должен быть в конечном итоге окончательным, что означает, что значение переменной: outsideOfImpl не должно изменяться после объявления.
Это еще один более чистый способ использования лямбда-выражения вместо внутренних классов Anonymous.
Напутствие: выпуск релиза JDK 8 перенесен на февраль 2014 года, а полное расписание можно найти здесь . Я использую лямбда-сборку Project, которая обновляется каждый день, поэтому не стесняйтесь сообщать мне, если что-то из этого не работает в последних сборках. Я буду стараться обновлять сборки и пробовать образцы, размещенные здесь.
Еще одно замечание: не волнуйтесь о том, что происходит в Java 8, эти функции уже являются частью многих языков программирования. Я обнаружил, что изучение синтаксиса и подхода лямбда-выражений в Java помогло мне понять и мыслить функционально и более конкретно оценить замыкания Scala.