Позвольте вам решить лямбда-выражения и функциональные интерфейсы, которые должны использовать крупные производители.

Java
Позвольте вам решить лямбда-выражения и функциональные интерфейсы, которые должны использовать крупные производители.

Предисловие:

В ответ на потребности читателей 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, правила использования многоточия следующие:

  1. Тип параметра в скобках можно не указывать;
  2. Если в скобкахЕсть только один параметр, скобки можно опустить;
  3. Если внутри фигурных скобокимеет одно и только одно утверждение, фигурные скобки, ключевое слово return и точка с запятой оператора могут быть опущены независимо от того, есть ли возвращаемое значение.

Примечание. После освоения этих правил пропусков просмотрите случай многопоточности в начале этой главы соответственно.

можно вывести, а можно опустить

Lambda подчеркивает «что делать», а не «как это делать», поэтому любая информация, которую можно получить, может быть опущена. Например, в приведенном выше примере также может использоваться пропуск Lambda:

Runnable接口简化:
1. () -> System.out.println("多线程任务执行!")
Comparator接口简化:
2. Arrays.sort(array, (a, b) -> a.getAge() - b.getAge());

1.4 Предпосылки для лямбда

Синтаксис Lambda очень лаконичен и полностью свободен от ограничений объектно-ориентированной сложности. Однако есть несколько моментов, которые требуют особого внимания при использовании:

  1. Использование Lambda должно иметь интерфейс и требоватьВ интерфейсе ровно один абстрактный метод. Либо встроенный JDKRunnable,ComparatorИнтерфейс также является пользовательским интерфейсом, и Lambda можно использовать только в том случае, если абстрактный метод в интерфейсе существует и уникален.
  2. Используя 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, я опубликую видео о синхронизации статей в будущем ~~~Добро пожаловать, чтобы обратить внимание на мой публичный аккаунт, чтобы получить больше информации~~~