Автор оригинала: Pankaj Kumar.
Java 14 представила новый способ создания классов, называемых записями. В этом уроке мы научимся:
- Зачем нам нужны записи Java
- Как создавать записи и использовать их
- Переопределение и расширение классов записей
Рекомендуемое чтение : Функции Java 14
Зачем нам нужны записи Java?
Одной из распространенных жалоб на Java была ее многословность. Если вам нужно создать простой класс POJO, для этого требуется следующий стандартный код.
- Частные поля
- Методы получения и установки
- Конструкторы
- Методы hashCode(), equals () и toString ().
Эта многословность является одной из причин высокого интереса к Котлину и проекту Ломбок .
На самом деле, явное разочарование от написания этих универсальных методов каждый раз приводит к тому, что для их создания используются ярлыки в Java IDE, такие как Eclipse и IntelliJ IDEA.
Вот снимок экрана, показывающий опцию Eclipse IDE для создания церемониальных методов для класса.
Записи Java предназначены для устранения этой многословности, предоставляя компактную структуру для создания классов POJO.
Как создавать записи Java
Записи Java – это функция предварительного просмотра, которая разработана в JEP 359 . Итак, вам нужны две вещи для создания записей в ваших Java-проектах.
- Установлен JDK 14. Если вы используете IDE, то она также должна обеспечивать поддержку Java 14. И Eclipse, и IntelliJ уже предоставляют поддержку Java 14, так что у нас все хорошо.
- Включить функцию предварительного просмотра : По умолчанию функции предварительного просмотра отключены. Вы можете включить его в Eclipse из настроек компилятора Java проекта.
Вы можете включить функции предварительного просмотра Java 14 в командной строке, используя параметр --enable-preview-source 14
.
Допустим, я хочу создать класс модели сотрудника. Это будет выглядеть примерно так, как показано в следующем коде.
package com.journaldev.java14; import java.util.Map; public class Employee { private int id; private String name; private long salary; private Mapaddresses; public Employee(int id, String name, long salary, Map addresses) { super(); this.id = id; this.name = name; this.salary = salary; this.addresses = addresses; } public int getId() { return id; } public String getName() { return name; } public long getSalary() { return salary; } public Map getAddresses() { return addresses; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((addresses == null) ? 0 : addresses.hashCode()); result = prime * result + id; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + (int) (salary ^ (salary >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Employee other = (Employee) obj; if (addresses == null) { if (other.addresses != null) return false; } else if (!addresses.equals(other.addresses)) return false; if (id != other.id) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (salary != other.salary) return false; return true; } @Override public String toString() { return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + ", addresses=" + addresses + "]"; } }
Фу, это более 70 строк автоматически сгенерированного кода. Теперь давайте посмотрим, как создать класс записей сотрудников, который, по сути, предоставляет те же функции.
package com.journaldev.java14; import java.util.Map; public record EmpRecord(int id, String name, long salary, Mapaddresses) { }
Вау, это не может быть короче, чем это. Мне уже нравятся занятия по записи.
Теперь давайте воспользуемся командой javap
, чтобы выяснить, что происходит за кулисами при компиляции записи.
# javac --enable-preview -source 14 EmpRecord.java Note: EmpRecord.java uses preview language features. Note: Recompile with -Xlint:preview for details. # javap EmpRecord Compiled from "EmpRecord.java" public final class EmpRecord extends java.lang.Record { public EmpRecord(int, java.lang.String, long, java.util.Map); public java.lang.String toString(); public final int hashCode(); public final boolean equals(java.lang.Object); public int id(); public java.lang.String name(); public long salary(); public java.util.Map addresses(); } #
Если вам нужны дополнительные внутренние сведения, выполните команду javap с опцией-v.
# javap -v EmpRecord
Важные моменты, касающиеся классов записей
- Класс записи является окончательным, поэтому мы не можем его продлить.
- Классы записей неявно расширяют
java.lang.Запись
класс. - Все поля, указанные в объявлении записи, являются окончательными.
- Поля записи являются “неглубокими” неизменяемыми и зависят от типа. Например, мы можем изменить поле адреса, получив к нему доступ, а затем обновив его.
- Создается единый конструктор со всеми полями, указанными в определении записи.
- Класс записи автоматически предоставляет методы доступа к полям. Имя метода совпадает с именем поля, а не с общими и обычными методами получения.
- Класс записи также предоставляет реализации hashCode() , equals () и toString ().
Использование записей в программе Java
Давайте рассмотрим простой пример использования нашего класса EmpRecord.
package com.journaldev.java14; public class RecordTest { public static void main(String[] args) { EmpRecord empRecord1 = new EmpRecord(10, "Pankaj", 10000, null); EmpRecord empRecord2 = new EmpRecord(10, "Pankaj", 10000, null); // toString() System.out.println(empRecord1); // accessing fields System.out.println("Name: "+empRecord1.name()); System.out.println("ID: "+empRecord1.id()); // equals() System.out.println(empRecord1.equals(empRecord2)); // hashCode() System.out.println(empRecord1 == empRecord2); } }
Выход:
EmpRecord[id=10, name=Pankaj, salary=10000, addresses=null] Name: Pankaj ID: 10 true false
Объект записи работает так же, как и любой класс модели, объект данных и т.д.
Расширение Конструктора Записей
Иногда мы хотим провести некоторые проверки или войти в наш конструктор . Например, идентификатор сотрудника и зарплата не должны быть отрицательными. Конструктор по умолчанию не будет иметь этой проверки. Мы можем создать компактный конструктор в классе record. Код этого конструктора будет помещен в начало автоматически сгенерированного конструктора.
public record EmpRecord(int id, String name, long salary, Mapaddresses) { public EmpRecord { if (id < 0) throw new IllegalArgumentException("employee id can't be negative"); if (salary < 0) throw new IllegalArgumentException("employee salary can't be negative"); } }
Если мы создадим запись EmpRecord, как в следующем коде:
EmpRecord empRecord1 = new EmpRecord(-10, "Pankaj", 10000, null);
Мы получим исключение во время выполнения в виде:
Exception in thread "main" java.lang.IllegalArgumentException: employee id can't be negative at com.journaldev.java14.EmpRecord.(EmpRecord.java:9)
Могут Ли Классы Записей Иметь Методы?
Да, мы можем создать метод в записях.
public record EmpRecord(int id, String name, long salary, Mapaddresses) { public int getAddressCount() { if (this.addresses != null) return this.addresses().size(); else return 0; } }
Но записи предназначены для того, чтобы быть носителями данных. Нам следует избегать использования служебных методов в классе записей. Например, описанный выше метод может быть создан в служебном классе.
Если вы считаете, что наличие метода необходимо для вашего класса записей, подумайте хорошенько, действительно ли вам нужен класс записей?
Вывод
Записи Java являются желанным дополнением к основным функциям программирования. Вы можете думать об этом как о “именованном кортеже”. Он предназначен для создания объекта-носителя данных с компактной структурой, избегая всего шаблонного кода.