惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

K
Kaspersky official blog
云风的 BLOG
云风的 BLOG
IT之家
IT之家
T
The Blog of Author Tim Ferriss
C
Check Point Blog
N
Netflix TechBlog - Medium
宝玉的分享
宝玉的分享
T
Tailwind CSS Blog
G
Google Developers Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
F
Fortinet All Blogs
D
DataBreaches.Net
The Register - Security
The Register - Security
L
LINUX DO - 最新话题
W
WeLiveSecurity
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V2EX - 技术
V2EX - 技术
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
小众软件
小众软件
F
Full Disclosure
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
I
InfoQ
S
Secure Thoughts
TaoSecurity Blog
TaoSecurity Blog
MyScale Blog
MyScale Blog
AI
AI
Recent Announcements
Recent Announcements
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Hugging Face - Blog
Hugging Face - Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
C
CXSECURITY Database RSS Feed - CXSecurity.com
V
Vulnerabilities – Threatpost
NISL@THU
NISL@THU
SecWiki News
SecWiki News
Cisco Talos Blog
Cisco Talos Blog
H
Heimdal Security Blog
Y
Y Combinator Blog
N
News | PayPal Newsroom
P
Privacy International News Feed
美团技术团队
Attack and Defense Labs
Attack and Defense Labs
D
Docker
PCI Perspectives
PCI Perspectives
Webroot Blog
Webroot Blog
A
About on SuperTechFans
A
Arctic Wolf
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
MongoDB | Blog
MongoDB | Blog
T
Threat Research - Cisco Blogs

博客园 - ace--碳水化合物

韦达定理 韦达定理1 梯形1 总平均分 m1 曲线相关 曲线 不等式 抛硬币 错位排列"(全错位)问题 11 1 两圆阴影面积 English1 Tidio 官方帮助中心 ERP 相关系统介绍 蝉翼定理 选配法 利润最大化公式 写在失业的一段话 排列组合-组合 在线简历 概率论与数理统计学习章节 绝对值 比例五大定理 算术平均值与几何平均值 等价符号 公因数与最大公因数 容斥原理 英语2026 机器学习,深度学习,强化学习 分别是什么以及区别是什么 深度学习 监督学习 FAQ IVR TTS选择 k 近邻算法 kaldi 平稳核函数(stationary kernel) Karush-Kuhn-Tucker 条件 凸二次规划(convex quadratic programming) FunASR+FreeSwitch做坐席客服系统记录 freeswitch原理图 客服系统,第三方平台,对话转录音,这些可以不依赖第三方做么 STUN服务器 Gun.js原理 游戏升级记 10 OBB 边界问题 关于yolo26是否可以通过结合java开发 opencv和yolo是一回事情吗 pytorch TorchVision - ace--碳水化合物 PyTorch 和 FashionMNIST 的关系 游戏升级记 9 VibeVoice实现90分钟、多角色播客生成,拓展语音合成新边界 同 WiFi 下用 Claude Code 控制另一台 Windows 电脑 Numpy 1 游戏升级记 8 开源claudecode前端 github star 9k+ 向量数据库skill 游戏升级记 7 游戏升级记 6 关系型数据库,向量数据库,ES,缓存,列式数据库,时序数据库,图数据库等的区别和共同点列举table 多Agent可视化 Agent设计模式 中文 Hermes+Obsidian+LLM wkii,构建AI知识库 Claude Code 前端工程泄露代码开源 游戏升级记 5 ai记忆 Rag 1 游戏升级记 4 游戏升级记 3 游戏升级记 2 AI学习路线 关于hermes agent安装 1 游戏升级记 1 代码迷踪 十三 代码迷踪 十二 ai智能体工程 Rust vs Go 微信小程序实名认证 怎样制作一个街机游戏 跟Claude code说 深入思考 它会思考更深入. googlebusiness profile设置统一白名单的操作,要弹窗模式的 该怎样利用ollama自己训练一个编程大模型 中华AI智能体编程一站式基站构想 打包网站到exe和app 识别的内容一般是试题模板的题号和手写的答题答案(数字) opencv怎么训练 在线SaaS系统做接口版本滚动更新 stripe相关支付流程 流程示意图 error: linker `link.exe` not found | = note: program not found - rust 给我一份关于stripe平台的使用开发说明 c++学习记20260219 奥数-平面几何经典定理 奥数-组合数学 奥数-几何 奥数-代数 奥数-数论
java record
ace--碳水化合物 · 2026-05-14 · via 博客园 - ace--碳水化合物

Java Record 是从 Java 14 开始预览,并在 Java 16 正式发布的特性。它是一种专门用于承载不可变数据的轻量级类,可以看作是一种“具名元组”。它的核心使命是简化数据载体类(Data Carrier)的编写,让你告别为 POJO 重复编写构造器、Getter、equalshashCodetoString 等样板代码的痛苦。

简单来说,以前写一个只有两个字段的类需要几十行代码,用 Record 只需一行。

🔍 核心特性与语法

定义一个 Record 使用 record 关键字:

public record Person(String name, int age) {}

仅此一行,编译器会自动为你生成以下所有内容:

  • 全部字段private final 字段,确保不可变性。
  • 规范构造器:参数顺序与声明顺序一致。
  • 自动 Getter:方法名就是字段名,如 name()age(),没有 get 前缀。
  • equals()hashCode():基于所有组件(字段)值的实现。
  • toString():格式为 Person[name=..., age=...] 的字符串。

它的使用方式和普通类几乎一样,但更具声明性:

Person person = new Person("Alice", 30);
String name = person.name(); // 调用自动生成的Getter
System.out.println(person);  // Person[name=Alice, age=30]

🏗️ 定制与增强

Record 并非完全死板,它允许在紧凑语法上进行有限的定制。

1. 自定义构造器(紧凑构造器)
你可以添加验证逻辑,不需要指定参数列表,也不能给字段赋值(编译器会自动完成):

public record Person(String name, int age) {
    // 这就是紧凑构造器,可以加逻辑
    public Person {
        if (age < 0) {
            throw new IllegalArgumentException("年龄不能为负数");
        }
        // 无需写 this.name = name,编译器会自动生成在末尾
    }
}

2. 添加实例方法或静态方法

public record Person(String name, int age) {
    public String nameToUpperCase() {
        return name.toUpperCase();
    }
    
    public static Person fromAnonymous() {
        return new Person("Anonymous", 0);
    }
}

3. 实现接口
Record 可以自由地实现接口,参与多态。

public interface Greetable { String greet(); }
public record Person(String name, int age) implements Greetable {
    @Override
    public String greet() { return "Hi, I'm " + name; }
}

⚖️ 主要限制

为了实现“纯粹的数据载体”目标,Record 有几条硬性限制,以保证语义的纯粹性:

  1. 不可继承:Record 默认是 final 的,且无法继承其他类。因为它已隐式继承 java.lang.Record 父类。
  2. 所有字段都是 final:保证实例一旦创建就不可变。
  3. 不能有实例字段:除了在记录头中声明的组件(字段),不能再添加其他实例变量。

✅ 适用场景

当你需要创建如下类型的对象时,Record 是完美的选择:

  • DTO (数据传输对象):在应用层间传递数据。
  • VO (值对象):用于领域驱动设计,根据属性来识别身份。
  • API 的返回值:临时组合查询结果。
  • Map 的复合键:当键由多个值决定时,Record 能自动提供正确的 equalshashCode

📝 与其他概念的对比

特性 Java Record 传统 POJO Lombok @Value
语法简洁度 极高,一行声明 极低,需 IDE 生成或手写 高,依赖注解处理
不可变性 语言级保证 需手动实现 注解级保证
本质 一种新的类类型 普通类 编译期代码增强
继承限制 final 类,仅能实现接口 无限制 无限制

💡 代码示例:在 Map 中作为键

import java.util.HashMap;
import java.util.Map;

public class RecordDemo {
    public static void main(String[] args) {
        // 定义坐标记录
        record Coordinate(int x, int y) {}
        
        var map = new HashMap<Coordinate, String>();
        map.put(new Coordinate(1, 2), "宝藏");
        
        // 因为equals/hashCode基于x,y的值,所以能正确取出
        System.out.println(map.get(new Coordinate(1, 2))); // 输出:宝藏
    }
}

总的来说,Java Record 让你在处理纯数据时,代码更简洁、意图更清晰、不可变性更安全。它很适合用来替代那些只需要承载数据的传统类。

Record 本身设计为最终类,如果你需要为基于 Record 的模型提供序列化支持,想了解如何与 Jackson 等 JSON 库搭配使用吗?

当需要将 Java Record 序列化成 JSON 或将 JSON 反序列化为 Record 时,Jackson 提供了很好的支持。下面介绍几种常用方式。

📦 添加依赖

pom.xml 中添加 Jackson 依赖(以 2.15 为例):

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.2</version>
</dependency>

✅ 基础使用:开箱即用

从 Jackson 2.12 开始,对 Record 的支持是内置且无需额外注解的,可以直接序列化和反序列化。

1. Record 定义

public record Person(String name, int age, String email) {}

2. 序列化与反序列化

import com.fasterxml.jackson.databind.ObjectMapper;

public class RecordJsonDemo {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        
        // Java Record -> JSON 字符串
        Person person = new Person("张三", 28, "zhangsan@example.com");
        String json = mapper.writeValueAsString(person);
        System.out.println("JSON: " + json);
        // 输出: JSON: {"name":"张三","age":28,"email":"zhangsan@example.com"}
        
        // JSON 字符串 -> Java Record
        String jsonStr = "{\"name\":\"李四\",\"age\":35,\"email\":\"lisi@example.com\"}";
        Person deserializedPerson = mapper.readValue(jsonStr, Person.class);
        System.out.println("反序列化: " + deserializedPerson);
        // 输出: 反序列化: Person[name=李四, age=35, email=lisi@example.com]
    }
}

🎨 定制字段名称:@JsonProperty

若 JSON 字段名与 Record 组件名不一致,使用 @JsonProperty

public record Person(
    @JsonProperty("full_name") String name,
    @JsonProperty("years_old") int age,
    String email
) {}

🏗️ 自定义构造器反序列化

对于需要验证或转换的场景,可以在紧凑构造器中处理:

import com.fasterxml.jackson.annotation.JsonCreator;

public record Person(String name, int age, String email) {
    @JsonCreator  // 明确指示 Jackson 使用此构造器
    public Person {
        if (age < 0) throw new IllegalArgumentException("年龄非法");
        // 可以做一些规范化,比如 trim
    }
}

🧩 空值处理与可选字段

使用 Optional 需特别注意:Jackson 默认能处理 Optional 类型,但更推荐用 @JsonInclude 控制非空序列化,或在反序列化时给默认值。

为字段设置默认值(反序列化时若 JSON 缺失该字段):

public record Person(String name, int age, String email) {
    // 手工重载规范构造器,在内部提供默认值
    @JsonCreator
    public Person(@JsonProperty("name") String name, 
                  @JsonProperty("age") int age, 
                  @JsonProperty("email") String email) {
        this.name = name == null ? "未知" : name;
        this.age = age;
        this.email = email == null ? "no-email@example.com" : email;
    }
}

⚠️ 常见注意事项

  1. 字段顺序:Jackson 按 Record 组件声明顺序进行序列化/反序列化,务必保持一致。
  2. 空构造函数:Record 没有无参构造器,反序列化要求 JSON 必须提供所有字段。如果某些字段可能缺失,请像上面那样提供带默认值的构造器。
  3. 内部类 Record:若 Record 定义在另一个类内部,确保是静态的(static record),否则 Jackson 可能无法实例化。

💡 实际应用示例

假设一个 API 返回用户信息,Record 作为 DTO:

// 定义 Record
public record ApiResponse<T>(int code, String message, T data) {}

// 在 Controller 中使用 (Spring Boot 示例)
@GetMapping("/user/{id}")
public ApiResponse<Person> getUser(@PathVariable int id) {
    Person user = new Person("王五", 30, "wangwu@example.com");
    return new ApiResponse<>(200, "成功", user);
}
// 返回的 JSON 自动为: {"code":200,"message":"成功","data":{"name":"王五","age":30,"email":"wangwu@example.com"}}

Jackson 从 2.12 起对 Record 的自动化支持已经相当成熟,无需额外插件或复杂配置即可无缝集成到 Spring Boot 等框架中使用。