Records (Java 16+)
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 51 из 87.
При создании простых классов для передачи данных вы часто пишете повторяющийся шаблонный код: приватные поля, конструктор, геттеры, toString(), equals() и hashCode(). В Java 16 появились records, чтобы избавиться от этой рутины.
Запись — это специальный класс, предназначенный для хранения неизменяемых данных. Вы объявляете её с помощью ключевого слова record, за которым следует список компонентов:
record Person(String name, int age) { }
// Эта единственная строка автоматически предоставляет:
// - private final поля: name и age
// - конструктор: Person(String name, int age)
// - методы доступа: name() и age()
// - toString(), equals(), и hashCode()Использование записи — это просто:
Person p = new Person("Alice", 30);
System.out.println(p.name()); // Alice
System.out.println(p.age()); // 30
System.out.println(p); // Person[name=Alice, age=30]Обратите внимание, что методы доступа не используют префикс get — они просто называются так же, как и поля. Записи (records) неявно являются final, поэтому их нельзя расширять. Все поля также являются final, что делает записи неизменяемыми по своей природе.
Вы можете добавлять пользовательские методы и переопределять автоматически сгенерированные, если это необходимо. Вы также можете добавить валидацию в компактном конструкторе:
record Person(String name, int age) {
public Person {
if (age < 0) throw new IllegalArgumentException("Age cannot be negative");
}
}Записи идеально подходят для DTO, ответов API или любого сценария, где вам нужен простой неизменяемый контейнер данных без написания шаблонного кода.
Задание
ЛегкоДавайте создадим систему бронирования билетов в кино, которая продемонстрирует элегантность записей (records) в Java. Вы увидите, как записи устраняют шаблонный код, позволяя при этом добавлять пользовательские методы и валидацию.
Вы организуете свой код в трех файлах:
Movie.java: Создайте запись, представляющую фильм, с тремя компонентами:title(String),genre(String) иdurationMinutes(int). Добавьте пользовательский методgetFormattedDuration(), который возвращает длительность в удобном формате:[hours]h [minutes]m(например, 142 минуты превращаются в2h 22m). Используйте целочисленное деление и остаток от деления для вычисления часов и оставшихся минут.Ticket.java: Создайте запись, представляющую билет в кино, с тремя компонентами:movie(Movie),seatNumber(String) иprice(double). Добавьте компактный конструктор, который проверяет цену — если цена меньше или равна нулю, выбросьте исключениеIllegalArgumentExceptionс сообщением"Price must be positive". Также добавьте пользовательский методprintTicket(), который возвращает многострочную строку:========== TICKET ========== Movie: [movie title] Genre: [movie genre] Duration: [formatted duration from movie] Seat: [seatNumber] Price: $[price] ============================Main.java: Объедините вашу систему бронирования! Вы получите пять входных данных: название фильма (String), жанр (String), длительность в минутах (int), номер места (String) и цена билета (double).Создайте запись Movie с первыми тремя входными данными, затем создайте запись Ticket с фильмом, номером места и ценой. Выведите результат вызова
printTicket()для вашего билета.
Вы получите пять входных данных по порядку: название фильма, жанр, длительность (минуты), номер места и цена.
Обратите внимание, насколько чище записи по сравнению с традиционными классами — нет необходимости писать конструкторы, геттеры, toString(), equals() или hashCode(). Компактный конструктор позволяет добавлять валидацию без повторного присваивания полей, и вы все равно можете добавлять пользовательские методы при необходимости!
Шпаргалка
Java 16 представила записи (records), чтобы исключить шаблонный код для простых классов, переносящих данные. Запись — это специальный класс, предназначенный для хранения неизменяемых данных.
Объявите запись с помощью ключевого слова record, за которым следует список компонентов:
record Person(String name, int age) { }Это автоматически обеспечивает:
- Приватные финальные поля
- Конструктор
- Методы доступа (без префикса
get) toString(),equals(), иhashCode()
Использование записи:
Person p = new Person("Alice", 30);
System.out.println(p.name()); // Alice
System.out.println(p.age()); // 30
System.out.println(p); // Person[name=Alice, age=30]Записи неявно являются final и не могут быть расширены. Все поля являются final, что делает записи неизменяемыми по своей природе.
Добавьте валидацию с помощью компактного конструктора:
record Person(String name, int age) {
public Person {
if (age < 0) throw new IllegalArgumentException("Age cannot be negative");
}
}В записи можно добавлять пользовательские методы:
record Person(String name, int age) {
public String getInfo() {
return name + " is " + age + " years old";
}
}Попробуйте сами
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Чтение входных данных
String title = scanner.nextLine();
String genre = scanner.nextLine();
int durationMinutes = Integer.parseInt(scanner.nextLine());
String seatNumber = scanner.nextLine();
double price = Double.parseDouble(scanner.nextLine());
// TODO: Создайте запись Movie с полями title, genre и durationMinutes
// TODO: Создайте запись Ticket с полями movie, seatNumber и price
// TODO: Выведите билет, используя метод printTicket()
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»