Записи Java, введені в Java 14 як функція попереднього перегляду і стандартизовані в Java 16, спрощують створення незмінних носіїв даних, зменшуючи кількість шаблонного коду. Але їхня корисність не обмежується лише простими DTO. Записи можна розширювати та поєднувати з іншими функціями Java для отримання потужних можливостей.
У цій статті ми розглянемо, як підняти використання записів Java на новий рівень за допомогою практичних прикладів та фрагментів коду.
1. Загальний випадок використання та пояснення записів
Записи — це незмінні класи даних, які спрощують моделювання простих об'єктів даних. Вони автоматично генерують шаблонний код, такий як конструктори, методи equals()
, hashCode()
і toString()
, що робить їх ідеальними для DTO, об'єктів конфігурацій та носіїв значень.
Приклад:
Уявіть, що вам потрібно зберігати пару координат.
public record Point(int x, int y) {}
public class Main {
public static void main(String[] args) {
Point point = new Point(10, 20);
System.out.println(point); // Point[x=10, y=20]
System.out.println("X: " + point.x()); // X: 10
System.out.println("Y: " + point.y()); // Y: 20
}
}
Основні переваги:
- Стиснутий код: Відсутність шаблонного коду.
- Незмінність: Поля за замовчуванням є фінальними.
- Читабельність: Орієнтація на модель даних, а не її реалізацію.
2. Налаштування конструктора
Канонічні конструктори в записях можна налаштовувати для додавання логіки перевірки або трансформації.
Приклад:
Давайте переконаємося, що вік Person
не може бути від'ємним.
public record Person(String name, int age) {
public Person {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
}
}
public class Main {
public static void main(String[] args) {
try {
Person person = new Person("Alice", -5); // Throws IllegalArgumentException
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage()); // Age cannot be negative
}
}
}
3. Використання записів для бібліотек валідації даних
Поєднайте записи з бібліотеками, такими як Hibernate Validator, для перевірки полів на рівні валідації.
Приклад:
public record User(
@NotNull String username,
@Email String email,
@Min(18) int age
) {}
4. Покращення читабельності з вкладеними записами
Групуйте пов'язані дані за допомогою вкладених записів.
Приклад:
public record Order(int id, Item item) {
public record Item(String name, int quantity, double price) {}
}
5. Додавання власних методів для бізнес-логіки
Хоча записи переважно використовуються для зберігання даних, ви можете розширити їх бізнес-логікою, додаючи власні методи.
Приклад:
Уявімо запис Circle
, що представляє геометричні дані. Ми можемо додати методи для обчислення площі та периметра безпосередньо в записі.
public record Circle(double radius) {
public double area() {
return Math.PI * radius * radius;
}
public double circumference() {
return 2 * Math.PI * radius;
}
}
public class Main {
public static void main(String[] args) {
Circle circle = new Circle(5);
System.out.println("Area: " + circle.area()); // Area: 78.53981633974483
System.out.println("Circumference: " + circle.circumference()); // Circumference: 31.41592653589793
}
}
Інтеграція з шаблоном Builder і обробка JSON
Записи Java безперешкодно інтегруються з шаблоном Builder та бібліотеками для роботи з JSON, такими як Jackson або Gson, для серіалізації та десеріалізації.
## Приклад:
@Builder
@Jacksonized
public record Person(String name, int age) {}
public class Main {
public static void main(String[] args) {
Person person = Person.builder()
.name("Alice")
.age(25)
.build();
System.out.println(person);
}
}
```
Приклад: Обробка JSON з Jackson
public record Product(String name, double price) {}
public class Main {
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
// Серіалізація
Product product = new Product("Laptop", 1200.50);
String json = objectMapper.writeValueAsString(product);
System.out.println(json); // {"name":"Laptop","price":1200.5}
// Десеріалізація
Product deserialized = objectMapper.readValue(json, Product.class);
System.out.println(deserialized);
}
}
7. Використання статичних полів для констант
Записи можуть містити статичні поля та методи для визначення констант або утилітних методів.
Приклад:
public record Temperature(double celsius) {
public static Temperature fromFahrenheit(double fahrenheit) {
return new Temperature((fahrenheit - 32) * 5 / 9);
}
}
8. Інтеграція з Spring Boot
Записи є природним вибором для Spring Boot, оскільки вони спрощують DTO, конфігураційні властивості та об'єкти запитів/відповідей.
Приклад: Конфігураційні властивості
@ConfigurationProperties(prefix = "app")
public record AppConfig(String name, String version) {}
Приклад: DTO для запитів/відповідей
public record UserRequest(String username, String email) {}
@RestController
@RequestMapping("/users")
public class UserController {
@PostMapping
public ResponseEntity createUser(@RequestBody UserRequest userRequest) {
return ResponseEntity.ok("User created: " + userRequest);
}
}
9. Використання з функціональним програмуванням
Незмінність записів робить їх ідеальними для функціонального програмування. Поєднайте їх з потоками Java для створення ланцюгів обробки та фільтрації даних.
Приклад: Фільтрація за допомогою потоків
public record Person(String name, int age) {}
public class Main {
public static void main(String[] args) {
List people = List.of(new Person("Alice", 25), new Person("Bob", 15));
List adults = people.stream()
.filter(person -> person.age() >= 18)
.collect(Collectors.toList());
System.out.println(adults);
}
}
Висновок
Записи Java — це набагато більше, ніж просто носії даних. Поєднуючи їх з передовими функціями та бібліотеками Java, ви можете створювати надійні, лаконічні та сучасні додатки. Незалежно від того, чи використовуєте ви їх для конфігурації, серіалізації, тестування чи функціонального програмування, записи є потужним інструментом у вашому арсеналі Java.
Перекладено з: Unlocking the Full Potential of Java Records