Метод andThen () по умолчанию в интерфейсе BiFunction - PullRequest
0 голосов
/ 28 апреля 2018

В интерфейсе BiFunction (java.util.function пакет) есть метод по умолчанию andThen().

default <V> BiFunction<T,U,V> andThen(Function<? super R,? extends V> after)

В документации сказано:

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

Немного смущает понимание того, что означает объяснение. Насколько я понимаю, составная функция возвращается, когда вызывается метод andThen() по умолчанию. Эта составная функция вызывается для типов T и U, которая возвращает тип V. Наконец, есть и функция after, которая вызывается для типов R и V.

Зачем нужен этот метод? Как это на самом деле вписывается в картину?

Ответы [ 4 ]

0 голосов
/ 28 апреля 2018

Нетрудно понять, что означает это объяснение.

Чтобы объяснить это настолько просто, насколько я могу, метод andThen возвращает функцию, которая сначала применяет данную функцию к входу, а затем применяет другую функцию к результату этого приложения.

Предположим, у нас было две функции f и g, функция f, выполняющая некоторую логику, и функция g, выполняющая некоторый другой тип логики, поэтому, когда вы составляете f.andThen(g), это по существу означает g(f(x)), т.е. примените функцию, заданную в качестве аргумента f(x), а затем примените функцию g к результату.

Пример:

BiFunction<Integer, Integer, Integer> f = Math::addExact; 
Function<Integer, Integer> g = e -> e * 2; 
System.out.println(f.andThen(g).apply(10,10)); // 40

Сначала мы вызываем функцию f(10, 10), а затем берем результат, равный 20, передаем его в функцию g(20) и выполняем умножение 20 на 2, следовательно, получая 40.

Если честно, синтаксис для вызова функции в Java не самый лучший, каким он может быть, поэтому я могу понять, когда кто-то смотрит на это в первый раз, это может быть трудно понять и становится труднее следовать, чем больше вы сочиняете например, в C# можно было бы просто выполнить g(f(10, 10)), что наглядно для глаз легче наблюдать, читать и понимать.

Зачем нужен этот метод? Как это на самом деле вписывается в картина

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

0 голосов
/ 28 апреля 2018

Это легче понять на примере:

BiFunction<Integer, Integer, String> f = 
        (n1, n2) -> String.format("result is %s", n1+n2);

И «составленная функция»:

BiFunction<Integer, Integer, String> f1 = 
        f.andThen(string -> string.toUpperCase());

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

Рассмотрим вызов:

System.out.println(f1.apply(2, 3));

Который выводит RESULT IS 5, то есть: он вызывает первую функцию, а затем вызывает вторую функцию с результатом первой. Таким образом, это просто понимается как f1(f(x, y)) с конечным входом, являющимся входом, требуемым для f, а конечным результатом является результат, полученный с помощью f1.

0 голосов
/ 28 апреля 2018

Я думаю, что основная цель функции andThen - сделать ваш код более читабельным и функциональным.

Давайте рассмотрим и пример:

BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
Function<Integer, Integer> negate = x -> -x;
BiFunction<Integer, Integer, Integer> newFunction = add.andThen(negate);

Угадай, что делает newFunction? добавляет и затем отменяет два числа! Посмотрите, насколько похожа эта строка на английский:

BiFunction<Integer, Integer, Integer> newFunction = add.andThen(negate);

Если вы позвоните .apply(1, 2), вы знаете, что получите -3.

Конечно, вы можете сделать это без использования andThen:

BiFunction<Integer, Integer, Integer> newFunction = (x, y) -> negate.apply(add.apply(x, y))

Но посмотрите, как это нечитаемо!

Функциональное кодирование иногда может значительно облегчить чтение и понимание.

0 голосов
/ 28 апреля 2018

Рассмотрим f1.andThen(f2):

  1. Во-первых, f1 будет принимать 2 элемента, в результате всего 1
  2. после этого f2 примет результат f1 и преобразует его в другой результат
BiFunction<Integer, Integer, Integer> plus10 = (i1, i2) -> i1 + i2 + 10;

Function<Integer, Integer> mult = i -> i * 5;

System.out.println(plus10.andThen(mult).apply(5, 6)); // (5+6+10) *5 = 105

Это способ сократить вычисления

int val1 = plus10.apply(5, 6);
int res1 = mult.apply(val1);

int res2 = plus10.andThen(mult).apply(5, 6);
System.out.println(res1 == res2);            //true

Это становится все более и более полезным, когда у вас есть несколько функций для использования, потому что есть одинаковые method для Function, так что вы можете объединить их в цепочку:

System.out.println(plus10.andThen(mult).andThen(mult).andThen(mult).apply(5, 6)); 
// (5+6+10)*5*5*5 = 2625
...