Это конец очереди для добытчиков, сеттеров и проекта Ломбок?
Фото Майк Кенилли на Расплескать
Если вы попытаетесь научить Java тысячелетию или кому-то, кто пришел с другого, менее подробного языка, вы часто можете столкнуться с сопротивлением в отношении написания геттеров, сеттеров, методов toString, equals и хэш-кода и необходимости такого большого количества шаблонного кода.
Разработчики Vintage не будут беспокоиться об этом. Мы просто привыкли поручать IDE генерировать их для нас.
Но давайте посмотрим правде в глаза: они нам не особенно нравятся . Мы просто привыкли к ним. Мы признали необходимость этих методов, но, честно говоря, все могло быть по-другому.
Java 14 запустила записи : функцию предварительного просмотра для нового типа, которая устраняет необходимость в методах getters, setters, toString, equals и hashCode. Можно создать объект с помощью нескольких строк кода.
Как это работает?
Поскольку это еще функция предварительного просмотра, мы должны включить функции предварительного просмотра в нашем компиляторе, IDE и/или Maven.
В кратких отчетах имеются следующие характеристики:
- Они окончательны и неизменны.
- Они могут реализовывать интерфейсы.
- У них могут быть статические члены.
- Они могут определять проверки.
- Они могут определять значения по умолчанию.
- Они принимают дженерики.
Я протестировал его, и проект доступен на моем GitHub .
Все прошло! \o/
Окончательный и неизменный
Обратите внимание, что записи не имеют классических приемников и установщиков, и поэтому невозможно изменить их значения после их назначения.
Обратите внимание на строки с 34 по 38 ниже, что чтение атрибутов выполняется без префикса “get”. Мы прямо используем имя атрибута.
import static org.junit.Assert.assertTrue;
import java.time.LocalDateTime;
import java.time.Month;
import java.util.Objects;
import org.junit.Test;
import com.danianepg.previewfeature.data.NationalHoliday;
import com.danianepg.previewfeature.data.records.CelebrationGenericRecord;
import com.danianepg.previewfeature.data.records.SpecialDate;
/**
* Test class to verify the records' functionalities.
* @author Daniane P. Gomes
*
*/
public class RecordsDemoTest {
private String name = "My Bday";
private Integer day = 20;
private Month month = Month.OCTOBER;
private LocalDateTime created = LocalDateTime.now();
private String country = "Brazil";
private String nationalHolidayName = "Independence Day";
private Integer nationalHolidayDay = 7;
private Month nationalHolidayMonth = Month.SEPTEMBER;
@Test
public void specialDateRecord_ok() {
SpecialDate myBday = new SpecialDate(name, day, month, created);
boolean isNameEquals = myBday.name().equals(name);
boolean isDayEquals = myBday.day() == day;
boolean isMonthEquals = myBday.month() == month;
boolean isCreatedEquals = myBday.created().equals(created);
assertTrue(isNameEquals && isDayEquals && isMonthEquals && isCreatedEquals);
}
@Test
public void specialDateRecord_equals_ok() {
SpecialDate myBday = new SpecialDate(name, day, month, created);
SpecialDate myBdayCopy = new SpecialDate(name, day, month, created);
assertTrue(myBday.equals(myBdayCopy));
}
@Test
public void specialDateRecord_alternativeConstructor() {
SpecialDate myBday = new SpecialDate(name, day, month);
boolean isCreatedNotNull = !Objects.isNull(myBday.created());
assertTrue(isCreatedNotNull);
}
@Test(expected = IllegalArgumentException.class)
public void specialDateRecord_exceptionWhenDayOutOfTheRange() {
try {
new SpecialDate(name, 32, month);
} catch (IllegalArgumentException e) {
System.out.println("Message exception: "+e.getMessage());
throw e;
}
}
@Test
public void celebrationGenericRecord_ok() {
CelebrationGenericRecord dateGenericClassic = new CelebrationGenericRecord<>(
new NationalHoliday(country), nationalHolidayName, nationalHolidayDay, nationalHolidayMonth);
boolean isInstanceOfNationalHoliday = dateGenericClassic.contents() instanceof NationalHoliday;
boolean isCountryEquals = false;
if (isInstanceOfNationalHoliday) {
NationalHoliday dateClassic = (NationalHoliday) dateGenericClassic.contents();
isCountryEquals = dateClassic.getCountry().equals(country);
}
assertTrue(isInstanceOfNationalHoliday && isCountryEquals);
}
}
Интерфейсы, Статические элементы, Проверки, Значения по умолчанию
Записи совместимы с нашими классическими интерфейсами. Проверьте запись “Особая дата”, которая реализует интерфейс “Интерфейс празднования” и, следовательно, перезаписывает метод “totalDates()”. Обратите внимание на строки 13 и 48.
Для дополнительного статического элемента проверьте строку 18.
Для проверки проверки строка 28.
Для значения по умолчанию проверьте альтернативный конструктор в строке 41, который назначает текущую дату и время для созданного объекта, даже если об этом не сообщается во время создания объекта записи.
package com.danianepg.previewfeature.data.records;
import java.time.LocalDateTime;
import java.time.Month;
import com.danianepg.previewfeature.interfaces.CelebrationInterface;
/**
* An example of a record implementing an interface, validating data, passing default values and using extra static attributes and methods.
* @author Daniane P. Gomes
*
*/
public record SpecialDate(String name, Integer day, Month month, LocalDateTime created) implements CelebrationInterface {
/**
* Additional static members
*/
private static int totalDates;
/**
* Define validations for the attributtes
* @param name
* @param day
* @param month
* @param created
*/
public SpecialDate {
if (day < 1 || day > 31) {
throw new IllegalArgumentException("Day must be on the interval 1-31.");
}
totalDates++;
}
/**
* Additional constructor, to assign a default value to attribute "created"
* @param name
* @param day
* @param month
*/
public SpecialDate(String name, Integer day, Month month) {
this(name, day, month, LocalDateTime.now());
}
/**
* Additional public method to retrieve
*/
public int totalDates() {
return totalDates;
}
}
Дженерики
Записи являются гибкими и принимают дженерики! Определение можно найти ниже, а также пример того, как его использовать, доступен в тесте “| GenericRecord_ok()” класса ” RecordsDemoTest |/”.
package com.danianepg.previewfeature.data.records; import java.time.Month; /** * Generic record * @author Daniane P. Gomes * * @param*/ public record CelebrationGenericRecord (T contents, String name, Integer day, Month month) { }
Почему это полезно?
Короткий ответ: к данным носителя.
Длинный ответ: теперь мы можем объявить простой объект передачи данных с помощью нескольких строк кода и без необходимости выполнять все церемонии, к которым мы привыкли в Java, что означает ЧИСТЫЙ код!
Поскольку записи совместимы с другими важными функциями Java, я действительно рад начать их использовать. Мне доставляет большое удовлетворение удалять лишний код в моих проектах.
Вывод
Ну что ж тогда… неужели это конец очереди для наших любимых ненавистных добытчиков и сеттеров домашних животных? Хммм… Очевидно, еще не совсем.
Поскольку записи неизменяемы, они не могут просто заменить наши классические классы. Кроме того, еще одна проблема, которую необходимо решить, заключается в том, насколько они совместимы с такими фреймворками, как Hibernate и Spring?
Однако они помогут нам сделать код чище и меньше и в некоторых случаях они могли бы даже устранить необходимость во внешних библиотеках, таких как Lombok, как заявил Бен Эванс для Java Magazine :
“Это поможет многим приложениям сделать классы доменов более четкими и компактными. Это также поможет командам устранить множество реализаций базового шаблона, написанных вручную, и уменьшить или устранить необходимость в библиотеках, таких как Lombok “.
Однако важно иметь в виду, что это функция предварительного просмотра, и, как напоминает документация :
” Функции предварительного просмотра могут быть удалены в будущей версии или обновлены до постоянных функций языка Java.”
Я надеюсь, что они сохранят его. Скрестив пальцы.
Рекомендации
JEP 359: Записи (Предварительный просмотр)
Записи поступают на Яву
Первоначально опубликовано на моя средняя страница .
Оригинал: “https://dev.to/danianepg/java-14-records-did-we-live-to-see-getters-and-setters-die-350e”