1. 概述

toString() 方法是 Java 开发中获取对象字符串表示的常用手段。Project Lombok 能帮我们自动生成一致性的字符串表示,避免手写样板代码污染源文件,尤其当类包含大量字段时,可显著提升代码可维护性。

本文将演示如何通过 Lombok 自动生成 toString() 方法,并深入探讨各种配置选项,助你精准控制输出结果。

2. 环境准备

首先在项目中添加 Lombok 依赖:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.30</version>
    <scope>provided</scope>
</dependency>

后续示例将使用一个简单的 Account POJO 类演示功能特性:

public class Account {
    private String id;
    private String name;
    // 标准 getter/setter
}

3. 基础用法

直接在类上添加 @ToString 注解即可自动生成 toString() 方法:

@ToString
public class Account {
    private String id;
    private String name;
    // 标准 getter/setter
}

默认行为

  • 输出包含类名
  • 按字段声明顺序打印所有非静态字段
  • 字段格式为 字段名=值(优先调用 getter,无 getter 时直接访问字段)
  • 字段间用逗号分隔

调用示例:

Account account = new Account();
account.setId("12345");
account.setName("An account");
System.out.println(account.toString());

输出结果:

Account(id=12345, name=An account)

对于简单对象,这种默认输出通常已足够清晰。

4. 配置选项

Lombok 提供多种配置选项满足复杂场景需求:

4.1. 调用父类 toString()

默认不包含父类信息,通过 callSuper=true 启用:

@ToString(callSuper = true)
public class SavingAccount extends Account {
    private String savingAccountId;
    // 标准 getter/setter
}

输出示例:

SavingAccount(super=Account(id=12345, name=An account), savingAccountId=6789)

注意:仅当父类不是 Object 时才有意义(Object.toString() 输出无实际信息)

4.2. 省略字段名

设置 includeFieldNames=false 可简化输出:

@ToString(includeFieldNames = false)
public class Account {
    private String id;
    private String name;
    // 标准 getter/setter
}

输出结果:

Account(12345, An account)

4.3. 直接访问字段而非 getter

通过 doNotUseGetters=true 强制使用字段值:

@ToString(doNotUseGetters = true)
public class Account {
    private String id;
    private String name;

    // 特殊 getter(会被忽略)
    public String getId() {
        return "this is the id:" + id;
    }
    // 标准 getter/setter
}

对比输出:

  • 默认(调用 getter):Account(id=this is the id:12345, name=An account)
  • 启用后(直接访问字段):Account(id=12345, name=An account)

4.4. 字段包含与排除

排除敏感字段

@ToString
public class Account {
    private String id;
    
    @ToString.Exclude
    private String name;  // 被排除
    // 标准 getter/setter
}

显式包含字段

@ToString(onlyExplicitlyIncluded = true)
public class Account {
    @ToString.Include
    private String id;    // 仅包含此字段
    
    private String name;  // 被忽略
    // 标准 getter/setter
}

两种方式输出相同:

Account(id=12345)

特殊规则:以 $ 开头的字段默认排除,但可用 @ToString.Include 强制包含

4.5. 输出顺序控制

通过 rank 属性调整字段顺序:

@ToString
public class Account {
    private String name;
    
    @ToString.Include(rank = 1)
    private String id;  // 强制置顶
    // 标准 getter/setter
}

输出结果(id 排在 name 前):

Account(id=12345, name=An account)

排序规则

  • rank 值越小越靠前(默认 rank=0)
  • 相同 rank 按声明顺序排列

4.6. 包含方法输出

无参实例方法可通过 @ToString.Include 加入输出:

@ToString
public class Account {
    private String id;
    private String name;
    
    @ToString.Include
    String description() {
        return "Account description";
    }
    // 标准 getter/setter
}

输出结果:

Account(id=12345, name=An account, description=Account description)

注意:若方法名与字段名冲突,方法优先级高于字段

4.7. 修改字段名

通过 name 属性自定义输出名称:

@ToString
public class Account {
    @ToString.Include(name = "identification")
    private String id;  // 输出时重命名
    
    private String name;
    // 标准 getter/setter
}

输出结果:

Account(identification=12345, name=An account)

5. 数组处理

数组字段通过 Arrays.deepToString() 处理,自动处理循环引用:

@ToString
public class Account {
    private String id;
    private Object[] relatedAccounts;  // 数组字段
    // 标准 getter/setter
}

输出示例(含循环引用):

Account(id=12345, relatedAccounts=[54321, [...]])

循环引用会被标记为 [...],避免 StackOverflowError

6. 注意事项

几个关键点需牢记:

  1. 手动覆盖优先:类中存在任意名为 toString() 的方法(无论返回类型),Lombok 将不再生成
  2. 版本兼容性:不同 Lombok 版本输出格式可能变化,避免依赖 toString() 输出做解析
  3. 枚举支持:可用于枚举类,输出格式如 AccountType.SAVING

7. 总结

通过 Lombok 的 @ToString 注解,我们实现了:

  • 零样板代码生成对象字符串表示
  • 灵活配置字段包含/排除、顺序、命名等
  • 安全处理数组和循环引用
  • 支持父类信息和方法输出

建议:优先使用默认配置,仅在特殊场景(如敏感数据隐藏、复杂对象定制)时启用高级选项。

完整示例代码见 GitHub 仓库(链接已更新为有效地址)。