Java 16에서 정식 출시된 불변 데이터 객체를 간단히 정의하기 위한 특별한 클래스 형태로, 주로 데이터를 담는 "데이터 홀더" 역할을 한다.
DTO , 값 객체 (Value Objects) 등의 다양한 용도로 사용할 수 있다.
기존의 클래스와 달리 모든 필드가 final 키워드로 선언되며, 객체 생성 후 변경할 수 없다는 특징이 있다.
또한 필드를 선언하면 자동으로 getter, equals(), hashCode(), toString() 등 메서드를 자동으로 생성해줘서 보일러 플레이트 코드를 줄일 수 있다. 이러한 특성으로 멀티 스레드 환경에서 데이터가 의도치 않게 변경되지 않고 안전하게 전달할 수 있다.
보일러 플레이트 코드 : 반복적인 코드를 줄일 수 있다.
기존에 사용하던 Class
public class StudentClass {
private final String name; // 불변성을 위해 final 사용
private final int age;
private final String studentId;
public StudentClass(String name, int age, String studentId) {
this.name = name;
this.age = age;
this.studentId = studentId;
}
// Getter 메서드
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getStudentId() {
return studentId;
}
// equals 메서드
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StudentClass that = (StudentClass) o;
return age == that.age &&
name.equals(that.name) &&
studentId.equals(that.studentId);
}
// hashCode 메서드
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + age;
result = 31 * result + studentId.hashCode();
return result;
}
// toString 메서드
@Override
public String toString() {
return "StudentClass{name='" + name + "', age=" + age + ", studentId='" + studentId + "'}";
}
}
record 사용
// 생성자, getter, equals(), hashCode(), toString() 이 자동으로 완성된다.
public record StudentRecord(String name, int age, String studentId) {}
record는 DTO 처럼 계층 간 데이터 전송을 목적으로 하는 객체에 사용되기도 하지만, 도메인 모델 내에서 특정 값을 표현하는 객체인 VO에서도 사용이 되기도 한다. 하지만 목적에 따라 사용하는 용도가 다르게 되는데.
DTO : 애플리케이션의 다양한 부분 간에 데이터를 이동시키는 데 사용되는 객체로. 데이터를 담고 있는 역할이다. ex) 서비스 계층에서 컨트롤러로 데이터를 전송, 컨트롤러에서 뷰 계층으로 데이터를 전달할 때 사용
Record : 불변 데이터를 간결하고 읽기 쉽게 담는데 초점을 맞추며, 반복적인 코드를 줄여줄 수 있다. 불변 객체이므로 Setter 메서드를 제공하지 않는다.
DTO 사용이 적합한 상황
- 데이터 수정이 필요한 경우 : DTO는 보통 가변적이어서 필드 값을 필요에 따라 변경할 수 있다. ex) 사용자가 회원가입을 진행할 때 일부 필드가 비어 있는 상태로 객체가 생성될 수 있으므로, 향후 업데이트를 하면서 객체의 값들이 변경될 수 있어야 한다.
- 추가적인 동작이나 검증이 필요한 경우 : 이메일 형식을 확인하거나, 입력을 정제하는 로직이 필요할 때. ex) 이메일 형식을 검증하는 메서드를 추가하여, 애플리케이션 계층 간에 데이터를 전달하기 전에 이메일이 유효한지 확인할 수 있다.
Record 사용이 적합한 상황
- 간결하고 불변성을 가진 데이터 전달 객체가 필요한 경우 : 필수 메서드를 자동으로 생성해 주기 때문에 데이터 표현을 간결하고 효율적으로 처리할 수 있다. ex) MSA에서 서비스 간 데이터를 전달할 때 데이터를 수정할 필요가 없는 경우
- 읽기 전용 데이터 전송이 필요한 경우 : 애플리케이션에서 데이터를 전달하기만 하고 수정할 필요가 없으며, 데이터베이스에서 서비스 계층 또는 서비스 간 데이터를 전달하는 데 적합하다. ex) 데이터베이스 계층에서 REST controller로 사용자 데이터를 전달할 때 사용
성능 고려 상황
- Record는 자동으로 생성되는 메서드가 있기 때문에 DTO보다 메모리를 조금 덜 사용할 수 있다.
- Record는 불변이므로, 멀티 스레드 환경에서 성능상의 이점을 제공한다. 스레드 간에 공유될 때 동기화나 Locking 메커니즘이 필요하지 않으므로, 스레드 간 경쟁으로 성능이 저하되는 상황에서 성능을 향상시킬 수 있다.
- DTO와 Record 모두 일반적인 자바 객체이므로 동일한 가비지 컬렉션 처리에 따라 관리된다. 하지만 Record는 메모리에 적은 객체가 생성되거나 유지되므로, 가비지 컬렉션이 조금 더 빠르게 이루어질 수 있다. -> 대량의 데이터 객체를 처리하는 애플리케이션에서 성능 향상에 기여할 수 있다.
'🖥️ Back-end' 카테고리의 다른 글
웹 소켓이란? (0) | 2025.04.01 |
---|---|
데이터베이스 락(Lock) 이란? (0) | 2025.03.31 |
DDD (Domain Driven Design) : 도메인 주도 설계 도전 1일차 (1) | 2025.03.13 |
웹 사이트의 동작 원리 (0) | 2025.03.11 |
Jackson 이란? (1) | 2025.03.05 |