Глубокое понимание лямбда-выражений и функциональных интерфейсов

Java

1. Что такое лямбда

  • Функциональное программирование? Анонимный внутренний класс? лаконичный?
  • Возникший из академических кругов λ, он в основном представляет собой параметризацию поведения, упрощенный внутренний класс и широко используется в функциональном интерфейсе.

2. Зачем изучать лямбда?

  • Не спрашивайте почему, управляющий фабрики мой двоюродный брат.
  • Эта статья позволит вам научиться использовать лямбда-выражения полностью, независимо от того, где вы можете ()->{} немного.

3. лямбда-синтаксис

  • полное лямбда-выражение
(Type1 param1,Type2 param2,Type3 params)->{

	statement1;
	statement2;
	....
	return data;
}

1. ()->{}, лямбда-параметры, стрелки и лямбда-тела обязательны

2. Тип параметра можно не указывать, и он вообще не указывается

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

4. Ссылки на методы можно использовать как лямбда-выражения.

лямбда без параметров

  • Более продвинутые, чем анонимные внутренние классы, имя интерфейса и имя функции опущены.
  • Тело лямбды состоит только из одной строки, и {} можно опустить.

параметризованная лямбда

  • Много раз идеи можно оптимизировать, но. . . В представленной кодовой базе все еще есть куча идейных советов, выделенных серым цветом.

4. Функциональный интерфейс

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

Несколько типовых функциональных интерфейсов

1. Бифункция

@FunctionalInterface
public interface BiFunction<T, U, R> {
    R apply(T t, U u);

    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t, U u) -> after.apply(apply(t, u));
    }
}

1. Этот функциональный интерфейс активно используется в потоке java 8.

2. Есть 2 метода, только 1 абстрактный метод

3. Абстрактный метод apply принимает два параметра, тип — T, U, а возвращаемое значение — R.

4. Функциональный интерфейс BiFunction третьего параметра get() ниже, поэтому вы можете передать лямбду, соответствующую спецификации функционального интерфейса, при вызове get(). Что касается параметра 1 и параметра 2, как работать, работать и шифровать. . . Зависит от вашего лямбда-тела.

2. Потребитель

  • Функция потребления, возвращаемое значение недействительно.

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

  • Возвращаемое значение недействительно, поэтому обычно используются его побочные эффекты.

3. Предикат

  • Проверка утверждения/условия, определяет абстрактный метод, должен иметь 1 входной параметр, возвращаемое значение логическое.
  • Наиболее часто используемый filter() в потоке может образовывать цепочку вызовов предикатов.
//以下都可以做一个Predicate的lambda
1、(s)->s.length()>0;
2、(v)->v > 100;
3、(o)->o.startWith("a");

4. Поставщик

  • Ввод не требуется, вывод T. Подобно контейнеру, вызов get возвращает объект.
Supplier<Integer> supplier = new Supplier<Integer>() {
            @Override
            public Integer get() {
                //返回一个随机值
                return new Random().nextInt();
            }
        };
System.out.println(supplier.get());
System.out.println(supplier.get());

ссылка на метод

  • Проще говоря, он позволяет повторно использовать существующие определения методов и передавать их как лямбда-выражения, используя :: для их обозначения. Есть три основные категории.
  • Основной момент: сигнатура функции должна быть согласованной, то есть тип параметра, количество параметров, тип возвращаемого значения или пустота.

1. Ссылка на метод статического метода

  • Статические методы действуют на объекты.
  public static void main(String[] args) {
    List<String> list = Lists.newArrayList("1","2","3","4");

    List<Integer> collect1 = list.stream().map(v -> Integer.parseInt(v))
        .collect(Collectors.toList());
    List<Integer> collect2 = list.stream().map(Integer::parseInt)
        .collect(Collectors.toList());
    
  }

2. Ссылка на метод экземпляра любого типа.

1. Этот произвольный тип обычно относится к типу параметра вашей лямбды.

2. Если следующим входным параметром является v, вызов v.length может записать тип v String::length.

  public static void main(String[] args) {

    List<String> list = Lists
        .newArrayList("hello", "how", "are", "you", "i", "am", "fine", "thank", "you", "and",
            "you");
    Set<Integer> collect = list.stream().map(v -> v.length()).collect(Collectors.toSet());

    Set<Integer> collect1 = list.stream().map(String::length).collect(Collectors.toSet());
    System.out.println(collect);
    System.out.println(collect1);
  }

3. Ссылка метода на метод существующего объекта

  • Аналогично пункту 2 выше, без подробностей.

V. Резюме

  • В основном представляет лямбда-выражения и функциональные интерфейсы.
  • Суть использования функционального интерфейса состоит в том, чтобы получить правильную сигнатуру функции, передать лямбду, соответствующую условной сигнатуре, и вы можете спровоцировать ()->{}.