0Pricing
Java Academy · 강의

레코드, 클래스, Lombok 비교

적절한 도구를 선택할 수 있도록 레코드와 전통적인 클래스, Lombok 주석을 비교합니다.

레코드, 클래스, Lombok 비교은(는) CoddyKit의 무료 Java Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Java Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

레코드, 클래스, Lombok 비교

Java에서는 데이터를 전달하는 타입을 만드는 여러 방법을 제공합니다. 반복 코드가 있는 일반 클래스, 레코드(Java 16 이상), Lombok 어노테이션을 사용할 수 있습니다. 올바른 선택은 사용 사례에 따라 달라집니다.

반복 코드 문제

단순한 데이터 전달 객체를 위한 일반 Java 클래스에는 생성자, 접근자, equals, hashCode, toString 등 몇 개의 필드만을 위해서도 상당한 반복 코드가 필요합니다.

// Traditional class — lots of boilerplate
class ProductOld {
    private final String id;
    private final String name;
    private final double price;

    public ProductOld(String id, String name, double price) {
        this.id = id; this.name = name; this.price = price;
    }
    public String getId() { return id; }
    public String getName() { return name; }
    public double getPrice() { return price; }

    @Override public boolean equals(Object o) { /* ... */ }
    @Override public int hashCode() { /* ... */ }
    @Override public String toString() { /* ... */ }
}

레코드 솔루션

레코드를 사용하면 같은 클래스를 한 줄로 줄일 수 있습니다. 컴파일러가 모든 반복 코드를 자동으로 생성합니다.

// Record — one line, same functionality
record Product(String id, String name, double price) {}

// Usage is almost identical except accessors use component names (no get prefix)
Product p = new Product("P001", "Laptop", 999.99);
System.out.println(p.id());     // P001 (not getId())
System.out.println(p.name());   // Laptop
System.out.println(p.price());  // 999.99
System.out.println(p);          // Product[id=P001, name=Laptop, price=999.99]

Lombok의 @Data와 @Value

Lombok은 어노테이션을 통해 컴파일 시 반복 코드를 생성합니다. @Value는 레코드와 비슷한 변경 불가능한 클래스를 만들고, @Data는 변경 가능한 클래스를 만듭니다.

// Lombok @Value — immutable (closest to record)
import lombok.Value;

@Value
public class LombokProduct {
    String id;
    String name;
    double price;
    // Lombok generates: all-args constructor, getters, equals, hashCode, toString
    // Note: accessors follow getX() naming convention (getPrice(), not price())
}

// Lombok @Data — mutable
import lombok.Data;
@Data
public class MutableProduct {
    private String id;
    private String name;
    private double price;
    // Generates: getters, setters, equals, hashCode, toString, no-args constructor
}

주요 차이점

레코드, Lombok @Value 및 일반 클래스의 중요한 차이점은 다음과 같습니다.

  • 접근자 명명: 레코드는 name()을 사용하고, Lombok은 getName()을 사용합니다
  • 가변 변형: 레코드는 항상 불변이며, Lombok은 가변성을 위한 @Data를 제공합니다
  • 상속: 레코드는 클래스를 확장할 수 없지만, Lombok 클래스는 확장할 수 있습니다
  • 빌드 도구 의존성: Lombok은 주석 처리기 설정이 필요하지만, 레코드는 기본 제공됩니다

레코드를 사용하는 경우

다음과 같은 경우 레코드가 적합합니다.

  • 형식이 주로 투명한 데이터 전달 객체(DTO, 값 객체)인 경우
  • 설계상 불변성이 필요한 경우
  • Java 16 이상을 사용하며 의존성을 전혀 추가하고 싶지 않은 경우
  • 형식이 패턴 매칭에 참여하는 경우(sealed + 레코드)
// Perfect record use cases:
record Coordinates(double lat, double lon) {}
record JwtClaims(String subject, String role, long expiresAt) {}
record PageRequest(int page, int size, String sortBy) {}
record ErrorResponse(int code, String message, String path) {}

// These are all simple data carriers with no mutable state

Lombok을 사용하는 경우

다음과 같은 경우 Lombok을 선호합니다.

  • 가변 JavaBeans가 필요한 경우(예: JPA 엔터티, Spring 설정 클래스)
  • 프레임워크와의 호환성을 위해 접근자 명명이 JavaBeans 규칙(getX)을 따라야 하는 경우
  • 복잡한 객체 생성을 위해 @Builder가 필요한 경우
  • 일부 필드에 부분적인 가변성이 필요한 경우(@NonFinal 사용)
// Lombok @Builder — great for complex object construction
import lombok.*;

@Builder
@Value
public class EmailMessage {
    String to;
    String from;
    String subject;
    String body;
    List<String> attachments;
}

EmailMessage msg = EmailMessage.builder()
    .to("user@example.com")
    .from("noreply@app.com")
    .subject("Welcome!")
    .body("Thank you for signing up")
    .attachments(List.of())
    .build();

일반 클래스를 사용하는 경우

다음과 같은 경우 일반 클래스가 여전히 적합합니다.

  • 클래스가 단순한 데이터 전달을 넘어 복잡한 동작을 포함하는 경우
  • 다른 클래스를 확장해야 하는 경우
  • hashCode/equals를 세밀하게 제어해야 하는 경우
  • 캡슐화를 적용한 가변 상태가 필요한 경우
// Plain class — when behavior dominates over data
class ShoppingCart {
    private final List<CartItem> items = new ArrayList<>();
    private final String customerId;

    public ShoppingCart(String customerId) {
        this.customerId = customerId;
    }

    public void addItem(CartItem item) { items.add(item); }
    public void removeItem(String sku) { items.removeIf(i -> i.sku().equals(sku)); }
    public double total() { return items.stream().mapToDouble(CartItem::lineTotal).sum(); }
    public boolean isEmpty() { return items.isEmpty(); }
}

레코드와 클래스 함께 사용하기

레코드와 클래스는 원활하게 함께 사용할 수 있습니다. 가변 상태를 관리하는 클래스 내부의 불변 데이터에는 레코드를 사용하십시오.

// Record for the immutable event data
record UserEvent(String userId, String action, java.time.Instant timestamp) {
    public static UserEvent now(String userId, String action) {
        return new UserEvent(userId, action, java.time.Instant.now());
    }
}

// Class for the mutable event store
class EventLog {
    private final List<UserEvent> events = new ArrayList<>();

    public void record(String userId, String action) {
        events.add(UserEvent.now(userId, action));
    }

    public List<UserEvent> eventsFor(String userId) {
        return events.stream()
            .filter(e -> e.userId().equals(userId)).toList();
    }
}

Spring Boot에서 레코드 사용하기

레코드는 Spring Boot에서 요청/응답 body로 사용할 때 잘 통합됩니다. Spring Boot의 Jackson 매퍼는 최소한의 설정만으로 레코드를 처리합니다.

// Spring Boot REST controller using records
import org.springframework.web.bind.annotation.*;

record CreateProductRequest(String name, double price, String category) {}
record ProductResponse(long id, String name, double price, String category) {}

@RestController
@RequestMapping("/api/products")
class ProductController {
    @PostMapping
    public ProductResponse create(@RequestBody CreateProductRequest req) {
        // Jackson automatically deserializes JSON into the record
        long id = productService.save(req);
        return new ProductResponse(id, req.name(), req.price(), req.category());
    }
}

성능 비교

세 가지 방식 모두 단순한 데이터 전달 객체에 대해 본질적으로 동일한 바이트코드를 생성합니다. 성능도 동일하므로, 선택 기준은 개발자 경험과 요구 사항입니다.

// All three compile to approximately equivalent bytecode:
// - Records: compiler-generated, always immutable
// - Lombok @Value: annotation-processor-generated, always immutable
// - Plain class: hand-written

// The key runtime difference:
// Records: accessor is a method matching field name (price() not getPrice())
// Lombok/Class: accessor follows JavaBeans (getPrice())

// Jackson compatibility:
// Records: work natively in Jackson 2.12+ with no config
// Lombok: work with @JsonProperty or jackson-databind-lombok module

빠른 확인

레코드 접근자는 어떤 명명 규칙을 따릅니까?

복습: 레코드와 클래스와 Lombok

핵심 내용:

  • 레코드는 생성자, 접근자(get 접두사 없음), equals, hashCode, toString을 자동으로 생성합니다
  • 레코드는 항상 불변이므로, 가변 상태에는 일반 클래스를 사용하십시오
  • Lombok @Value는 레코드와 비슷한 기능을 제공하지만 getX() 명명을 사용하고 설정이 필요합니다
  • Lombok @Builder는 선택적 필드가 많은 복잡한 객체 생성에 특히 적합합니다
  • 레코드는 DTO, 값 객체, API 요청/응답 body에 적합합니다
  • 동작이 중심이거나 상속이 필요한 경우에는 일반 클래스가 여전히 가장 적합합니다

자주 묻는 질문

“레코드, 클래스, Lombok 비교” 강의는 무료인가요?

네 — “레코드, 클래스, Lombok 비교” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Java Academy 강의 전체를 잠금 해제할 수 있습니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“레코드, 클래스, Lombok 비교”에서 뭘 배우나요?

적절한 도구를 선택할 수 있도록 레코드와 전통적인 클래스, Lombok 주석을 비교합니다. 브라우저에서 직접 실행하는 실습 코드로 Java Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Java Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Java Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“레코드, 클래스, Lombok 비교” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Java Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Java Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 레코드 소개
  2. 간결한 생성자와 유효성 검사
  3. 레코드의 사용자 정의 메서드
  4. 레코드, 클래스, Lombok 비교
← Java Academy(으)로 돌아가기