Java Academy · 课时

记录类、类与 Lombok 的比较

比较记录类、传统类和 Lombok 注解,以选择合适的工具

第 4 / 4 课13 个步骤

记录类、类与 Lombok 的比较 是 CoddyKit 上的免费 Java Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 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 需要配置注解处理器;记录类是内置功能

何时使用记录类

在以下情况下,记录类非常适合:

  • 类型主要是透明的数据载体(数据传输对象、值对象)
  • 根据设计需要不可变性
  • 使用 Java 16 或更高版本,并且希望零依赖
  • 类型参与模式匹配(密封类 + 记录类)
// 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:

  • 需要可变 JavaBean(例如 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 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 擅长构建包含许多可选字段的复杂对象
  • 记录类非常适合数据传输对象、值对象以及应用程序接口请求/响应正文
  • 当行为占主导地位或需要继承时,普通类仍然是最佳选择
免费开始

用 AI 导师学习 Java — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
104
课程
374

常见问题解答

「记录类、类与 Lombok 的比较」课时是免费的吗?

是的 — 「记录类、类与 Lombok 的比较」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。

「记录类、类与 Lombok 的比较」这节课中我会学到什么?

比较记录类、传统类和 Lombok 注解,以选择合适的工具 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Java Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「记录类、类与 Lombok 的比较」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Java Academy 课中编写并运行代码吗?

能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 认识记录类
  2. 紧凑构造方法与验证
  3. 为记录类添加自定义方法
  4. 记录类、类与 Lombok 的比较
← 返回 Java Academy