Как эффективно использовать функциональные интерфейсы | Практика разработки Java

Java

Эта статья участвует в "Java Theme Month - Java Development Practice", подробнее см.Ссылка на мероприятие

открытие

Это третий день моего участия в Gengwen Challenge.Подробности о мероприятии, пожалуйста, проверьте:Обновить вызов

Функция, которую все знают и используют в JDK8, это Lambda, которая используется многими людьми, например Stream, но она проста и проста, например, вызов Stream API коллекции и т. д., но она не определяет функциональные интерфейсы. или API сами по себе. Тематическое исследование по улучшению использования функционального программирования в Java.

Демонстрация кейса

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

интерфейс Входные параметры возвращаемый тип инструкция
UnaryOperator T T Унарная функция, типы ввода и вывода одинаковы
Predicate T boolean утверждение
Consumer T / Потребляйте данные, только ввод и без вывода
Function<T,R> T R Вход T возвращает R, как вход, так и выход
Supplier / T Предоставьте данные, без ввода, только вывод
BiFunction<T,U,R> (T,U) R два входных параметра
BiPredicate<L, R> (L,R) boolean два входных параметра
BiConsumer<T, U> (T,U) void два входных параметра
BinaryOperator (T,T) T Двоичная функция, типы ввода и вывода одинаковы

Дело номер один

Function<Integer, Integer> times2 = e -> e * 2;
Function<Integer, Integer> squared = e -> e * e;
// 先执行参数,再执行调用者
/*
 * 1. 4 * 4 = 16 16 * 2 = 32
 */
System.out.println("result: " + times2.compose(squared).apply(4)); // 32
/*
 * 先执行调用者: 4 * 2 = 8 再执行then传入的function 8 * 8 = 64
 */
System.out.println("result: " + times2.andThen(squared).apply(4)); // 64

Эти два метода,andThenУказывает, что она вызывается после выполнения внешней функции,composeУказывает, что он вызывается перед выполнением внешней функции.image.png

Случай 2

@Test
public void test2(){
    // 3个数相加
    Function<Integer, Function<Integer, IntFunction<Integer>>> addfun3 = x -> y -> z -> x + y + z ;
    // 7个数相加
    Function<Integer,
            Function<Integer,
                    Function<Integer,
                            Function<Integer,
                                    Function<Integer,
                                            Function<Integer, IntFunction<Integer>>>>>>>
            addfun7 = x -> y -> z -> a -> c -> b -> d -> x + y + z + a + c + b + d;
    // 1+2+3
    Integer sum = addfun3.apply(1).apply(2).apply(3);
    System.out.println(sum);
}

Таким образом можно достичь кумулятивного эффекта цепного программирования.image.png

Случай 3


@SafeVarargs
private static <R> Function<R, R> combineFunctions(Function<R, R>... functions) {
    return Arrays.stream(functions)
            .reduce(Function::andThen)
            .orElseThrow(() -> new IllegalArgumentException("No functions to combine"));
}

@Test
public void test3() {
    Function<Integer, Integer> addfun2 = x -> x * x;
    final Integer apply = combineFunctions(addfun2, addfun2).apply(2);
    System.out.println(apply);

    String str = "1,2,3,4,5,6";
    Function<Object, Object> splitByComma = s -> ((String) s).split(",");
    Function<Object, Object> convertToInt = tokens -> Stream.of((String[]) tokens).map(Integer::valueOf).toArray(Integer[]::new);
    Function<Object, Object> findMax = ints -> Stream.of((Integer[]) ints).max(Integer::compare).get();
    Integer max = (Integer) combineFunctions(splitByComma, convertToInt, findMax).apply(str);
    System.out.println(max);
}

Если вы хотите иметь метод, который принимает параметр функции переменной длины, вы можете использовать...дескриптор, где общий<R,R>Представляет ввод и тип ввода, используя дженерики для большей совместимости.

image.png

Случай 4

@Test
public void test4(){
    Function<Integer, Integer> addfun2 = x -> x * x;
    final Calculator<Integer, Integer> calculator = new Calculator<>(2);
    final Integer integer = calculator.combineFunctions(addfun2, addfun2);
    System.out.println(integer);
}

public class Calculator<R,T> {
    // 被操作的属性
    private Object input;

    public Calculator(Object input) {
        this.input = input;
    }
    // 可以通过这种方式定义对象自身的行为
    @SuppressWarnings("unchecked")
    @SafeVarargs
    public final R combineFunctions(Function<T, T>... functions) {
        return (R) Arrays.stream(functions)
                .reduce(Function::andThen)
                .orElseThrow(() -> new IllegalArgumentException("No functions to combine"))
                .apply((T)input);
    }
}

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

image.png

Случай 5

// BiConsumer<T, Integer> 两个输入参数T、Integer
 public static <T> Consumer<T> consumerWithIndex(BiConsumer<T, Integer> consumer) {
    class Obj {
        int i;
    }
    // 只会被调用一次,原因看java.lang.Iterable#forEach
    Obj obj = new Obj();
    // 返回的Consumer函数
    return t -> {
        int index = obj.i++;
        // 这里执行System.out.println("list[" + index + "]=" + item),消费指定泛型的数据。
        consumer.accept(t, index);
    };
}

@Test
public void test5(){
    val list = Arrays.asList("Hi", "I", "am", "Henry.Yao");
    // 2个元素为一组
    val partition = Lists.partition(list, 2);
    partition.forEach(LambdaUtils.consumerWithIndex((item, index) -> {
        System.out.println("list[" + index + "]=" + item);
    }));
}

Java8forEach()При зацикливании объектов нет возможности получить индекс индекса объекта, в этом случае для этого можно объявить функциональный метод, окончательная форма написания похожа на синтаксис forEach в Scala и js, что очень полезно !

image.png

java.lang.Iterable#forEach

// action:是一个Consumer函数
default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        /* 这里会循环调用Consumer函数,而consumerWithIndex返回的Consumer函数内容为
        t -> {
            int index = obj.i++;
            consumer.accept(t, index);
        }
        所以Obj obj = new Obj()只会被调用一次,这样就不用担心new Obj 时把 i 没有重置为0,不会发生的
        */
        consumer.accept(t, index);
    }
        action.accept(t);
    }
}

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

Подпишись + Нравится👍 Любимое ❤️ Не теряйся

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