0Pricing
Java Academy · Урок

Знакомство с записями

Объявляйте записи как лаконичные неизменяемые контейнеры данных и изучайте их автоматически создаваемые элементы.

«Знакомство с записями» — бесплатный урок Java Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.

Знакомство с записями

Записи Java (Java 16 и новее) — это лаконичный способ объявлять неизменяемые классы-носители данных. Они автоматически создают шаблонный код: конструктор, методы доступа, equals, hashCode и toString.

Объявление записи

Используйте ключевое слово record, затем укажите имя записи и список компонентов. Каждый компонент становится закрытым неизменяемым полем и публичным методом доступа.

record Point(double x, double y) {}

Point p = new Point(3.0, 4.0);
System.out.println(p.x());      // 3.0 (accessor, not getX())
System.out.println(p.y());      // 4.0
System.out.println(p);          // Point[x=3.0, y=4.0]
System.out.println(p.equals(new Point(3.0, 4.0))); // true

Автоматически создаваемые элементы

Компилятор автоматически создаёт для каждой записи канонический конструктор, публичные методы доступа, equals(), hashCode() и toString(). Вам не нужно писать их вручную.

record Product(String name, double price, int stock) {}

Product p1 = new Product("Widget", 9.99, 100);
Product p2 = new Product("Widget", 9.99, 100);

System.out.println(p1.name());          // Widget
System.out.println(p1.price());         // 9.99
System.out.println(p1.equals(p2));      // true (structural)
System.out.println(p1.hashCode() == p2.hashCode()); // true
System.out.println(p1);                 // Product[name=Widget, price=9.99, stock=100]

Записи неизменяемы

Компоненты записи имеют модификатор final. После создания записи их нельзя изменить — записи моделируют неизменяемые объекты-значения.

record Money(long cents, String currency) {}

Money price = new Money(999, "USD");
// price.cents = 500; // Compile error — final field!

// To "update" a record, create a new one
Money discounted = new Money(price.cents() - 100, price.currency());
System.out.println(discounted); // Money[cents=899, currency=USD]

Записи наследуются только от Object

Записи неявно наследуются от java.lang.Record и не могут наследоваться от других классов. Они могут реализовывать интерфейсы.

interface Describable { String describe(); }

record Circle(double radius) implements Describable {
    public String describe() {
        return String.format("Circle with radius %.1f", radius);
    }

    public double area() {
        return Math.PI * radius * radius;
    }
}

Circle c = new Circle(5.0);
System.out.println(c.describe()); // Circle with radius 5.0
System.out.printf("Area: %.2f%n", c.area()); // Area: 78.54

Записи в коллекциях

Поскольку записи корректно реализуют equals и hashCode на основе всех компонентов, их можно использовать как ключи отображений и элементы множеств.

import java.util.*;

record Coordinate(int row, int col) {}

Map<Coordinate, String> grid = new HashMap<>();
grid.put(new Coordinate(0, 0), "Origin");
grid.put(new Coordinate(1, 2), "Target");

// Lookup with equal-valued record works correctly
System.out.println(grid.get(new Coordinate(0, 0))); // Origin
System.out.println(grid.get(new Coordinate(1, 2))); // Target

Set<Coordinate> visited = new HashSet<>();
visited.add(new Coordinate(3, 3));
System.out.println(visited.contains(new Coordinate(3, 3))); // true

Записи как DTO

Записи идеально подходят для объектов передачи данных (DTO) в REST API: они передают данные между слоями, не добавляя поведения.

record CreateUserRequest(String email, String displayName, String plan) {}

record UserResponse(long id, String email, String displayName,
                    String plan, String createdAt) {}

// Simulating a service call
static UserResponse createUser(CreateUserRequest req) {
    long id = 42L;
    return new UserResponse(id, req.email(), req.displayName(),
        req.plan(), java.time.Instant.now().toString());
}

CreateUserRequest req = new CreateUserRequest("alice@example.com", "Alice", "PRO");
UserResponse resp = createUser(req);
System.out.println(resp);

Декомпозиция записей

Записи хорошо сочетаются с сопоставлением с образцом. Их можно декомпозировать в выражениях switch (Java 21 и новее).

sealed interface Shape permits Circle, Rectangle, Triangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}
record Triangle(double base, double height) implements Shape {}

static double area(Shape s) {
    return switch (s) {
        case Circle(double r)            -> Math.PI * r * r;
        case Rectangle(double w, double h) -> w * h;
        case Triangle(double b, double h) -> 0.5 * b * h;
    };
}

System.out.printf("%.2f%n", area(new Circle(5)));         // 78.54
System.out.printf("%.2f%n", area(new Rectangle(4, 6)));   // 24.00

Сериализация записей

Записи естественным образом реализуют Serializable, если объявить их реализующими этот интерфейс. Они из коробки хорошо работают с библиотеками JSON (Jackson, Gson).

// With Jackson (add @JsonProperty if needed)
import com.fasterxml.jackson.databind.ObjectMapper;

record OrderSummary(String orderId, double total, String status) {}

ObjectMapper mapper = new ObjectMapper();
OrderSummary order = new OrderSummary("ORD-001", 149.99, "SHIPPED");

String json = mapper.writeValueAsString(order);
System.out.println(json);
// {"orderId":"ORD-001","total":149.99,"status":"SHIPPED"}

OrderSummary restored = mapper.readValue(json, OrderSummary.class);
System.out.println(order.equals(restored)); // true

Вложенные записи

Записи могут содержать другие записи в качестве компонентов, формируя сложные неизменяемые графы объектов.

record Address(String street, String city, String country) {}
record Customer(long id, String name, Address address) {}

Address addr = new Address("123 Main St", "New York", "US");
Customer customer = new Customer(1L, "Alice", addr);

System.out.println(customer.name());              // Alice
System.out.println(customer.address().city());   // New York
System.out.println(customer);                    // Customer[id=1, name=Alice, address=Address[street=123 Main St, city=New York, country=US]]

Ограничения записей

Есть несколько ограничений, о которых следует помнить:

  • Нельзя наследоваться от других классов (запись неявно наследуется от Record)
  • Компоненты всегда имеют модификатор final — изменяемое состояние невозможно
  • Нельзя объявлять поля экземпляра за пределами списка компонентов
  • Записи не могут быть абстрактными
// Records CAN have static fields and methods
record Temperature(double celsius) {
    static final double ABSOLUTE_ZERO = -273.15;

    public double toFahrenheit() {
        return celsius * 9.0/5.0 + 32;
    }

    public static Temperature fromFahrenheit(double f) {
        return new Temperature((f - 32) * 5.0/9.0);
    }
}
System.out.println(Temperature.fromFahrenheit(98.6)); // Temperature[celsius=37.0]

Быстрая проверка

Какие элементы компилятор Java автоматически создаёт для записи?

Итоги: знакомство с записями

Главное:

  • Записи объявляют неизменяемые структуры для переноса данных с минимумом шаблонного кода
  • Автоматически создаются: канонический конструктор, методы доступа, equals, hashCode и toString
  • Компоненты имеют модификатор final — записи неизменяемы по своей задумке
  • Записи могут реализовывать интерфейсы, но не могут наследоваться от классов
  • Они идеально подходят для DTO, объектов-значений и ответов API
  • Благодаря структурному равенству корректно работают как ключи HashMap и элементы HashSet

Часто задаваемые вопросы

Урок «Знакомство с записями» бесплатный?

Да — полный текст урока «Знакомство с записями» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.

Чему я научусь в уроке «Знакомство с записями»?

Объявляйте записи как лаконичные неизменяемые контейнеры данных и изучайте их автоматически создаваемые элементы. Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Java Academy?

Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Знакомство с записями»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Java Academy?

Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Знакомство с записями
  2. Компактные конструкторы и проверка данных
  3. Пользовательские методы в записях
  4. Записи, классы и Lombok
← Назад к Java Academy