Предисловие:
В ответ на потребности читателей Brother Pei приносит вам новый выпуск сухих товаров!
Позвольте вам решить лямбда-выражения и функциональные интерфейсы, которые должны использовать крупные производители.
[Возьмите вас, чтобы решить ссылку на поток и метод Stream, которую должна использовать большая фабрика]
Если это было полезно вам и вашим друзьям, обратите внимание на IT Pei Ge. Коллекция!Поделитесь ею с большим количеством друзей, чтобы учиться и общаться вместе, а постоянные обновления каждый день неотделимы от вашей поддержки!
Глава 1 Лямбда-выражения
1.1 Обзор идей функционального программирования
В математикефункцияЕсть ли набор схем расчета для ввода, вывода, является «Что вы делаете». Относительно говоря, объектно-ориентированные чрезмерно подчеркивают «делать вещи через форму объектов», а функциональное мышление пытается игнорировать объектно-ориентированный сложный синтаксис -Подчеркните, что делать, а не в какой форме.
что делать, а не как
Действительно ли мы хотим создать анонимный объект внутреннего класса? Нет. мы просто делаем этопридетсяСоздайте объект. Что мы действительно хотим сделать, так это:run
Код внутри тела метода передается вThread
Классовая осведомленность.
передать кусок кода- Это наша настоящая цель. Создание объекта — это только средство, которое необходимо использовать из-за объектно-ориентированного синтаксиса. Итак, есть ли способ проще? Если мы вернем фокус с «как» на суть «что делать», мы обнаружим, что до тех пор, пока цель может быть достигнута лучше, процесс и форма не важны.
1.2 Оптимизация лямбда
Когда поток должен быть запущен для выполнения задачи, это обычно делается с помощьюjava.lang.Runnable
интерфейс для определения содержания задачи и использованияjava.lang.Thread
класс, чтобы начать поток.
Традиционный способ написания кода выглядит следующим образом:
public class Demo03Thread {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("多线程任务执行!");
}
}).start();
}
}
В духе «все есть объект» такой подход понятен: сначала создайтеRunnable
Анонимный объект внутреннего класса интерфейса, чтобы указать содержимое задачи, а затем передать его потоку для запуска.
Анализ кода:
заRunnable
Использование анонимного внутреннего класса , может проанализировать несколько моментов:
-
Thread
потребности классаRunnable
интерфейс как параметр, абстракция которогоrun
Этот метод используется для указания ядра содержимого задачи потока; - чтобы указать
run
тело метода,придетсянеобходимостьRunnable
Класс реализации интерфейса; - Чтобы не определять
RunnableImpl
Проблема реализации классов,придетсяиспользовать анонимные внутренние классы; - Абстракция переопределения должна быть переопределена
run
метод, поэтому имя метода, параметры метода, возвращаемое значение методапридетсяНапишите еще раз и не ошибетесь; - По факту,Кажется, что ключом является только тело метода.
Написание лямбда-выражения, код выглядит следующим образом:
С новым синтаксисом Java 8 приведенное вышеRunnable
Анонимный внутренний класс интерфейса можно эквивалентно записать с помощью более простого лямбда-выражения:
public class Demo04LambdaRunnable {
public static void main(String[] args) {
new Thread(() -> System.out.println("多线程任务执行!")).start(); // 启动线程
}
}
И реализация результатов этого кода точно такая же, на уровне компилятора 1.8 или выше. Как видно из семантики кода: мы запустили тред, а содержание треда отдано задаче в более лаконичной форме.
Больше не нужно «создавать объекты интерфейса», больше нет бремени «переопределения абстрактного метода», это так просто!
1.3 Формат лямбды
стандартный формат:
Lambda опускает объектно-ориентированные блоки, и формат задается3 частисочинение:
- некоторые параметры
- Стрелка
- кусок кода
Лямбда-выражениястандартный форматза:
(参数类型 参数名称) -> { 代码语句 }
Описание формата:
- Синтаксис внутри круглых скобок такой же, как и в традиционном списке параметров метода: оставьте его пустым, если параметр отсутствует; несколько параметров разделяются запятыми.
-
->
— это недавно введенный формат синтаксиса, который представляет действие указывания. - Синтаксис в фигурных скобках в основном такой же, как и в традиционных требованиях к телу метода.
Анонимный внутренний класс против лямбда:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("多线程任务执行!");
}
}).start();
Тщательно проанализировав код,Runnable
только один интерфейсrun
Определение метода:
public abstract void run();
То есть сформулирован план поступления вещей (на самом деле, метод):
- Нет параметров: Никаких условий для выполнения схемы не требуется.
- нет возвращаемого значения: Этот сценарий не дает результатов.
- кодовый блок(Тело метода): конкретные шаги выполнения программы.
Та же семантика отражена вLambda
Грамматика, если быть проще:
() -> System.out.println("多线程任务执行!")
- Предыдущая пара скобок
run
Параметр метода (none), что означает, что никаких условий не требуется; - Стрелка посередине представляет собой передачу предыдущего параметра следующему коду;
- Следующий выходной оператор представляет собой код бизнес-логики.
Параметры и возвращаемые значения:
Следующий пример демонстрируетjava.util.Comparator<T>
Сценарий использования кода интерфейса, где абстрактные методы определены как:
public abstract int compare(T o1, T o2);
Когда вам нужно отсортировать массив объектов,Arrays.sort
метод требуетComparator
Экземпляр интерфейса для указания правил сортировки. Предположим, естьPerson
класс, содержащийString name
иint age
Две переменные-члены:
public class Person {
private String name;
private int age;
// 省略构造器、toString方法与Getter Setter
}
Традиционное письмо
При использовании традиционной кодовой парыPerson[]
Массив сортируется следующим образом:
public class Demo05Comparator {
public static void main(String[] args) {
// 本来年龄乱序的对象数组
Person[] array = {
new Person("古力娜扎", 19),
new Person("迪丽热巴", 18),
new Person("马尔扎哈", 20)
};
// 匿名内部类
Comparator<Person> comp = new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
};
Arrays.sort(array, comp); // 第二个参数为排序规则,即Comparator接口实例
for (Person person : array) {
System.out.println(person);
}
}
}
Этот подход также кажется «естественным» в объектно-ориентированном мышлении. вComparator
Экземпляры интерфейса (с использованием анонимных внутренних классов) представляют собой упорядочение «от века к старому».
анализ кода
Давайте разберемся, что на самом деле делает приведенный выше код.
- Для сортировки,
Arrays.sort
метод требует сопоставления, т.е.Comparator
Экземпляр интерфейса, абстрактный методcompare
ключ; - чтобы указать
compare
тело метода,придетсянеобходимостьComparator
Класс реализации интерфейса; - Чтобы не определять
ComparatorImpl
Проблема реализации классов,придетсяиспользовать анонимные внутренние классы; - Абстракция переопределения должна быть переопределена
compare
метод, поэтому имя метода, параметры метода, возвращаемое значение методапридетсяНапишите еще раз и не делайте ошибок; - По факту,Критичны только параметры и тела методов..
лямбда-письмо
public class Demo06ComparatorLambda {
public static void main(String[] args) {
Person[] array = {
new Person("古力娜扎", 19),
new Person("迪丽热巴", 18),
new Person("马尔扎哈", 20) };
Arrays.sort(array, (Person a, Person b) -> {
return a.getAge() - b.getAge();
});
for (Person person : array) {
System.out.println(person);
}
}
}
Пропустить формат:
правило пропуска
Основываясь на стандартном формате Lambda, правила использования многоточия следующие:
- Тип параметра в скобках можно не указывать;
- Если в скобкахЕсть только один параметр, скобки можно опустить;
- Если внутри фигурных скобокимеет одно и только одно утверждение, фигурные скобки, ключевое слово return и точка с запятой оператора могут быть опущены независимо от того, есть ли возвращаемое значение.
Примечание. После освоения этих правил пропусков просмотрите случай многопоточности в начале этой главы соответственно.
можно вывести, а можно опустить
Lambda подчеркивает «что делать», а не «как это делать», поэтому любая информация, которую можно получить, может быть опущена. Например, в приведенном выше примере также может использоваться пропуск Lambda:
Runnable接口简化:
1. () -> System.out.println("多线程任务执行!")
Comparator接口简化:
2. Arrays.sort(array, (a, b) -> a.getAge() - b.getAge());
1.4 Предпосылки для лямбда
Синтаксис Lambda очень лаконичен и полностью свободен от ограничений объектно-ориентированной сложности. Однако есть несколько моментов, которые требуют особого внимания при использовании:
- Использование Lambda должно иметь интерфейс и требоватьВ интерфейсе ровно один абстрактный метод.
Либо встроенный JDK
Runnable
,Comparator
Интерфейс также является пользовательским интерфейсом, и Lambda можно использовать только в том случае, если абстрактный метод в интерфейсе существует и уникален. - Используя Lambda, вы должны иметь интерфейс в качестве параметра метода. То есть тип параметра или локальной переменной метода должен быть типом интерфейса, соответствующим Lambda, чтобы использовать Lambda в качестве экземпляра интерфейса.
Примечания: Интерфейс с одним и только одним абстрактным методом, называемым "функциональный интерфейс".
Глава 2 Функциональные интерфейсы
2.1 Обзор
Функциональный интерфейс в Java означает:Интерфейс с одним и только одним абстрактным методом.
Функциональный интерфейс, то есть интерфейс, подходящий для сценариев функционального программирования. Воплощением функционального программирования на Java является Lambda, поэтому функциональный интерфейс — это интерфейс, который может использоваться Lambda. Лямбда-выражения в Java могут быть выведены плавно только в том случае, если в интерфейсе есть ровно один абстрактный метод.
Примечания. С точки зрения приложения Lambda в Java можно рассматривать как упрощенный формат анонимного внутреннего класса, но в принципе они разные.
Формат
Просто убедитесь, что в интерфейсе ровно один абстрактный метод:
修饰符 interface 接口名称 {
public abstract 返回值类型 方法名称(可选参数信息);
// 其他非抽象方法内容
}
Из-за абстрактного метода в интерфейсеpublic abstract
можно опустить, поэтому определить функциональный интерфейс просто:
public interface MyFunctionalInterface {
void myMethod();
}
Аннотация функционального интерфейса
и@Override
Аннотации работают аналогично, и в Java 8 появилась новая аннотация специально для функциональных интерфейсов:@FunctionalInterface
. Эту аннотацию можно использовать для определения интерфейса:
@FunctionalInterface
public interface MyFunctionalInterface {
void myMethod();
}
Как только интерфейс определен с этой аннотацией, компилятор принудительно проверит, имеет ли интерфейс только один абстрактный метод, в противном случае он сообщит об ошибке. Однако, даже если аннотация не используется, пока выполняется определение функционального интерфейса, он по-прежнему является функциональным интерфейсом и может использоваться так же.
2.2 Часто используемые функциональные интерфейсы
JDK предоставляет большое количество часто используемых функциональных интерфейсов для обогащения типичных сценариев использования Lambda, которые в основном используются вjava.util.function
предоставляется в упаковке. предыдущийMySupplier
Интерфейс имитирует функциональный интерфейс:java.util.function.Supplier<T>
. На самом деле их гораздо больше, ниже приведены самые простые интерфейсы и примеры использования.
Интерфейс поставщика
java.util.function.Supplier<T>
интерфейс, что означает «снабжение», соответствующее лямбда-выражение требует «Обеспечить извне"Данные объекта, соответствующие универсальному типу.
абстрактный метод: получить
Содержит только один метод без параметров:T get()
. Используется для получения данных объекта типа, указанного универсальным параметром.
public class Demo08Supplier {
private static String getString(Supplier<String> function) {
return function.get();
}
public static void main(String[] args) {
String msgA = "Hello";
String msgB = "World";
System.out.println(getString(() -> msgA + msgB));
}
}
Найдите максимальное значение элемента массива
использоватьSupplier
В качестве типа параметра метода используется интерфейс, а максимальное значение в массиве int получается лямбда-выражением. Совет: Пожалуйста, используйте общий тип интерфейсаjava.lang.Integer
своего рода.
Пример кода:
public class DemoIntArray {
public static void main(String[] args) {
int[] array = { 10, 20, 100, 30, 40, 50 };
printMax(() -> {
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
return max;
});
}
private static void printMax(Supplier<Integer> supplier) {
int max = supplier.get();
System.out.println(max);
}
}
Потребительский интерфейс
java.util.function.Consumer<T>
Интерфейс как раз наоборот, он не выдает данные, аПотреблениеДанные, тип данных которых определяется универсальным параметром.
Абстрактный метод: принять
Consumer
Интерфейс содержит абстрактные методыvoid accept(T t)
, что означает использование данных указанного универсального типа. Основное использование, такое как:
import java.util.function.Consumer;
public class Demo09Consumer {
private static void consumeString(Consumer<String> function , String str) {
function.accept(str);
}
public static void main(String[] args) {
consumeString(s -> System.out.println(s), "后端跟我学");
}
}
Функциональный интерфейс
java.util.function.Function<T,R>
Интерфейс используется для получения другого типа данных в соответствии с одним типом данных.Первый называется предварительным условием, а второй называется постусловием. Есть вход и выход, поэтому он называется «Функция».
Абстрактный метод: применить
Function
Основные абстрактные методы в интерфейсе:R apply(T t)
, который получает результат типа R на основе аргумента типа T. Используемые сценарии, например:String
преобразование типа вInteger
тип.
public class Demo11FunctionApply {
private static void method(Function<String, Integer> function, Str str) {
int num = function.apply(str);
System.out.println(num + 20);
}
public static void main(String[] args) {
method(s -> Integer.parseInt(s) , "10");
}
}
Предикатный интерфейс
Иногда нам нужно оценить определенный тип данных, чтобы получить результат логического значения. В это время вы можете использоватьjava.util.function.Predicate<T>
интерфейс.
Абстрактный метод: тест
Predicate
Интерфейс содержит абстрактный метод:boolean test(T t)
. Для сценариев условного суждения критерием условного суждения является входящая логика лямбда-выражения.Если длина строки больше 5, она считается очень длинной.
public class Demo15PredicateTest {
private static void method(Predicate<String> predicate,String str) {
boolean veryLong = predicate.test(str);
System.out.println("字符串很长吗:" + veryLong);
}
public static void main(String[] args) {
method(s -> s.length() > 5, "HelloWorld");
}
}
Для последующих статей, пожалуйста, смотрите:
Для получения дополнительных статей, пожалуйста, перейдите наКак изучить экологию технологии Java (распределенные микросервисы), у брата Пей есть что сказать!
Если это было полезно вам и вашим друзьям, обратите внимание на IT Pei Ge. Коллекция!Поделитесь ею с большим количеством друзей, чтобы учиться и общаться вместе, а постоянные обновления каждый день неотделимы от вашей поддержки!
Добро пожаловать, чтобы обратить внимание на мою станцию B, я опубликую видео о синхронизации статей в будущем ~~~Добро пожаловать, чтобы обратить внимание на мой публичный аккаунт, чтобы получить больше информации~~~