Java Academy · レッスン

レコード、クラス、Lombok の比較

適切なツールを選べるように、レコードを従来のクラスや Lombok のアノテーションと比較します。

レッスン 4/413 ステップ

「レコード、クラス、Lombok の比較」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

レコード、クラス、Lombokの比較

Javaには、データを保持する型を作成する方法がいくつかあります。定型コードを記述する通常のクラス、レコード(Java 16以降)、またはLombokアノテーションです。適切な選択は用途によって異なります。

定型コードの問題

単純なデータキャリアとして通常のJavaクラスを作成する場合、コンストラクタ、getter、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() { /* ... */ }
}

レコードによる解決

レコードを使えば、同じクラスを1行に凝縮できます。コンパイラが定型コードをすべて自動生成します。

// 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 + records)に参加する場合
// 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が適しています。

  • 可変なBean(例: 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と適切に連携します。Springの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());
    }
}

パフォーマンス比較

単純なデータキャリアであれば、3つのアプローチはいずれも本質的に同じバイトコードを生成します。パフォーマンスに違いはありません。選択の基準は、開発者体験と要件です。

// 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のリクエストボディーやレスポンスボディーに適しています
  • 振る舞いが中心となる場合や継承が必要な場合は、プレーンなクラスが適しています
無料で開始

AI チューターと学ぶ Java — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
104
レッスン
374

よくある質問

「レコード、クラス、Lombok の比較」レッスンは無料ですか?

はい。「レコード、クラス、Lombok の比較」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「レコード、クラス、Lombok の比較」で何を学びますか?

適切なツールを選べるように、レコードを従来のクラスや Lombok のアノテーションと比較します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「レコード、クラス、Lombok の比較」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. レコード入門
  2. コンパクトコンストラクターと検証
  3. レコードのカスタムメソッド
  4. レコード、クラス、Lombok の比較
← Java Academyに戻る