← Назад к вопросам
Что такое декларативный код?
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));
}
}
Преимущества декларативного кода
- Читаемость — сразу ясна намерение
- Меньше ошибок — меньше логики = меньше багов
- Легче тестировать — сосредоточиться на намерении
- Параллелизм — Stream API может автоматически параллелить
- Оптимизация — компилятор/runtime может оптимизировать
Недостатки декларативного кода
- Производительность — иногда медленнее, чем оптимизированный императивный
- Контроль — меньше контроля над деталями выполнения
- Отладка — сложнее дебагить (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 разработке. Стремись к нему!