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

Сначала давай быстро пробежимся по терминам, а потом сравним эти стили программирования и посмотрим, как они отражаются в Java и могут ли сосуществовать в данном языке.

Функциональное программирование — это парадигма, в которой процесс вычисления определяется вычислением значений функций в математическом их понимании, а не в понимании подпрограмм, как в процедурном программировании. То есть в этих двух парадигмах значение слова “функция” трактуется по-разному. Это нужно запомнить и не путать. В Java ты с этим не запутаешься: функции в значении подпрограмм — это “методы”, а функции как математические функции — это просто “функции” (также: лямбда-функции или method reference).

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

Положительные стороны функционального программирования

  • Повышение надежности кода
  • Удобство организации модульного тестирования
  • Возможности оптимизации кода при компиляции
  • Возможности параллелизма

Отрицательные стороны функционального программирования

Недостатки функционального программирования вытекают из все тех же его особенностей:

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

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

Краткая справка по функциональному программированию завершена, теперь перейдем непосредственно к стилям программирования.

Императивное программирование — это парадигма программирования, для которой характерны следующие черты:

  • В исходном коде программы записываются инструкции (команды).

  • Инструкции должны выполняться последовательно.

  • Данные, получаемые при выполнении предыдущих инструкций, могут читаться из памяти последующими инструкциями.

  • Данные, полученные при выполнении инструкции, могут записываться в память.

Основные черты императивных языков:

  • Использование именованных переменных.
  • Использование оператора присваивания.
  • Использование составных выражений.
  • Использование подпрограмм.

Императивная программа похожа на приказы, выражаемые повелительным наклонении в естественных языках, то есть представляют собой последовательность команд.

К императивным языкам программирования относятся C, C++.

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

Другой язык декларативного программирования — SQL.

Чтобы сравнить два стиля программирования, рассмотрим пример из реальной жизни: как объяснить человек, как добраться до какого-то места?

Представим ситуацию: к нам подошел человек на улице и спросил: “Как пройти к музею N?”

При императивном подходе мы бы объясняли ему алгоритм того, как добраться туда пешком:

  • сейчас развернуться
  • идти 2 квартала по прямой
  • повернуть направо

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

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

Во время своего долгого развития язык расширял свою объектно-ориентированную модель для того, чтобы его пользователи получали различные инструменты и могли выбрать лучший для решения каждой конкретной задачи.

Поэтому на данный момент Java поддерживает как и императивный (например, написание кода вызовов методов), так и декларативный подход (например, аннотации, доступные в Runtime).

Подведем итог:

  • Существуют различные парадигмы программирования.

  • Есть декларативный и императивный подходы.

  • Выбирать стоит тот, который лучше будет справляться с решением поставленных задач.

  • Java — мультипарадигменный язык, поддерживающий оба подхода.