Перейти к основному содержимому

Лямбды как параметры и результаты методов

Лямбды как параметры методов​

Одним из преимуществ лямбд в языке Java является то, что их можно передавать в качестве параметров в методы. Рассмотрим пример:

public class Program {
public static void main(String[] args) {
doOperation(10, 4, (a, b) -> a + b); // 14
doOperation(10, 4, (a, b) -> a - b); // 6
doOperation(10, 4, (a, b) -> a * b); // 40
}

static void doOperation(int a, int b, Operation op) {
System.out.println(op.execute(a, b));
}
}

interface Operation {
int execute(int a, int b);
}

Здесь для представления лямбда-выражений применяется функциональный интерфейс Operation с методом execute(), который принимает два числа, выполняет над ними некоторые вычисления и возвращает число - результат вычислений:

interface Operation {
int execute(int a, int b);
}

В программе определен метод doOperation, который принимает два числа и объект интерфейса Operation - то есть некоторую операцию над двумя числами:

static void doOperation(int a, int b, Operation op) {
System.out.println(op.execute(a, b));
}

То есть на момент определения метода мы точно не знаем, что это будет за операция. Мы только знаем, что она принимает два числа и возвращает число.

В методе main вызываем несколько раз метод doOperation, передавая в него через лямбда-выражения разные операции. При этом можно не определять переменную интерфейса, а сразу передать в метод лямбда-выражение:

doOperation(10, 4, (a, b) -> a + b); // 14
doOperation(10, 4, (a, b) -> a - b); // 6
doOperation(10, 4, (a, b) -> a * b); // 40

Это особенно удобно тем, что нам не надо дополнительно создавать переменную для хранения лямбда-выражения, которое, возможно, использовалось бы один раз. Хотя при необходимости также можно было бы создать переменную интерфейса Operation и передать её в метод.

Другой пример:

public class Program {
public static void main(String[] args) {
Expression func = n -> n % 2 == 0;
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
System.out.println(sum(nums, func)); // 20
}

static int sum(int[] numbers, Expression func)
{
int result = 0;
for (int i : numbers) {
if (func.isEqual(i))
result += i;
}
return result;
}
}

interface Expression {
boolean isEqual(int n);
}

Функциональный интерфейс Expression определяет метод isEqual(), который возвращает true, если в отношении числа n действует какое-нибудь равенство.

В основном классе программы определяется метод sum(), который вычисляет сумму всех элементов массива, соответствующих некоторому условию. А само условие передается через параметр Expression func. Причем на момент написания метода sum мы можем абсолютно не знать, какое именно условие будет использоваться. Само же условие определяется в виде лямбда-выражения:

Expression func = n -> n % 2 == 0;

То есть в данном случае все числа должны быть четными или остаток от их деления на 2 должен быть равен 0. Затем это лямбда-выражение передается в вызов метода sum.

В методе main применяем метод sum, передавая в него лямбда-выражение:

int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int x = sum(nums, n -> n > 5); // сумма чисел, которые больше 5
System.out.println(x); // 30

Лямбды как результат методов​

Также метод в Java может возвращать лямбда-выражение. Рассмотрим следующий пример:

public class Program {
public static void main(String[] args) {
Operation func = action(1);
int a = func.execute(6, 5);
System.out.println(a); // 11

int b = action(2).execute(8, 2);
System.out.println(b); // 6
}

private static Operation action(int number) {
switch (number) {
case 1: return (x, y) -> x + y;
case 2: return (x, y) -> x - y;
case 3: return (x, y) -> x * y;
default: return (x, y) -> 0;
}
}
}

interface Operation {
int execute(int a, int b);
}

В данном случае определен функциональный интерфейс Operation, в котором метод execute принимает два значения типа int и возвращает значение типа int.

Метод action принимает в качестве параметра число и в зависимости от его значения возвращает то или иное лямбда-выражение. Оно может представлять либо сложение, либо вычитание, либо умножение, либо просто возвращает 0. Стоит учитывать, что формально возвращаемым типом метода action является интерфейс Operation, а возвращаемое лямбда-выражение должно соответствовать этому интерфейсу.

В методе main мы можем вызвать этот метод action. Например, сначала получить его результат - лямбда-выражение, которое присваивается переменной Operation. А затем через метод execute выполнить это лямбда-выражение:

Operation func = action(1);
int a = func.execute(6, 5);
System.out.println(a); // 11

Либо можно сразу получить и тут же выполнить лямбда-выражение:

int b = action(2).execute(8, 2);
System.out.println(b); // 6