Наскільки мені відомо, існують лише два види функцій, деструктивні та конструктивні.
Хоча конструктивна функція, як випливає з назви, щось конструює, деструктивна знищує щось, але не так, як ви можете думати зараз.
Наприклад, функція
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
взагалі існує. Що не означає, що його слід видалити! Я борюся за своїх монадів, поки не помру!
Отже, якщо у вас є багато аргументів, які ви не можете об'єднати в логічний клас контейнерів, і якщо вам потрібна функція, щоб бути конструктивною, використовуйте посилання на метод. Інакше спробуйте використовувати нову здобуту здатність деструктивних функцій, ви можете виявити, що ви робите багато справ із набагато меншими рядками коду.