java 14 버전에서 출시된 새 유형의 클래스, 불변 객체를 생성할 때 사용한다.
다양한 함수를 기본적으로 제공해주기 때문에 보일러 플레이트 코드가 많이 빠진다.
public class LoginResponseDto {
@JsonProperty("code")
private String code;
@JsonProperty("message")
private String message;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="Asia/Seoul")
@JsonProperty("lastAccessTime")
private LocalDateTime lastAccessTime;
public LoginResponseDto() {
}
public LoginResponseDto(String code, String message, LocalDateTime lastAccessTime) {
this.code = code;
this.message = message;
this.lastAccessTime = lastAccessTime;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public LocalDateTime getLastAccessTime() {
return lastAccessTime;
}
public void setLastAccessTime(LocalDateTime lastAccessTime) {
this.lastAccessTime = lastAccessTime;
}
}
Record로는 아래와 같이 선언된다.
위의 코드에는 없지만, equals와 hashcode, toString도 기본으로 제공해준다.
public record LoginResponseDto (
@JsonProperty("code")
String code,
@JsonProperty("message")
String message,
@JsonProperty("lastAccessTime")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="Asia/philippines")
LocalDateTime lastAccessTime
) {}
{
"code": "200",
"message": "success",
"lastAccessTime": "2024-06-03 17:29:43"
}
물론 Lombok의 @Getter, @AllArgsConstructor, @EqualsAndHashCode @ToString를 사용하면 줄일 수 있다.
하지만 몇십 개나 되는 DTO 클래스에 위의 어노테이션을 일일이 달아주는 게 상당히 번거로운 작업이 될 수 있다.
record의 특성 자체, 모든 필드가 final이라 변경을 못하지만, 데이터 변질에 대해 걱정하지 않아도 된다.
애초에 DTO는 말 그대로 데이터를 전송하기 위한 Object이기 때문에 수정을 못하는 것이 더 안전하게 사용할 수 있다.
setter는 없으니, 생성자를 통해 값을 바인딩 할 수 있다. 헷갈릴 수 있는 점은, 기존에 getter가 있을때는 request.getCode()
****과 같은 형태로 getter를 통해 값을 받았지만 record의 경우엔 record.code();
과 같이 get이 빠진 형태로 getter가 구현된다.
정리해보자면
장점:
- 간결성: 레코드 클래스는 데이터를 담는 클래스를 매우 간결하게 표현할 수 있다. 필드와 해당 필드에 대한 getter 메소드, equals(), hashCode(), toString() 메소드를 자동으로 제공하기 때문에 코드의 양을 크게 줄일 수 있다.
- 불변성: 레코드 클래스의 필드는 모두 final로 선언되므로, 한번 생성된 레코드 객체의 상태는 변경되지 않습니다. 이는 객체의 안정성을 높이고, 버그 발생 가능성을 줄여준다.
단점:
- 상속 불가: 레코드 클래스는 상속을 지원하지 않는다. 따라서 기능의 확장이 필요한 경우, 레코드 클래스 대신 일반 클래스를 사용해야 한다.
- 빌더 패턴 미지원: 레코드 클래스는 빌더 패턴을 지원하지 않는다. 복잡한 생성 로직이 필요한 경우, 별도의 빌더 클래스를 만들어야 한다.
장점:
- 유연성: 일반 클래스는 상속, 메소드 오버라이딩 등 레코드 클래스보다 더 다양한 기능을 제공한다. 따라서 기능의 확장이 필요한 경우, 일반 클래스를 사용하는 것이 더 유연한 해결책이 될 수 있다.
- 빌더 패턴 지원: 일반 클래스는 빌더 패턴을 쉽게 적용할 수 있다. 복잡한 생성 로직이 필요한 경우, 빌더 패턴을 통해 객체를 안정적으로 생성할 수 있다.
단점:
- 코드 중복: 필드에 대한 getter, setter 메소드와 equals(), hashCode(), toString() 메소드 등을 직접 작성해야 한다. 이로 인해 코드의 중복이 발생하고, 코드의 가독성이 떨어질 수 있다.
- 불변성 미보장: 일반 클래스의 필드는 final로 선언되지 않는 한, 값이 변경될 수 있다. 이로 인해 객체의 상태가 예기치 않게 변경되는 문제가 발생할 수 있다.
참고: https://velog.io/@jinyr1128/12%EC%9B%947%EC%9D%BC-%EB%A0%88%EC%BD%94%EB%93%9C-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EB%B9%8C%EB%8D%94-%ED%8C%A8%ED%84%B4-%EC%84%B1%EB%8A%A5-%EB%B9%84%EA%B5%90%EC%9E%A5%EB%8B%A8%EC%A0%90,
https://devjaewoo.tistory.com/160