Что такое функциональное программирование (ФП) и его основные концепции?

«Что такое функциональное программирование (ФП) и его основные концепции?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Ключевые концепции:

Концепция Описание Пример в Java (с использованием Stream API)
Чистые функции Функция, которая для одинаковых входных данных всегда возвращает одинаковый результат и не имеет побочных эффектов. x -> x * x (лямбда для возведения в квадрат)
Неизменяемость Состояние объекта не может быть изменено после создания. Использование final переменных и коллекций из java.util.Collections.unmodifiableList или List.of().
Функции высшего порядка Функции, которые могут принимать функции как аргументы или возвращать их как результат. Методы stream.map(), stream.filter(), stream.reduce().
Рекурсия Часто используется вместо циклов для итерации. Вычисление факториала: int fact(int n) { return n <= 1 ? 1 : n * fact(n-1); }
Ссылочная прозрачность Возможность замены выражения его значением без изменения поведения программы. Свойство чистых функций.

Практический пример на Java:

import java.util.List;
import java.util.stream.Collectors;

public class FPExample {
    public static void main(String[] args) {
        List<Integer> numbers = List.of(1, 2, 3, 4, 5);

        // Функциональный стиль: фильтрация и преобразование
        List<Integer> result = numbers.stream()
            .filter(n -> n % 2 != 0)      // Чистая функция: оставить нечётные
            .map(n -> n * n)              // Чистая функция: возвести в квадрат
            .collect(Collectors.toList()); // Создание нового списка

        System.out.println(result); // Вывод: [1, 9, 25]
        // Исходный список 'numbers' остался неизменным.
    }
}

Зачем это нужно в Java? Даже в объектно-ориентированном языке элементы ФП (лямбды, Stream API) позволяют писать более выразительный, тестируемый и безопасный для многопоточности код, минимизируя изменяемое состояние.