Mike Kenneally 在Unsplash上 拍摄的照片
如果你试图将Java传授给千禧年以前的人,或者传授给来自另一种不那么啰嗦的语言的人,你就会常常遇到关于编写getter、setter、toString、equals和hashCode方法以及需要这么多样板代码的阻力。
老式的开发人员不会理会它。我们只是习惯于指示IDE为我们生成它们。
但让我们面对现实:我们并不特别喜欢它们。我们只是习惯了 他们。我们接受了对这些方法的需求,但是老实说:可能会有所不同。
Java 14已经发布了 记录:一种新类型的预览功能,它忽略了getter、setter、toString、equals和hashCode方法的必要性。用几行代码就可以创建一个对象。
由于它仍然是预览功能,因此我们应该在编译器、IDE和/或Maven上启用预览功能。
总之,记录具有以下特征:
我已经对其进行了测试,并且该项目在我的 GitHub上可用。
那么,我们所钟爱的讨厌的宠物方法getter和setter就到此为止了吗?嗯……显然还没有。全部通过!\ 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<NationalHoliday> 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);
}
}
记录与我们的经典界面兼容。检查实现接口“ CelebrationInterface”的记录“ SpecialDate”,并因此覆盖方法“ 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;
}
}
记录很灵活,可以接受泛型!可以在下面找到该定义,并且在类“ RecordsDemoTest ” 的测试“ celebrationGenericRecord_ok()”上可以找到有关如何使用该定义的示例。
package com.danianepg.previewfeature.data.records;
import java.time.Month;
/**
* Generic record
* @author Daniane P. Gomes
*
* @param
*/
public record CelebrationGenericRecord<T>(T contents, String name, Integer day, Month month) {
}
简短的答案:对运营商数据。
长答案:现在,我们可以用几行代码声明一个简单的数据传输对象,而无需满足我们习惯于Java的所有仪式,这意味着CLEAN代码!
由于记录与其他Java的重要功能兼容,因此我很高兴开始使用它。删除项目上的多余代码使我非常满意。
那么,我们所钟爱的讨厌的宠物方法getter和setter就到此为止了吗?嗯……显然还没有。
由于记录是不变的,因此它们不能简单地替代我们的经典类。另外,还要解决的另一个问题是它们与Hibernate和Spring等框架的兼容性如何?
但是,它们将帮助我们使代码 更整洁、 更小,并且在某些情况下,甚至可以消除对Lombok等外部库的需要,如Java Magazine的 Ben Evans所述 :
“这将帮助许多应用程序来使域类更清晰、更小。它还将帮助团队消除对底层模式的许多手工编码实现,并减少或消除对Lombok之类的库的需求。”
不过,请务必记住,这是预览功能,正如文档所提醒的那样:
“预览功能可能会在将来的版本中删除,或升级为Java语言的永久功能。”
我希望他们保留它。一起祈祷吧!
原文链接:https://dev.to//danianepg/java-14-records-did-we-live-to-see-getters-and-setters-die-350e