Введение в лямбда
Lambda, иначе функциональное программирование, Википедия дает следующее введение:
Функциональное программирование — это парадигма программирования. Он рассматривает вычисления как оценку математических функций, избегая, таким образом, изменения состояния и использования изменяемых данных. Это парадигма декларативного программирования, программирование с помощью выражений и объявлений, а не операторов.
Лямбда-выражение названо в честь лямбда-исчисления в математике, что напрямую соответствует лямбда-абстракции, это анонимная функция, то есть функция без имени функции. Лямбда-выражения могут представлять замыкания (обратите внимание, что это отличается от традиционного математического смысла).
λ-исчисление — это формальная система математической логики, которая использует связывание переменных и замену для выражения вычислений на основе функциональной абстракции и приложения. Обсуждение λ-исчисления неотделимо от формальных выражений. В этой статье мы попытаемся сосредоточиться на основных понятиях, связанных с программированием, а не на формальном представлении математики. λ-исчисление на самом деле является упрощением ранее упомянутой концепции функций, что облегчает систематическое изучение функций.
Лямбды в Java
С появлением Java 8 это означает, что java теперь также поддерживает синтаксис лямбда, так что предыдущие утомительные операции могут быть заменены простым синтаксисом.Наиболее репрезентативной реформой является новый класс Stream.Сортировка, фильтрация, сопоставление и сбор только стало легче!
Составляем сценарий.Для заданного массива int отфильтровываем отрицательные числа и сортируем оставшиеся элементы.До java8 нашу реализацию нужно было писать так:
int[] array = {7, -2, 3, 5, -9, 3, -5, -1, 6, 8, 20};
List<Integer> list = new ArrayList<Integer>();
//过滤负数
for(int i: array) {
if(i >= 0) list.add(i);
}
//排序
Collections.sort(list);
for(int i: list) {
System.out.println(i);
}
После использования потока:
int[] array = {7, -2, 3, 5, -9, 3, -5, -1, 6, 8, 20};
Arrays.stream(array)
.filter(a -> a >= 0) //过滤
.sorted() //排序
.forEach(System.out::println);
Видно, что процесс реализации стал более лаконичным и элегантным, лямбда-выражение значительно экономит место в коде и улучшает его читаемость, но при этом возрастает и сложность использования.Для традиционных методов программирования синтаксис лямбда, несомненно, оказывает большое влияние.
Использование синтаксиса Lambda в Java
функциональный интерфейс
чтофункциональный интерфейсШерстяная ткань? До Java 8 мы хотели реализовать интерфейс, самый простой способ напрямую использовать анонимные классы:
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 > o2 ? 1 : -1;
}
};
Здесь следует отметить, что Comparator является типом интерфейса, и у него есть только один метод, который необходимо реализовать, поэтому мы называем его функциональным интерфейсом, а общий функциональный интерфейс добавит@FunctionalInterface
Обратите внимание, если в интерфейсе будет реализовано более двух методов, ваша IDE напомнит вам, что это не канонический функциональный интерфейс.Для тех, которые соответствуют, мы можем использовать лямбда-синтаксис для инициализации:
Comparator<Integer> comparator = (o1, o2) -> o1 > o2 ? 1 : -1;
Сравнивая его с реализацией до java8, мы находим много общего.Давайте проанализируем реализацию лямбды:
(o1, o2) -> o1 > o2 ? 1 : -1;
заменить вышеуказанную часть на->
Проведите разделительную линию и разделите ее на две части, они(o1, o2)
иo1 > o2 ? 1 : -1
. Очевидно, что первый представляет собой два входных параметра функции, а второй представляет собой логическую реализацию двух входных параметров.Из этого видно, что лямбда состоит из двух частей:入参定义
и逻辑实现
.
Для функционального интерфейса мы можем использовать простой синтаксис лямбда для реализации единственного метода, который должен быть реализован в интерфейсе.И наоборот, для стиля определения анонимной функции лямбда, если интерфейс имеет два метода для реализации, лямбда невозможна. конкретно указать, какой метод реализован.Из этого вывода функциональный интерфейс может иметь не более одного метода для реализации.
Поддержка JDK для Lambda
Через определение функционального интерфейса и лямбда-реализации мы знаем простой формат лямбда-синтаксиса, но в процессе разработки мы не можем определить функциональный интерфейс для каждого лямбда-приложения, На самом деле, в JDK их уже много. лямбда-функция:
-
Function<T, R>: принимает один ввод параметра, тип ввода — T, тип вывода — R. Абстрактный метод
R apply(T)
. -
BiFunction<T, U, R>: принимает два входных параметра, T и U — типы двух параметров соответственно, а R — тип вывода. Абстрактный метод
R apply(T, U)
. -
Consumer: принимает один ввод, без вывода. Абстрактный метод
void accept(T t)
. -
Predicate: принимает один вход и выводит логический тип. Абстрактный метод
boolean test(T t)
. -
Supplier: Нет входа, один выход. Абстрактный метод
T get()
. -
BinaryOperator: принимает два входа одного типа, а выход имеет тот же тип, что и вход, что эквивалентно BiFunction
. -
UnaryOperator: принимает ввод, а вывод имеет тот же тип, что и ввод, что эквивалентно Function
. - BiPredicate<T, U>: принимает два входа и выводит логический тип. Абстрактный метод — это логический тест (T t, U u).
Они используются в разных сценариях, и ниже будет несколько демонстраций.Во-первых, калькулятор реализован с использованием лямбды:
BinaryOperator<Integer> cal = (a, b) -> a + b;
System.out.println(bo.apply(1, 2)); // 3
Еще один, используйте лямбда, чтобы определить, является ли число положительным или отрицательным.
int a = 1;
int b = -1;
Predicate<Integer> predicate = i -> i >= 0;
System.out.println(predicate.test(a)); //true
System.out.println(predicate.test(b)); //false
Суммировать
В Stream применение лямбды очень обширно, и если мы хотим освоить лямбду более умело, нам нужно самим использовать лямбду и по-настоящему испытать силу лямбды в реальном бою.