Волшебный функциональный интерфейс серии Java8

Java
Волшебный функциональный интерфейс серии Java8

предисловие

В предыдущем объяснении Lambda мы упомянули функциональные интерфейсы, такие как: Consumer<String>Consumer = (s) -> System.out.println(s), где Consumer — функциональный интерфейс. Вот объект с функциональным интерфейсом, созданный с помощью лямбда-выражения. Если вы не знаете, что такое Lambda, прочтите, пожалуйста, "Таинственная лямбда".

Что такое функциональный интерфейс?

Интерфейс с одним и только одним абстрактным методом называется функциональным интерфейсом. Функциональный интерфейс подходит для сценариев функционального программирования. Lambda — это воплощение функционального программирования в Java. Выражение Lambda можно использовать для создания объекта с функциональным интерфейсом. Убедитесь, что в интерфейсе есть только один абстрактный метод, чтобы Lambda могла плавно делать выводы.

Аннотация @FunctionalInterface

Подобно роли аннотации @Override, Java 8 представляет новую аннотацию специально для функциональных интерфейсов: @FunctionalInterface. Эту аннотацию можно использовать при определении интерфейса.После того как аннотация используется для определения интерфейса, компилятор заставит проверить, имеет ли интерфейс только один абстрактный метод, иначе будет сообщено об ошибке. Но эта аннотация не требуется, если она соответствует определению функционального интерфейса, тогда интерфейс является функциональным интерфейсом.

статический метод и метод по умолчанию

Я действительно не знаю, где представить эти два метода, поэтому я перемешал их здесь.

статический метод:

В java8 в интерфейс добавлена ​​новая функция, которая определяет один или несколько статических методов. Использование такое же, как и у обычного статического метода, например:

public interface Interface {
    /**
     * 静态方法
     */
    static void staticMethod() {
        System.out.println("static method");
    }
}

注意:实现接口的类或者子接口不会继承接口中的静态方法。

метод по умолчанию:

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

public interface Interface {
    /**
     * default方法
     */
    default void print() {
        System.out.println("hello default");
    }
}

注意:如果接口中的默认方法不能满足某个实现类需要,那么实现类可以覆盖默认方法。不用加default关键字,Например:

public class InterfaceImpl implements Interface {
    @Override
    public  void print() {
        System.out.println("hello default 2");
    }
}

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

Пользовательский функциональный интерфейс

Вы также можете написать функциональные интерфейсы, как определено в следующем формате:

 @FunctionalInterface
 修饰符 interface 接口名称 {
    返回值类型 方法名称(可选参数信息);
    // 其他非抽象方法内容
 }

Хотя аннотация @FunctionalInterface необязательна, лучше всего добавлять пользовательские функциональные интерфейсы.Один из них — выработать хорошие привычки программирования, а другой — предотвратить изменение другими.Как только вы увидите эту аннотацию, вы поймете, что это функциональный интерфейс, чтобы избежать других Добавление абстрактных методов к интерфейсам создает ненужные проблемы.

@FunctionalInterface
public interface MyFunction {
    void print(String s);
}

Глядя на картинку выше, вы видите функциональный интерфейс, который я настроил, так какова функция этого интерфейса? Это вывод строки строк, которая принадлежит интерфейсу потребителя и написана для имитации интерфейса потребителя, но при этом не используются дженерики, а параметры специально типизированы.Не имеет значения, если вы не знаете Consumer.Существует много часто используемых функциональных интерфейсов, и Consumer является одним из них.Как правило, вам не нужно определять его самостоятельно, просто используйте его напрямую. Итак, как использовать этот пользовательский функциональный интерфейс? Мы можем использовать функциональный интерфейс в качестве параметра и передавать лямбда-выражение при вызове. Если параметр метода является Lambda, то тип параметра должен быть функциональным интерфейсом. Например:

public class MyFunctionTest {
    public static void main(String[] args) {
        String text = "试试自定义函数好使不";
        printString(text, System.out::print);
    }

    private static void printString(String text, MyFunction myFunction) {
        myFunction.print(text);
    }
}

После выполнения будет выведено предложение «Попробуйте пользовательскую функцию, чтобы сделать ее лучше». Если спрос изменится в один прекрасный день, я не хочу выводить это предложение. Если я хочу вывести что-то еще, просто замените текст напрямую. Функциональное программирование не имеет побочных эффектов.Самым большим преимуществом является то, что функция не имеет состояния внутри, то есть вход определяет результат. В функциональном программировании есть более интересные подпрограммы, которые нужно изучить каждому. 😝

Общий функциональный интерфейс

Consumer<T>: Потребительский интерфейс

Абстрактный метод:void accept(T t), получает параметр для потребления, но не должен возвращать результат.

Как пользоваться:

  Consumer consumer = System.out::println;
  consumer.accept("hello function");

Метод по умолчанию:andThen(Consumer super T> after), потреблять сначала, а затем потреблять, сначала выполнить метод accept, который вызывает интерфейс andThen, а затем выполнить метод accept в параметре after метода andThen.

Как пользоваться:

  Consumer<String> consumer1 = s -> System.out.print("车名:"+s.split(",")[0]);
  Consumer<String> consumer2 = s -> System.out.println("-->颜色:"+s.split(",")[1]);

  String[] strings = {"保时捷,白色", "法拉利,红色"};
  for (String string : strings) {
     consumer1.andThen(consumer2).accept(string);
  }

вывод:Название автомобиля: Porsche --> Цвет: белый Название автомобиля: Ferrari --> Цвет: красный

Supplier<T>: Интерфейс типа питания

абстрактный метод: T get(), без параметров, возвращаемое значение.

Как пользоваться:

 Supplier<String> supplier = () -> "我要变的很有钱";
 System.out.println(supplier.get());

Конечным результатом является «Я собираюсь разбогатеть», и этот тип интерфейса подходит для сценариев, в которых предоставляются данные.

Function<T,R>: функциональный интерфейс

Абстрактный метод:R apply(T t), передавая один параметр, возвращает желаемый результат.

Как пользоваться:

 Function<Integer, Integer> function1 = e -> e * 6;
 System.out.println(function1.apply(2));

Очень простой пример умножения, очевидно, что конечный результат равен 12.

Метод по умолчанию:

  • compose(Function super V, ? extends T> before), сначала выполните метод применения в параметре метода компоновки перед, а затем передайте результат выполнения методу применения в функции компоновки для выполнения.

Как пользоваться:

 Function<Integer, Integer> function1 = e -> e * 2;
 Function<Integer, Integer> function2 = e -> e * e;

 Integer apply2 = function1.compose(function2).apply(3);
 System.out.println(apply2);

Или возьмем пример умножения, Процесс выполнения метода compose заключается в том, чтобы сначала выполнить выражение function2, которое равно 33=9, то выражение, передающее результат выполнения функции1, равно 92=18, поэтому окончательный результат равен 18.

  • andThen(Function super R, ? extends V> after), сначала выполните метод применения, который вызывает функцию andThen, а затем передайте результат выполнения методу применения в параметре after метода andThen для выполнения. Он выполняется в порядке, обратном методу compose.

Как пользоваться:

 Function<Integer, Integer> function1 = e -> e * 2;
 Function<Integer, Integer> function2 = e -> e * e;

 Integer apply3 = function1.andThen(function2).apply(3);
 System.out.println(apply3);

Здесь мы используем пример с методом compose, так что это точно такой же пример.Из-за разных методов порядок выполнения также отличается, поэтому результаты сильно различаются. Метод andThen должен сначала выполнить выражение function1, которое равно 3.2=6, а затем выполнение выражения function2 равно 66=36. Результат 36. **Статический метод: **identity(), получить экземпляр функции с тем же входным параметром и вернуть результат.

Как пользоваться:

 Function<Integer, Integer> identity = Function.identity();
 Integer apply = identity.apply(3);
 System.out.println(apply);

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

Predicate<T>: интерфейс утверждения

Абстрактный метод:boolean test(T t), передать параметр и вернуть логическое значение.

Как пользоваться:

 Predicate<Integer> predicate = t -> t > 0;
 boolean test = predicate.test(1);
 System.out.println(test);

Когда функция-предикат вызывает тестовый метод, она выполняет условное суждение t -> t > 0 с параметрами тестового метода, 1 должно быть больше 0, а окончательный результат — истина.

Метод по умолчанию:

  • and(Predicate super T> other), который эквивалентен && в логическом операторе, возвращает значение true, только если возвращаемые результаты обеих функций Predicate равны true.

Как пользоваться:

 Predicate<String> predicate1 = s -> s.length() > 0;
 Predicate<String> predicate2 = Objects::nonNull;
 boolean test = predicate1.and(predicate2).test("&&测试");
 System.out.println(test);
  • or(Predicate super T> other) , что эквивалентно || в логическом операторе. Когда один из результатов, возвращаемых двумя функциями Predicate, равен true, он возвращает true, в противном случае возвращается false.

Как пользоваться:

 Predicate<String> predicate1 = s -> false;
 Predicate<String> predicate2 = Objects::nonNull;
 boolean test = predicate1.and(predicate2).test("||测试");
 System.out.println(test);
  • negate(), этот метод означает отрицание.

Как пользоваться:

 Predicate<String> predicate = s -> s.length() > 0;
 boolean result = predicate.negate().test("取反");
 System.out.println(result);

Очевидно, что если тестовый метод выполняется нормально, он должен быть истинным, но после вызова метода отрицания он вернется к ложному. **Статический метод: **isEqual(Object targetRef), выполнить операцию "=" над текущей операцией, то есть взять операцию равенства, которую можно понимать как A == B.

Как пользоваться:

 boolean test1 = Predicate.isEqual("test").test("test");
 boolean test2 = Predicate.isEqual("test").test("equal");
 System.out.println(test1);   //true
 System.out.println(test2);   //false

Другие функциональные интерфейсы

Битипный интерфейс

BiConsumer, BiFunction и BiPredicate являются расширениями Consumer, Function и Predicate. Можно передавать несколько параметров. BiSupplier отсутствует, поскольку у Supplier нет параметров.

Интерфейсы для работы с примитивными типами данных

IntConsumer, IntFunction, IntPredicate, IntSupplier, LongConsumer, LongFunction, LongPredicate, LongSupplier, DoubleConsumer, DoubleFunction, DoublePredicate, DoubleSupplier. На самом деле, обычно используемые функциональные интерфейсы — это четыре основных интерфейса Consumer, Function, Prediate и Supplier.Другие функциональные интерфейсы не перечислены один за другим.Если вам интересно, вы можете перейти к пакету java.util.function для подробный вид.

После просмотра ставьте лайки и подписывайтесь! Другие блоги будут следовать. Если есть какая-то ошибка, пожалуйста, поправьте меня.