Рубрики
Без рубрики

Записи Java: краткие и читаемые классы носителей данных

Записи Профессиональным разработчикам Java нужны неизменяемые классы носителей данных для связи… Помечено как java, программирование, производительность, разработка.

Записи

Профессиональным разработчикам Java нужны неизменяемые классы носителей данных для связи с базами данных, веб-сервисами. Нам нужно написать много шаблонного кода для создания простого класса носителей данных, обычно мы реализуем конструктор, средства доступа, equals(), hashCode() и toString(). Этот процесс является повторяющимся и подверженным ошибкам. Разработчики также жалуются, что “Java слишком многословна”.

Классы записей предоставляют способ моделирования данных в java. Примером данных может служить одна строка из таблицы базы данных. Эта функция упрощает кодирование, делает java-код более кратким и читаемым. Это повысит производительность профессиональных разработчиков java. Java 14 представила записи в качестве функции предварительного просмотра, Java 15 вносит некоторые обновления в качестве второго предварительного просмотра, а Java 16 делает это окончательной функцией, после этого никаких изменений в записи.

Общие варианты использования реализации

1. Несколько возвращаемых значений: Часто мы сталкиваемся со случаями, когда мы хотим вернуть несколько значений из метода, для этого нам придется создать класс, содержащий значения, которые нам нужно вернуть. Запись обеспечивает простой способ, а не написание шаблонного кода.

2. Объекты передачи данных (DTO): Разработчики, работающие с базами данных, часто пишут В которые, как правило, используются только для хранения, мы можем снова сократить шаблонный код, используя классы записей java.

Java-код до и после записи

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

class Point
{
 public final int x;   
 public final int y;    
 public Point(int x, int y) { this.x = x; this.y = y; }    
 public int getX() {...}   
 public int getY() {...}   
 public String toString() {...}   
 public boolean equals(Object o) {...}   
 public int hashCode() {...)  
}

Рекордный эквивалент для класса очков следует за одной строкой, ВАУ!

record Point(int x, int y){}

В этом примере имя класса записи – Точка, и оно состоит из 2 компонентов x,y, которые описывают состояние. Класс записи также может иметь тело, позже в этом посте у нас будут такие примеры.

Мы можем использовать команду javap, чтобы увидеть скомпилированный класс:

javac com/jfeatures/jdk16/records/Point.java 
javap -p com/jfeatures/jdk16/records/Point.class

Compiled from "Point.java"
final class com.jfeatures.jdk16.records.Point extends java.lang.Record {
  private final int x;
  private final int y;
  com.jfeatures.jdk16.records.Point(int, int);
  public final java.lang.String toString();
  public final int hashCode();
  public final boolean equals(java.lang.Object);
  public int x();
  public int y();
}

В приведенном выше выводе команды java мы видим, что классы записей имеют:

  1. Частное конечное поле для каждого компонента в объявлении записи (описание состояния). (В приведенном выше примере private final int x, private final int y)
  2. Общедоступный метод доступа для чтения для каждого компонента записи с тем же именем и типом, что и параметр. ( публичный int x(), публичный int y())
  3. Открытый конструктор, имеющий те же аргументы, что и компоненты записи, также называется каноническим конструктором. Этот конструктор инициализирует каждое поле из соответствующего аргумента. ((com.features.jdk16.записи. Точка(int, int))
  4. Реализации equals и хэш-кода, которые говорят, что два класса записей равны, если они одного типа и содержат одно и то же состояние.
  5. Реализация toString, которая включает строковое представление всех компонентов записи с их именами.

Записывайте занятия в деталях

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

  1. Может быть объявлен как верхний уровень или вложенный, может быть общим.
  2. Может реализовывать интерфейсы.
  3. Создаются с помощью нового ключевого слова.
  4. Тело класса записи может объявлять статические методы, статические поля, статические инициализаторы, конструкторы, методы экземпляра и вложенные типы.
  5. Класс записи и отдельные компоненты в описании состояния могут быть аннотированы.
  6. Мы можем определить вложенный класс записей. Вложенная запись неявно статична, поскольку непосредственно заключенный экземпляр может добавить состояние в запись.
  7. Экземпляры классов записей могут быть сериализованы и десериализованы. Сериализация выполняется с использованием компонентов записи, а десериализация выполняется с помощью канонического конструктора. Сериализацию и десериализацию нельзя настроить с помощью обычных средств (методы writeObject, readObject, readObjectNoData, writeExternal или readExternal).

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

Следующий код показывает ошибку компиляции в расширениях, поскольку классы записей неявно являются окончательными.

record Base(int a) { }
record Child(int a, int b) extends Base { }

Аналогичным образом, у нас есть еще несколько ограничений для классов записей.

Ограничения на классы записей можно разделить на 3 категории:

  1. Ограничения, которые гарантируют, что только компоненты класса записей определяют представление

    1. классы записей не могут расширять какой-либо другой класс
    2. классы записей не могут объявлять поля экземпляра, только компоненты записи передают состояние объекта записи.
  2. Ограничения, подчеркивающие, что API записи определяется исключительно ее компонентами записи и не может быть расширен позже другим классом или записью.

    1. классы записей неявно являются окончательными.
    2. классы записей не могут быть абстрактными.
    3. классы записей не могут объявлять собственные методы.
  3. Ограничение, чтобы убедиться, что запись неизменна по умолчанию.

    1. Компоненты записи неявно являются окончательными.

Конструкторы

Классы записей имеют 3 типа конструкторов:

  1. Канонический конструктор
  2. Компактный канонический конструктор
  3. Пользовательский конструктор

Канонический конструктор : Он содержит все компоненты записи. Это объявлено неявно, но также может быть объявлено явно. Начиная с Java 15, если канонический конструктор объявлен неявно, то его модификатор доступа совпадает с классом записи. Если канонический конструктор явно объявлен, то его модификатор доступа должен обеспечивать по крайней мере такой же доступ, как и класс записи.

record Employee(String name, int id) {
       Employee(String name, int id) {
           this.name = name;
           this.id = id;
       }
}

Компактный канонический конструктор : У него нет никаких параметров, он всегда вызывается при определении. Компактная форма помогает разработчикам сосредоточиться на проверке и нормализации параметров. Здесь параметры объявляются неявно, а закрытые поля, соответствующие компонентам записи, назначаются автоматически) в конце конструктора.

record Employee(String name, int id) {
        Employee {
            //validation
            if(name.length()==0) throw new RuntimeException("Nota a valid name");
        }
}

Для класса записи может быть определен только один вне канонического конструктора или компактный канонический конструктор. Определение обоих результатов как сбоя компиляции.

Пользовательский конструктор : Мы также можем создавать пользовательские конструкторы, используя всего несколько параметров из заголовка записи. Поскольку это не канонический конструктор, его первый оператор должен вызывать другой конструктор класса record.

record Employee(String name, int id) {
       public Employee(String name) {
           this(name, 0);
       }
}

Начиная с Java 15, назначение любого из полей экземпляра (компонентов записи) в теле конструктора стало ошибкой во время компиляции. Это разрешено делать только каноническому конструктору.

Обновление аннотации @Override

Java 15 расширяет значение аннотации @Override, включив в нее явно объявленный метод доступа для записи. Теперь ниже приведен действительный код java.

package com.jfeatures.jdk16.records;

public record Employee(String name, int id) {

    @Override
    public int id() {
        return id;
    }

    @Override
    public String name() {
        return name;
    }
}

Локальные записи, перечисления и интерфейсы теперь разрешены в Java

В Java 15 появилась возможность объявлять локальные классы записей, локальные классы перечислений и локальные интерфейсы. Вложенные классы записей и локальные классы записей неявно статичны. Это позволяет избежать добавления непосредственного заключающего экземпляра в состояние класса записи.

public class LocalComponents {
    public static void main(String[] args) {
        System.out.println("Start Test");
        new LocalComponents().instanceMethod();
    }

    void instanceMethod() {
        record LocalRecord(int x, int y) {
            LocalRecord {
                System.out.println("Inside Local Record compact canonical constructors");
            }
        }
        enum LocalEnum {
            VALUE1,
            VALUE2;
        }

        interface LocalInterface extends Cloneable {
        }
    }
}

Для версий до Java 15 приведенный выше код не будет компилироваться. Ниже приведена ошибка компиляции для локального перечисления в приведенном выше примере.

com/jfeatures/jdk16/records/LocalComponents.java:16: error: enum types must not be local
enum LocalEnum {
^
1 error

Внутренний класс может объявлять статические члены

До Java 16 внутренний класс не мог объявлять статический член. Java 16 позволяет внутреннему классу объявлять члена класса записи типа. Это позволит внутреннему классу объявить член, который является классом записи.

package com.jfeatures.jdk16.records;

public class RecordInInnerClass {
    public static void main(String[] args) {
        System.out.println("Starting test");
    }

    class Inner{
        record TestRecord(int id, String name){
        }
    }
}

Этот код показывает ниже ошибку компиляции с Java 15, он отлично работает с Java 16 или более поздней версией.

javac --enable-preview -source 15 com/jfeatures/jdk16/records/RecordInInnerClass.java
com/jfeatures/jdk16/records/RecordInInnerClass.java:9: error: static declarations not allowed in inner classes
record TestRecord(int id, String name){
^
Note: com/jfeatures/jdk16/records/RecordInInnerClass.java uses preview language features.
Note: Recompile with -Xlint:preview for details.
1 error

Зачем записывать, почему не просто кортежи?

Центральным аспектом философии Java является то, что “имена” имеют значение. A Лицо с недвижимостью Имя и фамилия понятнее и безопаснее, чем кортеж из строки и Строка .

Вывод

Записи помогают удалять повторяющийся и подверженный ошибкам код, уменьшать количество ошибок в коде, уменьшать детализацию кода и повышать производительность разработчиков. Использование подобных языковых функций сделает вас отличным разработчиком, которого все хотят нанять.

Если вы хотите получить потрясающую работу на Java, я написал электронную книгу 5 шагов к лучшей работе на Java . Вы можете скачать это пошаговое руководство бесплатно!

Ресурсы

  1. https://openjdk.java.net/jeps/395
  2. https://cr.openjdk.java.net/~briangoetz/amber/datum.html

Оригинал: “https://dev.to/vipin_sharma/java-records-concise-and-readable-data-carrier-classes-3jlc”