← Назад к вопросам

Что такое декларативный код?

2.0 Middle🔥 171 комментариев
#SOLID и паттерны проектирования

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое декларативный код?

Декларативный код — это стиль программирования, когда ты описываешь ЧТО нужно сделать, а не КАК это сделать. Противоположность — императивный код, где ты пошагово описываешь все действия.

Декларативный vs Императивный

Пример 1: Фильтрация списка

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

public class FilteringExample {
    
    // ❌ ИМПЕРАТИВНЫЙ — КАК это делать
    public List<Integer> filterEvenNumbersImperative(List<Integer> numbers) {
        List<Integer> result = new ArrayList<>();
        for (int i = 0; i < numbers.size(); i++) {
            if (numbers.get(i) % 2 == 0) {
                result.add(numbers.get(i));
            }
        }
        return result;
    }
    
    // ✅ ДЕКЛАРАТИВНЫЙ — ЧТО нужно сделать
    public List<Integer> filterEvenNumbersDeclarative(List<Integer> numbers) {
        return numbers.stream()
            .filter(n -> n % 2 == 0)
            .collect(Collectors.toList());
    }
}

Пример 2: Трансформация данных

public class TransformationExample {
    
    // ❌ ИМПЕРАТИВНЫЙ
    public List<String> convertToUpperImperative(List<String> words) {
        List<String> result = new ArrayList<>();
        for (String word : words) {
            result.add(word.toUpperCase());
        }
        return result;
    }
    
    // ✅ ДЕКЛАРАТИВНЫЙ
    public List<String> convertToUpperDeclarative(List<String> words) {
        return words.stream()
            .map(String::toUpperCase)
            .collect(Collectors.toList());
    }
}

Декларативное программирование с SQL

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

// ❌ ИМПЕРАТИВНЫЙ (Java код вместо SQL)
public List<User> getUsersWithHighSalary() {
    List<User> allUsers = database.getAllUsers();
    List<User> result = new ArrayList<>();
    
    for (User user : allUsers) {
        if (user.getSalary() > 50000) {
            if (!result.contains(user)) {
                result.add(user);
            }
        }
    }
    
    return result;
}

// ✅ ДЕКЛАРАТИВНЫЙ (SQL запрос)
String sql = "SELECT DISTINCT u.* FROM users u WHERE u.salary > 50000";
// Ты описал ЧТО тебе нужно, а БД знает КАК это получить

Spring Data JPA — Декларативный подход

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;

// ✅ ДЕКЛАРАТИВНЫЙ — описываем намерение, не реализацию
public interface UserRepository extends JpaRepository<User, Long> {
    
    // Просто объявляем метод, Spring понимает намерение
    List<User> findByAgeGreaterThan(int age);
    
    // Более сложный запрос, но всё равно декларативный
    @Query("SELECT u FROM User u WHERE u.salary > :salary AND u.department = :dept")
    List<User> findHighEarnersInDepartment(BigDecimal salary, String dept);
}

// Использование
public class UserService {
    private UserRepository userRepository;
    
    public List<User> getSeniors() {
        // ТЫ ОПИСАЛ ЧТО нужно, Spring/Hibernate справится КАК
        return userRepository.findByAgeGreaterThan(50);
    }
}

Декларативный стиль с Stream API

import java.util.List;
import java.util.stream.Collectors;
import java.util.Comparator;
import java.util.function.Predicate;

public class StreamExample {
    
    // ❌ ИМПЕРАТИВНЫЙ
    public void processOrdersImperative(List<Order> orders) {
        List<Order> validOrders = new ArrayList<>();
        for (Order order : orders) {
            if (order.getStatus().equals("PENDING")) {
                validOrders.add(order);
            }
        }
        
        validOrders.sort((o1, o2) -> o1.getAmount().compareTo(o2.getAmount()));
        
        for (Order order : validOrders) {
            System.out.println("Processing: " + order.getId());
        }
    }
    
    // ✅ ДЕКЛАРАТИВНЫЙ
    public void processOrdersDeclarative(List<Order> orders) {
        orders.stream()
            .filter(o -> o.getStatus().equals("PENDING"))
            .sorted(Comparator.comparing(Order::getAmount))
            .forEach(o -> System.out.println("Processing: " + o.getId()));
    }
}

Декларативная конфигурация (Spring Boot)

import org.springframework.context.annotation.Configuration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

// ❌ ИМПЕРАТИВНЫЙ подход (old-style)
public class OldConfig {
    public void setupDatabase() {
        // Вручную инициализируем DriverManager
        // Вручную создаём DataSource
        // Вручную настраиваем ConnectionPool
    }
}

// ✅ ДЕКЛАРАТИВНЫЙ подход
@Configuration
public class DeclarativeConfig {
    // Spring магически создаст DataSource на основе application.properties
    // spring.datasource.url=jdbc:postgresql://localhost/mydb
    // spring.datasource.username=user
    // Нам не нужно писать ничего!
}

Декларативная валидация

import javax.validation.constraints.*;

// ❌ ИМПЕРАТИВНЫЙ подход
public class User {
    private String email;
    private int age;
    
    public void validate() {
        if (email == null || !email.contains("@")) {
            throw new IllegalArgumentException("Invalid email");
        }
        if (age < 18 || age > 120) {
            throw new IllegalArgumentException("Invalid age");
        }
    }
}

// ✅ ДЕКЛАРАТИВНЫЙ подход
public class UserDeclarative {
    @Email(message = "Email должен быть валидным")
    private String email;
    
    @Min(18)
    @Max(120)
    private int age;
    
    @NotBlank
    private String name;
    
    // Spring/Hibernate Validator проверит автоматически!
}

Декларативное описание REST API

import org.springframework.web.bind.annotation.*;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

// ✅ ДЕКЛАРАТИВНЫЙ подход с аннотациями
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    
    @GetMapping("/{id}")
    @ApiOperation("Get user by ID")
    public ResponseEntity<User> getUser(
            @PathVariable
            @ApiParam("User ID")
            Long id) {
        return ResponseEntity.ok(userService.findById(id));
    }
    
    @PostMapping
    @ApiOperation("Create new user")
    public ResponseEntity<User> createUser(
            @RequestBody
            @Valid User user) {
        return ResponseEntity.status(201).body(userService.save(user));
    }
}

Преимущества декларативного кода

  1. Читаемость — сразу ясна намерение
  2. Меньше ошибок — меньше логики = меньше багов
  3. Легче тестировать — сосредоточиться на намерении
  4. Параллелизм — Stream API может автоматически параллелить
  5. Оптимизация — компилятор/runtime может оптимизировать

Недостатки декларативного кода

  1. Производительность — иногда медленнее, чем оптимизированный императивный
  2. Контроль — меньше контроля над деталями выполнения
  3. Отладка — сложнее дебагить (stacktrace может быть запутанным)

Когда использовать декларативный стиль

// ✅ Используй декларативный для:
// - Фильтрации и трансформации данных (Stream API)
// - Конфигурации (аннотации, properties)
// - Валидации
// - Database queries (JPA Specifications, QueryDSL)
// - UI компонентов (React-like подход)

// ⚠️ Иногда нужен императивный для:
// - Сложной бизнес-логики
// - Критичной производительности
// - Когда нужен полный контроль над выполнением

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

public class ReportService {
    
    // ✅ ДЕКЛАРАТИВНЫЙ подход
    public List<MonthlyReport> generateReports(List<Transaction> transactions) {
        return transactions.stream()
            .filter(t -> t.getStatus().equals("COMPLETED"))
            .filter(t -> t.getAmount() > 0)
            .collect(Collectors.groupingBy(
                t -> YearMonth.from(t.getDate()),
                Collectors.collectingAndThen(
                    Collectors.mapping(Transaction::getAmount, Collectors.toList()),
                    amounts -> new MonthlyReport(
                        amounts.stream().mapToDouble(Double::doubleValue).sum(),
                        amounts.size()
                    )
                )
            ))
            .entrySet().stream()
            .map(e -> new MonthlyReport(e.getKey(), e.getValue()))
            .sorted(Comparator.comparing(MonthlyReport::getMonth))
            .collect(Collectors.toList());
    }
}

Декларативный код — современный стандарт в Java разработке. Стремись к нему!