Какие знаешь современные стили написания кода?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Какие современные стили написания кода знаешь?
В современной Java разработке используются несколько подходов и стилей, которые влияют на архитектуру, читаемость и поддерживаемость кода. Расскажу о наиболее актуальных.
1. Functional Programming Style (Функциональный стиль)
Начиная с Java 8, появилась поддержка функционального программирования через Lambda expressions и Stream API:
public class FunctionalStyle {
static class User {
private String name;
private int age;
private List<String> skills;
// Конструктор и геттеры опущены
}
// ❌ Императивный стиль (старый)
public List<String> getSkillsOld(List<User> users) {
List<String> result = new ArrayList<>();
for (User user : users) {
if (user.getAge() > 25) {
for (String skill : user.getSkills()) {
if (!result.contains(skill)) {
result.add(skill);
}
}
}
}
return result;
}
// ✅ Функциональный стиль (современный)
public List<String> getSkillsNew(List<User> users) {
return users.stream()
.filter(user -> user.getAge() > 25)
.flatMap(user -> user.getSkills().stream())
.distinct()
.sorted()
.collect(Collectors.toList());
}
}
2. Records (Java 16+)
Records — это краткий способ создания immutable data classes:
// ❌ Старый способ
public class PersonOld {
private final String name;
private final int age;
private final String email;
public PersonOld(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
public String getName() { return name; }
public int getAge() { return age; }
public String getEmail() { return email; }
@Override
public boolean equals(Object o) { /* ... */ }
@Override
public int hashCode() { /* ... */ }
@Override
public String toString() { /* ... */ }
}
// ✅ Новый способ с Records
public record Person(
String name,
int age,
String email
) {
// Всё генерируется автоматически!
// equals, hashCode, toString, getters
}
// Использование
public class RecordExample {
public static void main(String[] args) {
Person person = new Person("Иван", 30, "ivan@example.com");
System.out.println(person.name());
System.out.println(person);
}
}
3. Sealed Classes (Java 17+)
Sealed classes позволяют контролировать, какие классы могут наследовать:
// Определяем, какие классы могут наследовать Shape
public sealed class Shape permits Circle, Rectangle, Triangle {
abstract double getArea();
}
public final class Circle extends Shape {
private double radius;
@Override
double getArea() {
return Math.PI * radius * radius;
}
}
public final class Rectangle extends Shape {
private double width, height;
@Override
double getArea() {
return width * height;
}
}
public final class Triangle extends Shape {
private double a, b, c;
@Override
double getArea() { /* ... */ }
}
// Использование
public class SealedExample {
public static void main(String[] args) {
Shape shape = new Circle();
// Компилятор знает все возможные типы!
}
}
4. Pattern Matching (Java 16+, улучшается в каждой версии)
Pattern Matching упрощает работу с instanceof и switch:
// ❌ Старый способ
public void processOld(Object obj) {
if (obj instanceof String) {
String str = (String) obj;
System.out.println("Строка: " + str.toUpperCase());
} else if (obj instanceof Integer) {
Integer num = (Integer) obj;
System.out.println("Число: " + (num * 2));
}
}
// ✅ Новый способ с Pattern Matching
public void processNew(Object obj) {
if (obj instanceof String str) {
System.out.println("Строка: " + str.toUpperCase());
} else if (obj instanceof Integer num) {
System.out.println("Число: " + (num * 2));
}
}
// ✅ Switch с Pattern Matching (Java 17+)
public String getTypeInfo(Object obj) {
return switch (obj) {
case String str -> "Строка длины " + str.length();
case Integer num -> "Число: " + (num * 2);
case Double d -> "Дробь: " + d.toString();
case null -> "null";
default -> "Неизвестный тип";
};
}
5. Domain-Driven Design (DDD)
Структура приложения, ориентированная на бизнес-логику:
// Domain Layer
public record OrderId(String value) {}
public record Money(BigDecimal amount, Currency currency) {}
public class Order {
private OrderId id;
private List<OrderItem> items;
private Money totalPrice;
public void addItem(OrderItem item) {
// Бизнес-логика в домене
if (items.size() >= 100) {
throw new DomainException("Максимум 100 товаров");
}
items.add(item);
recalculateTotal();
}
}
// Application Layer
@Service
public class CreateOrderUseCase {
private OrderRepository repository;
public void execute(CreateOrderCommand cmd) {
Order order = new Order(/* ... */);
// Бизнес-логика выполнена, сохраняем
repository.save(order);
}
}
// Infrastructure Layer
@Repository
public class OrderRepositoryJpa implements OrderRepository {
private JpaRepository<OrderEntity, Long> jpa;
@Override
public void save(Order order) {
// Трансляция в JPA сущность
jpa.save(toEntity(order));
}
}
6. Clean Architecture / Hexagonal Architecture
Отделение бизнес-логики от деталей реализации:
// Core business logic (не зависит от DB, HTTP и т.д.)
public class PaymentService {
private PaymentRepository repository;
public void processPayment(Payment payment) {
if (payment.getAmount().isNegative()) {
throw new InvalidPaymentException();
}
repository.save(payment);
}
}
// Adapter for Database
@Repository
public class PaymentRepositoryPostgres implements PaymentRepository {
private JdbcTemplate jdbc;
@Override
public void save(Payment payment) {
// PostgreSQL специфичный код
}
}
// Adapter for HTTP
@RestController
@RequestMapping("/api/payments")
public class PaymentController {
private PaymentService service;
@PostMapping
public ResponseEntity<?> create(@RequestBody PaymentRequest req) {
service.processPayment(/* ... */);
return ResponseEntity.ok().build();
}
}
7. Convention over Configuration
Вместо явной конфигурации используются соглашения (Spring Boot подход):
// ✅ Современный подход (Spring Boot)
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return /* ... */;
}
}
// Всё работает без явной конфигурации!
8. Immutability by Default
Современный подход — делать объекты неизменяемыми по умолчанию:
public record Config(
String host,
int port,
boolean ssl
) {}
public class User {
private final String name; // final
private final List<String> tags; // Неизменяемый список
public User(String name, List<String> tags) {
this.name = name;
this.tags = List.copyOf(tags); // Защита от изменений
}
// Вместо setters используем copy() для создания новых объектов
public User withName(String newName) {
return new User(newName, this.tags);
}
}
Резюме современных трендов
- Функциональное программирование — Stream API, Lambda
- Records — краткий синтаксис для data classes
- Sealed classes — контроль наследования
- Pattern Matching — упрощение работы с типами
- DDD/Clean Architecture — организация по бизнес-логике
- Immutability — неизменяемость объектов
- Convention over Configuration — минимум явной конфигурации
- Dependency Injection — слабая связанность через DI контейнеры
Эти подходы делают код более читаемым, поддерживаемым и менее подверженным ошибкам.