Java Record vs Lombok DTO 선택 기준: 언제 무엇을 쓸까
DTO를 만들 때 record로 갈지, Lombok으로 클래스를 만들지 고민이 잦습니다. 한 방에 끝나는 정답은 없지만, “무엇을 언제 쓰는지”를 분명히 하면 팀 품질과 유지보수가 훨씬 좋아집니다. 아래 기준과 예제를 참고해 실무에 맞게 결정하세요.
빠른 요약
- 불변 데이터 전송용(API 응답, 설정 스냅샷, 캐시 키) → Record 우선
- 가변 DTO / 빌더 DSL / JPA 엔티티 → Lombok 우선(
@Getter,@Setter,@Builder,@NoArgsConstructor) - Jackson 직렬화: record는 2.12+에서 자연스럽게 동작. Lombok DTO는 no-args 또는 builder 구성이 흔함
Record로 만들 때
// Java 16+
public record UserDto(Long id, String name, String email) {
// 유효성: 'canonical constructor'에서 검증
public UserDto {
Objects.requireNonNull(id, "id");
if (name == null || name.isBlank()) throw new IllegalArgumentException("name");
}
}
특징: 모든 구성요소(component)로 equals/hashCode/toString이 생성되고, 기본적으로 불변입니다. 해시 기반 컬렉션(Map 키 등)에 안전하며, 패턴 매칭/분해(var (id, name, email) = dto;)에도 잘 어울립니다.
Lombok DTO로 만들 때
import lombok.*;
@Getter @Setter @ToString
@AllArgsConstructor @NoArgsConstructor
@Builder
public class UserDto {
private Long id;
private String name;
private String email;
}
특징: 가변/불변을 유연하게 선택할 수 있고(@Value는 불변), @Builder로 가독성 좋은 생성 DSL을 쉽게 제공합니다. 단, Lombok 의존이 생기며, 생성되는 코드가 눈에 직접 보이지 않기 때문에 팀 컨벤션이 필요합니다.
상황별 결정 가이드
- API 응답/요청: 대부분 불변이 유리 → Record 권장. 요청 바인딩이 복잡하면 Lombok
@Builder도 고려 - Config 스냅샷/캐시 키: 변경되면 안 됨 → Record
- 폼 바인딩/단계적 세팅: 세터 필요 → Lombok
- JPA 엔티티: no-args, 프록시, 지연로딩 등 요구 → Lombok POJO (Record는 부적합)
- 빌더가 꼭 필요: Record에도 Lombok
@Builder를 붙일 수 있으나, 팀이 Lombok 비사용 원칙이면 별도 빌더 클래스를 작성
직렬화/역직렬화
// Jackson 2.12+ : record 지원
public record ProductDto(Long id, String name, int price) { }
// Lombok DTO (no-args + getters)
@Getter @NoArgsConstructor @AllArgsConstructor
public class ProductDto2 {
private Long id; private String name; private int price;
}
라이브러리 호환성만 맞으면 record가 설정 없이 잘 동작합니다. Lombok DTO는 no-args 생성자 또는 @Builder 기반 역직렬화를 선택하면 매끈합니다.
검증 포인트
- Record: compact/canonical 생성자에서 불변 조건을 보장
- Lombok: 세터/생성자/빌더 레벨에서 검증.
@Builder사용 시 필수값은@NonNull로 명시
안티 패턴
- Record를 만들고 필드를 컬렉션 가변으로 노출한 뒤 그대로 변경함 → 불변 이점 상실(불변 컬렉션로 감싸거나 방어적 복사)
- Lombok
@Data를 엔티티/DTO 어디든 남발 → equals/hash가 모든 필드에 묶여 예기치 않은 성능/버그 유발
요약 체크리스트
- 바뀌지 않는 전송용 모델? → Record
- 점진적 세팅/빌더/프레임워크 요구사항? → Lombok DTO
- 엔티티는 Record 금지, DTO는 상황에 따라 선택
- 해시 키·캐시 키는 불변 타입(Record)로
FAQ
Q1. Record에 빌더가 필요합니다. 어떻게 하나요?
A. 표준 자바에는 내장 빌더가 없습니다. 선택지는 (1) 별도 빌더 클래스 작성, (2) Lombok @Builder를 Record에 적용(팀 정책 확인)입니다.
Q2. JPA에서 Record를 엔티티로 써도 되나요?
A. 일반적으로 권장되지 않습니다. JPA 프록시/지연로딩/무인자 생성자 요구와 맞지 않습니다. 엔티티는 POJO(Lombok 조합 포함)가 안전합니다.
관련 글
👉 1편: ArrayList vs LinkedList: 언제 무엇을 쓰나 (+O(1) 착각 5가지)
👉 2편: 제네릭 와일드카드 완전정복(PECS 암기팁 포함)
👉 3편: Stream API: for→stream 리팩터링 10가지(성능/가독 균형)
👉 4편: Optional.orElse vs orElseGet 차이와 NPE 방지
👉 5편: java.time 제대로 쓰기(타임존/포맷 실수 7가지)
👉 6편: Java Record vs Lombok DTO 선택 기준
👉 7편: NIO.2로 폴더 스캔/감시 구현(FileVisitor/WatchService)
👉 8편: ExecutorService 스레드풀 사이즈/큐 전략
'Java & Spring' 카테고리의 다른 글
| ExecutorService 스레드풀 사이즈/큐 전략 (0) | 2025.09.29 |
|---|---|
| NIO.2로 폴더 스캔/감시 구현(FileVisitor/WatchService) (0) | 2025.09.29 |
| java.time 제대로 쓰기: 타임존/포맷 실수 7가지와 안전한 사용법 (0) | 2025.09.28 |
| Optional.orElse vs orElseGet 차이와 NPE 방지: 실무 규칙 7가지 (0) | 2025.09.28 |
| Stream API: for→stream 리팩터링 10가지(성능/가독 균형) (0) | 2025.09.28 |