Prev >
Java 16 - Record Class (1) Easy Syntax
Next >
Java 16 Record 사용처: 속성 파일을 쉽게 객체화한 Configuration Properties - @Value보다 ...
앞글에서 말한 대로 record는 불변 객체를 만들라고 나온 쉬운 클래스 유형이다.
사용이 쉬운 덕분에 DTO 작성 때 딱히 뭘 안 하고 필드만 나열하면 알아서 final로 인식되고 getter도 toString도 생성자도 equals도 hashCode도 implements Serializable도 알아서 생겨서 편하게 쓸 수 있다.
가장 대표적인 사용처다.
@Builder
public record SignInRequestDto(
@Pattern(regexp = "...", message = "...")
String username,
@JsonProperty("password")
@Pattern(regexp = "...", message = "...")
String rawPassword
) {}
@Builder
public record OauthSignInRequestDto(
@NotBlank String code,
String state,
@NotNull AuthType provider
) {}
public enum AuthType {
@JsonProperty("kakao") KAKAO,
@JsonProperty("naver") NAVER,
@JsonProperty("google") GOOGLE,
@JsonProperty("apple") APPLE,
@JsonProperty("native") NATIVE
}
// Response DTO
@Builder
public record MemberOAuthSignInResponseDto(
@JsonInclude(Include.NON_EMPTY)
String signUpCode,
@JsonInclude(Include.NON_EMPTY)
String email,
@JsonInclude(Include.USE_DEFAULTS)
Boolean isRegistered,
@JsonInclude(Include.NON_DEFAULT)
Boolean hasNativeAccount,
@JsonInclude(Include.NON_DEFAULT)
Boolean requires2Fa
) {}
우리가 record
에서 관심을 기울일 생성자 두 유형은 다음과 같다.
이중에서 All Args Constructor는 기본 생성이 된다.
그리고 이때 생성자에 온 파라미터를 확인하는 곳이 Compact Constructor다.
컴팩트 생성자는 public 레코드클래스이름 {}
형태로 사용한다.
public record SampleRecord(String name) {
// Compact Constructor
public SampleProperties {
if (name == null || name.isBlank()) {
name = "noname"; // 기본값을 주거나 예외를 발생시킬 수 있다.
}
name = name.strip(); // 값을 전처리할 수 있다.
}
}
이때 name
은 this.name
이 아니라 파라미터 name
이다. (생성자 파라미터 검색)
this
와 this.name
은 컴팩트 생성자 안에서 사용하면 안 된다. (아직 실제 생성 전이기 때문.)
정보를 요약하면 다음과 같다.
final
이 아니다.this
, this.name
등을 사용하면 안 된다.나중에 데이터 스펙이 얼마든지 바뀔 수 있기 때문이다.
Record는 All Arguments Constructor를 자동으로 생성하는 놈이기 때문에, 나중에 필드 종류를 바꾸거나 순서만 바꿔도, 얘의 생성자가 쓰이고 있는 모든 곳을 수정하거나, 매번 생성자를 추가해서 새로운 All Args Constructor에게 전달해야 한다.
그럴 바엔 빌더랑, 필요에 따라 컴팩트 생성자로 관리하는 게 훨씬 편하다.
일반적으로 래퍼 사용이 유리할 것이다.
즉 Nullable
에 대한 명시를 하면 좋겠다는 의미다.
레코드 클래스를 통해 생성하는 객체는 반드시 All Args Constructor를 통하도록 만들어야 한다.
public record MyRecord(String name, Integer age) {
public MyRecord(String name, Instant birth) {
// this(...)로 All Args Constructor 호출
this(name, calculateAge(birth));
}
private static int calculateAge(Instant birth) {
// ...
}
}
유념할 것은 자바는 전통적인 언어라서, super()
, this()
등 다른 생성자를 사용할 땐 반드시 생성자 실행문 첫 줄에 사용해야 한다는 것이다. (주석 제외한 첫 줄)
그래서 어떤 연산이 필요하다면 위 예시처럼 다른 함수를 통해야 한다.