Несмотря на мое традиционно скептическое отношение к незнакомым технологиям, я признаю преимущество функционального программирования. Ниже приведен примерный список из плюсов, которые описывают эту парадигму программирования.
![Кофе-брейк #131. Роль Java в разработке в веб- и мобильных приложений. Функциональное программирование — за и против - 2]()

Безопасный параллелизм
Функциональный подход поощряет безопасный параллелизм, то есть возможность запускать задания в отдельных потоках без возникновения конфликтов потоков и коллизий модификаций. Причина в том, что в отличие от объектного подхода, вы не разделяете объект, состояние которого можно изменить во время обработки. Есть входы и выходы, и вход не меняется из-за вас. В Java, даже если вы используете “потоко-ориентированные” объекты, вы не можете гарантировать, что они будут иметь одинаковые значения во время вызова вашего метода. В приведенном ниже примере мы видим, что цикл, который обрабатывает элементы по одному, может быть легко обработан параллельно с помощью лямбда-функции внутри потока.
for( String item : items ) {
process(item);
}
А теперь он становится:
items.parallelStream().forEach( item -> process(item) );
Быстрый ввод/вывод
Функциональное программирование поддерживает подход, отличный от многопоточности. Это означает, что у нас больше нет отдельных потоков, ожидающих ответов на ввод-вывод, таких как вызовы базы данных. То есть мы максимизируем использование процессора и пропускной способности. Для высокопроизводительных приложений это явное преимущество. Это реализуется с идеей, что вызов функции может вернуть Future, которое не является фактическим результатом вызова, а скорее обещанием вернуть результат в какой-то момент в будущем. В какой-то момент в будущем получается возвращаемое значение, которое запускает функцию. Это означает, что потоки процессора не ждут завершения вызовов баз данных или REST и могут заниматься чем-то другим.Краткость выражения
Разработчики программного обеспечения хотят иметь возможность изящно выражать сложные идеи. Функциональное программирование позволяет делать это лаконично. Например, общие конструкции, такие как циклы for, могут быть заменены потоками, которые абстрагируют общие операции for, для которых используются циклы. Нет никаких сомнений в том, что добавление функций Lambda и потоков в Java расширило возможности для выражения идей, которые ранее были невозможны.Почему бы не стать функциональным?
Просто повторю вышеизложенное: у функционального кодирования есть много преимуществ, поэтому в этой статье мы не пытаемся обобщить все в один случай и сказать, что вам обязательно нужно заниматься функциональным программированием или наоборот. Такое решение нужно принимать с четким пониманием причин перехода и потенциальных проблем.Интуитивно понимать всегда трудно
При написании кода вы пытаетесь общаться с компьютером? Если вам так важно общение с компьютером, почему бы не писать машинным кодом? Разумеется, это очень сложно, поэтому для облегчения придумали компьютерные языки. Они также позволяют программистам создавать выражения, понятные другим программистам. Поскольку программное обеспечение становится больше и сложнее, нам нужны стратегии для управления сложностью. Мы достигаем этого за счет абстракций и сокрытия информации. Класс, который вы используете в Java для отправки электронной почты, довольно сложен, но интерфейс этого класса прост. Он скрывает детальную реализацию, открывая нам только внешнюю сторону управления. Особенности языка, такие как фигурные скобки и квадратные скобки, сообщают нам структуру, такую как условные операторы и циклы. Только теперь мы перемещаем циклы, или, вернее, рекурсию, и условия в функции:
for( String item : items ) {
System.out.println(item);
}
Выходит:
items.foreach( item -> System.out.println(item) );
Потоковый и лямбда-подход, безусловно, короче. Вы можете выразить ту же функциональность с меньшим количеством кода. Проблема в том, что теперь мы скрываем фактическое поведение внутри методов, которые мы должны знать. Циклы в Java используют ключевые слова. С другой стороны, лямбда-функции могут реализовывать различные формы рекурсии, и только имя здесь указывает на то, что оно делает. Например:
boo.fooble( item -> System.out.println(item) );
Вы больше не можете просто читать код, чтобы понять структуру. Это затрудняет отслеживание потока выполнения.
Другая особенность — цепочка функций, когда результат одной функции является вводом следующей без назначения промежуточной переменной.
boolean result = boo
.fooble( /*some code*/ )
.bobble( /*some code*/)
.goober( /*some code*/);
Для автора этого кода это может иметь смысл, потому что он вроде бы написал каждую функцию и знает, что она делает. Однако для тех, кто плохо знаком с кодом, это мало что говорит о параметрах, процессах или возвращаемых значениях каждой функции. Но если вы напишете то же самое в чем-то, что присваивает типы, вы получите:
Car car = boo.fooble( /*some parameters*/);
Tyre tyre = car.bobble( /*some parameters*/);
int pressure = tyre.goober( /*some parameters*/);
Возможно, это не идеальная аналогия, поскольку параметры и анонимные функции — это не одно и то же, но смысл здесь в том, что длинное предложение с неизвестными результатами и параметрами трудно читать без более глубокого понимания того, что делают функции, описанные ниже.
И поэтому возможно, что функциональное программирование одновременно очень выразительно в удивительно коротких сегментах кода, но не поддается пониманию для людей, плохо знакомых с программным обеспечением.
Смысл классов и интерфейсов связан с сокрытием данных, с созданием повторно используемых фрагментов кода, которые не требуют от разработчика понимания или, возможно, даже просмотра реализации. Они существуют для того, чтобы разработчики могли работать с большими сложными системами без головной боли. Это удобный способ организации кода, связанного с конкретными сущностями.
Тем не менее, я плохо понимаю, как функциональное программирование помогает структурировать большие сложные проекты. Вероятно, этому есть субъективные причины.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ