본문 바로가기
Java & Spring

Java Record vs Lombok DTO 선택 기준: 언제 무엇을 쓸까

by yamoojin83 2025. 9. 28.

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 스레드풀 사이즈/큐 전략

👉 9편: CompletableFuture allOf/anyOf로 외부 API 병렬화

👉 10편: 예외 처리 베스트 프랙티스(체크/언체크, 경계 설계)