Насколько мне известно, есть только два вида функций: деструктивные и конструктивные.
В то время как конструктивная функция, как следует из названия, что-то конструирует, деструктивная функция что-то разрушает, но не так, как вы сейчас думаете.
Например, функция
Function<Integer,Integer> f = (x,y) -> x + y
является конструктивным . Как вам нужно что-то построить. В этом примере вы построили кортеж (x, y) . У конструктивных функций есть проблема, заключающаяся в том, что они не могут обрабатывать бесконечные аргументы. Но хуже всего то, что нельзя просто оставить спор открытым. Вы не можете просто сказать «ну, пусть x: = 1» и пробовать каждый y, какой захотите. Вы должны каждый раз строить весь кортеж с помощью
x := 1
. Так что, если вы хотите увидеть, что возвращают функции, y := 1, y := 2, y := 3
вы должны написать f(1,1) , f(1,2) , f(1,3)
.
В Java 8 конструктивные функции должны обрабатываться (большую часть времени) с использованием ссылок на методы, потому что использование конструктивной лямбда-функции не дает особых преимуществ. Они немного похожи на статические методы. Вы можете использовать их, но они не имеют реального состояния.
Другой тип - разрушительный, он что-то берет и разбирает по мере необходимости. Например, деструктивная функция
Function<Integer, Function<Integer, Integer>> g = x -> (y -> x + y)
делает то же самое, что и функция, f
которая была конструктивной. Преимущества деструктивной функции заключаются в том, что теперь вы можете обрабатывать бесконечные аргументы, что особенно удобно для потоков, и вы можете просто оставить аргументы открытыми. Итак, если вы снова захотите увидеть, каков будет результат, если x := 1
и y := 1 , y := 2 , y := 3
, вы можете сказать h = g(1)
и
h(1)
является результатом для y := 1
, h(2)
для y := 2
и h(3)
для y := 3
.
Итак, у вас есть фиксированное состояние! Это довольно динамично, и в большинстве случаев это именно то, что мы хотим от лямбды.
Такие шаблоны, как Factory, намного проще, если вы можете просто добавить функцию, которая сделает всю работу за вас.
Деструктивные легко сочетаются друг с другом. Если тип правильный, вы можете просто составить их, как вам нравится. Используя это, вы можете легко определять морфизмы, которые значительно упрощают (с неизменяемыми значениями) тестирование!
Вы можете сделать то же самое с конструктивным, но деструктивная композиция выглядит лучше и больше похожа на список или декоратор, а конструктивная очень похожа на дерево. А такие вещи, как возврат с помощью конструктивных функций, просто нехорошие. Вы можете просто сохранить частичные функции деструктивного (динамическое программирование), а при «возврате» просто использовать старую деструктивную функцию. Это делает код намного меньше и лучше читается. С конструктивными функциями у вас есть более или менее запомнить все аргументы, которых может быть много.
Итак, почему существует необходимость, BiFunction
должно быть больше вопросов, чем почему нет TriFunction
?
Во-первых, много времени у вас есть всего несколько значений (меньше 3) и нужен только результат, поэтому обычная деструктивная функция не понадобится вообще, а конструктивная подойдет. И есть такие вещи, как монады, которые действительно нуждаются в конструктивной функции. Но помимо этого, на самом деле не так много веских причин, по которым вообще существует BiFunction
. Это не значит, что его нужно удалить! Я борюсь за свои Монады, пока не умру!
Поэтому, если у вас много аргументов, которые нельзя объединить в логический контейнерный класс, и если вам нужно, чтобы функция была конструктивной, используйте ссылку на метод. В противном случае попробуйте использовать новую полученную способность деструктивных функций, вы можете обнаружить, что делаете много вещей с гораздо меньшим количеством строк кода.