Как известно, лямбда-выражение может быть использовано в любом контексте, предоставляющем его целевой тип.
Один из таких контекстов возникает при передаче лямбда-выражения в качестве аргумента.
В действительностипередача лямбда-выражений в качестве аргументов является весьма распространенным примером их применения.
Более того, это весьма эффективное их применение, поскольку оно дает возможность передать исполняемый код методу в качестве его аргумента.
Благадоря этому значительно повышается выразительная сила Java.
Для передачи лямбда-выражения в качестве аргумента параметр, получающий это выражение в качестве аргумента, должен иметь тип функционального интерфейса, совместимого с этим лямбда-выражением.
Несмотря на всю простоту применения лямбда-выражений в качестве передаваемых аргументов, полезно все же показать, как это происходит на практике.
В следующем примере программы демонстрируется весь этот процесс:
1 2 3 4 5 6 7 8 9 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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
// Передать лямбда-выражение в качестве аргумента методу interface StringFunc { String func(String n); } class LambdaAsArgumentsDemo { // Первый параметр этого метода имеет тип функционального // интерфейса. Следовательно, ему можно передать ссылку на // любой экземпляр этого интерфейса, включая экземпляр, // создаваемый в лямбда-выражении. А второй параметр // обозначает обрабатываемую символьную строку. static String stringOp(StringFunc sf, String s) { return sf.func(s); } public static void main(String args[]) { String inStr = "Лямбда-выражения повышают эффективность Java"; String outStr; System.out.println("Это исходная строка: " + inStr); // Ниже приведено простое лямбда-выражение, преобразующее // в верхний регистр букв все символы исходной строки, // передаваемой методу stringOp() outStr = stringOp((str) -> str.toUpperCase(), inStr); System.out.println("Это строка в верхнем регистре: " + outStr); // А здесь передается блочное лямбда-выражение, удаляющее // пробелы из исходной символьной строки outStr = stringOp((str) -> { String result = ""; int i; for(i = 0; i < str.length(); i++) { if(str.charAt(i) != ' ') { result += str.charAt(i); } } return result; }, inStr); System.out.println("Это строка с удаленными пробелами: " + outStr); // Конечно, можно передать и экземпляр интерфейса StringFunc, // созданный в предыдущем лямбда-выражении. Например, после // следующего объявления ссылка reverse делается на экземпляр // интерфейса StringFunc StringFunc reverse = (str) -> { String result = ""; int i; for(i = str.length() - 1; i >= 0; i--) { result += str.charAt(i); } return result; }; // А теперь ссылку reverse можно передать в качестве первого // параметра методу stringOp() // поскольку оно ссылается на объект StringFunc System.out.println("Это обращенная строка: " + stringOp(reverse, inStr)); } } |
Ниже приведен результат выполнения данной программы:
1 2 3 4 5 6 7 |
pro-java.ru@admin:~$ javac lambdarg.java pro-java.ru@admin:~$ java LambdaAsArgumentsDemo Это исходная строка: Лямбда-выражения повышают эффективность Java Это строка в верхнем регистре: ЛЯМБДА-ВЫРАЖЕНИЯ ПОВЫШАЮТ ЭФФЕКТИВНОСТЬ JAVA Это строка с удаленными пробелами: Лямбда-выраженияповышаютэффективностьJava Это обращенная строка: avaJ ьтсонвиткеффэ тюашывоп яинежарыв-адбмяЛ pro-java.ru@admin:~$ |
Прежде всего обратите внимание в данном примере программы на метод stringOp(), у которого имеются два параметра.
Первый параметр относитсяк типу StringFunc, т.е. к функциональному интерфейсу. Следовательно, этот параметр может получать ссылку на любой экземпляр функционального интерфейса StringFunc, в том числе и создаваемый в лямбда-выражении.
А второй параметр метода, stringOp(), относится к типу String и обозначает обрабатываемую символьную строку.
Затем обратите внимание на первый вызов метода stringOp():
1 |
outStr = stringOp((str) -> str.toUpperCase(), inStr); |
где в качестве аргумента данному методу передается простое лямбда-выражение. При этом создается экземпляр функционального интерфейса StringFunc и ссылка на данный объект передается первому параметру метода stringOp().
Таким образом, код лямбда-выражения, встраиваемый в экземпляр класса, передается данному методу. Контекст целевого типа лямбда-выражения определяется типом его параметра.
А поскольку лямбда-выражение совместимо с этим типом, то рассматриваемый здесь вызов достоверен.
Встраивать в метод такие простые лямбдав-ыражения, как упомянутое выше, нередко оказывается очень удобно, особенно когда лямбда-выражение предназначается для однократного употребления.
Далее в рассматриваемом здесь примере программы методу stringOp() передается блочное лямбда-выражение.
Оно удаляет пробелы из исходной символьной строки и еще раз показано ниже.
1 2 3 4 5 6 7 8 9 10 11 12 |
outStr = stringOp((str) -> { String result = ""; int i; for(i = 0; i < str.length(); i++) { if(str.charAt(i) != ' ') { result += str.charAt(i); } } return result; }, inStr); |
И хотя здесь указывается блочное лямбда-выражение, описанный выше процесс передачи лямбда-выражения остается тем же самым и для простого одиночного лямбда-выражения.
Но в данном случае некоторым программистам синтаксис может показаться несколько неуклюжим.
Если блочное выражение кажется слишком длинным для встраивания в вызов метода, то его можно просто присвоить переменной ссылки на функциональный интерфейс, как это делалось в предыдущих примерах.
И тогда остается только передать эту ссылку вызываемому методу. Такой прием показан в конце рассматриваемого здесь примера программы, где определяется блочное лямбда-выражение изменяющее порядок следования символов в строке на обратный.
Это лямбда-выражение присваивается переменной reverse, ссылающейся на функциональны йинтерфейс StringFunc.
Следовательно, переменную reverse можно передатьв качестве аргумента первому параметру метода stringOp().
Именно так и делается в конце данной программы, где методу stringOp() передаются переменная reverse и обрабатываемая символьная строка.
Экземпляр, получаемый в результате вычисления каждого лямбда-выражения, является реализацией функционального интерфейса StringFunc, поэтому каждое из этих выражений может быть передано в качестве первого аргумента вызываемому методу stringOp().
И последнее замечание: помимо инициализации переменных, присваиванияи передачи аргументов, следующие операции образуют контекст целевого типа лямбда-выражений: приведение типов, тернарная операция ?, инициализация массивов, операторы return, а также сами лямбда-выражения.