«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Записи против классов в Java

Записи против классов в Java

Опубликовано 2 ноября 2024 г.
Просматривать:948

Records vs Clases en Java

Если вы уже знакомы с записями в Java, вы можете обнаружить, что их использование очень похоже на использование классов, но есть важные различия, которые необходимо принять во внимание. В этой статье мы рассмотрим различия между записями и классами в Java. Если вы еще не знакомы с записями рекомендую прочитать мою публикацию «Записи в Java: что это такое и как их использовать».

Неизменяемость

Неизменяемый объект — это объект, атрибуты которого нельзя изменить после создания объекта. В случае records они являются неизменяемыми, то есть после создания объекта типа record его атрибуты не могут быть изменены. С другой стороны, класс может быть или не быть неизменяемым, в зависимости от того, как он реализован. Эта часть обеспечивает целостность данных и предотвращает их случайное изменение.

Цель

Классы обычно пишутся просто для хранения данных, например, данных из запроса к базе данных или данных из формы. Во многих случаях эти данные неизменяемы, поскольку достоверность данных необходимо обеспечивать без использования синхронизации. Для этого класс пишется со следующими элементами:

  • Личные атрибуты для каждого поля.
  • Геттеры для каждого поля.
  • Конструктор, инициализирующий все поля.
  • Метод равенства, который сравнивает объекты на предмет равенства.
  • Метод hashCode, который генерирует хэш-код на основе полей.
  • Метод toString, генерирующий строковое представление полей.

Например, если у вас есть класс Person с двумя атрибутами name и LastName, вы можете написать его следующим образом:

public class Person {

    private final String name;
    private final String lastName;

    public Person(String name, String lastName) {
        this.name = name;
        this.lastName = lastName;
    }

    public String getName() {
        return name;
    }

    public String getLastName() {
        return lastName;
    }

    @Override
    public String toString() {
        return "Person{"   "name='"   name   '\''  
                ", lastName='"   lastName   '\''  
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person person)) return false;
        return Objects.equals(getName(), person.getName()) && Objects.equals(getLastName(), person.getLastName());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getName(), getLastName());
    }
}

Это решение задачи, но там много кода того, что собственно нужно. Если бы у класса было больше атрибутов, его пришлось бы писать еще дольше, даже если бы это было сделано с помощью IDE или плагина, такого как GitHub Copilot. Лучшим решением было бы объявить наш класс как класс данных, то есть класс, который только хранит данные и не должен иметь определенного поведения, и именно здесь на помощь приходят записи.

Таким образом класс Person можно переписать как запись следующим образом:

public record Person(String name, String lastName) { }

При этом автоматически создаются методы Equals, hashCode и toString, а также методы получения для каждого из атрибутов.

В чем разница между записью и классом?

  • Неизменяемость: записи являются неизменяемыми, то есть после создания объекта типа запись его атрибуты невозможно изменить. Вместо этого класс может быть или не быть неизменяемым, в зависимости от того, как он был реализован.
  • Сгенерированные методы: records автоматически генерируют методы равенства, hashCode и toString, а также методы получения для каждого из атрибутов. Однако в классах эти методы необходимо реализовывать вручную или с помощью IDE.
  • Использование в ООП: записи не могут наследовать от других классов или расширяться другими классами, но могут реализовывать интерфейсы. С другой стороны, классы могут наследовать от других, расширяться и в целом идеально подходят для охвата концепций объектно-ориентированного программирования.
  • Синтаксис: Синтаксис записи проще, чем синтаксис класса, поскольку его можно определить в одной строке, а для класса требуется несколько строк кода.
  • Цель: записи представляют собой структуру, напоминающую DTO (объект передачи данных), то есть класс, который помогает моделировать неизменяемые данные, со своей стороны, класс — это более общая структура, которая может иметь поведение и состояние.

Когда использовать запись, а когда класс?

Если для хранения данных требуется неизменяемая структура данных и не требуется вносить никаких изменений в атрибуты (она просто рассматривается как объект для переноса информации). С другой стороны, если вам нужна более общая структура, имеющая уникальную логику и конкретные методы, подход к объектно-ориентированной парадигме, применение шаблонов проектирования или работу с JPA или Hibernate и т. д., то вам следует использовать класс.

Дополнительно: запись с изменяемыми атрибутами.

Давайте рассмотрим следующий пример: есть две записи «Продукт» с атрибутами «имя и цена» и «Корзина» с одним атрибутом «продукты» типа ArrayList и несколько методов для получения количества продуктов и общей суммы в корзине.

package org.jordi.example;

public record Product(String name, double price) { }
package org.jordi.example;

import java.util.ArrayList;
import java.util.List;

public record Cart(List products) {

    public Cart() {
        this(new ArrayList());
    }

    public int getQuantity() {
        return this.products.size();
    }

    public double getTotal() {
        return this.products.stream().mapToDouble(Product::price).sum();
    }
}

Проблема в этом случае заключается в том, что каждая из записей сама по себе является неизменяемой, но в случае записи Cart она имеет атрибут типа ArrayList и поскольку по своей природе ArrayList является изменяемым , вы можете изменить содержимое списка после создания экземпляра корзины записей.

package org.jordi.example;

public class Main {
    public static void main(String[] args) {
        Product water = new Product("Water", 15);
        Product milk = new Product("Milk", 22);

        Cart cart = new Cart();
        cart.products().add(water);
        cart.products().add(milk);
        System.out.println("Price: "   cart.getTotal());

        cart.products().clear();
        System.out.println("Quantity: "   cart.getQuantity());
        System.out.println("Price: "   cart.getTotal());
    }
}

Приведенный выше код компилируется без проблем, поскольку изменяется только содержимое списка, но сам атрибут продуктов не изменяется. Это всего лишь пример для конкретного случая, в котором, возможно, нет необходимости, но приятно знать, что это можно сделать.

Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/asjordi/records-vs-clases-en-java-1bb6?1. Если есть какие-либо нарушения, свяжитесь с [email protected], чтобы удалить их.
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3