Java List.getFirst 怎样处理空列表
Java 21 及以上版本里,List.getFirst() 可以直接读取列表的第一个元素;列表为空时,它会抛出 NoSuchElementException。所以处理空列表的关键不是给异常“消音”,而是先决定:空列表代表业务默认值、需要跳过,还是应该被视为输入错误。
官方文档:https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/util/List.html
我在把老代码从 get(0) 改成 getFirst() 时,最容易忽略的就是这一点:方法名更贴近业务语言,但它并不会把“没有首元素”变成一个普通的 null 结果。

先确认 List.getFirst 的版本与语义
List.getFirst() 是 SequencedCollection 体系中的首元素访问方法,Java 21 起可用。对非空列表,它等价于取遇到顺序中的第一个元素;对空列表,API 契约是抛出 NoSuchElementException。它不会修改列表,也不会删除元素。
这里有三个容易混淆的状态:
| 状态 | 调用结果 | 调用方应表达的含义 |
|---|---|---|
| 列表非空,首元素非 null | 返回首元素 | 读取成功 |
| 列表非空,首元素为 null | 返回 null(取决于列表是否允许 null) | 有元素,但元素值为空 |
| 列表为空 | 抛出 NoSuchElementException | 没有可读取的元素 |
因此,不能把“返回了 null”和“列表没有元素”当成同一件事。前者是元素值问题,后者是集合数量问题。
用 isEmpty 建立显式保护
如果空列表是正常输入,最直观的写法是在调用前检查 isEmpty()。下面示例把空分支、首元素读取和异常兜底分开,返回一个明确的结果对象。
import java.util.List;
public class FirstElementDemo {
static String describe(List values) {
// 先区分“没有元素”和“首元素值为 null”这两个状态。
if (values.isEmpty()) {
return "EMPTY";
}
// 列表已经确认非空,getFirst 只负责读取,不会移除元素。
String first = values.getFirst();
return first == null ? "FIRST_IS_NULL" : "FIRST=" + first;
}
public static void main(String[] args) {
// 使用不可变列表演示读取;getFirst 不要求列表可修改。
System.out.println(describe(List.of("alpha", "beta")));
System.out.println(describe(List.of()));
}
}
这段代码的重点是分支顺序:先判断数量,再读取元素。若业务上不允许空列表,也可以不返回 EMPTY,而是在入口处把它转换为输入错误;但转换动作应该发生在边界层,而不是让每个调用点各自猜测异常含义。
比较 getFirst、get(0) 与 Optional
getFirst() 和 get(0) 在非空 List 上都能拿到首元素,但表达意图不同。前者强调“按遇到顺序取首元素”,后者强调“访问下标 0”。在只处理 List 的旧代码里,get(0) 并没有错;当代码需要和 SequencedCollection 的首尾操作保持一致时,getFirst() 更容易读懂。
| 写法 | 空集合行为 | 更适合的场景 |
|---|---|---|
getFirst() | 抛出 NoSuchElementException | 空集合是异常或已在前置流程排除 |
get(0) | 抛出 IndexOutOfBoundsException | 确实在表达下标访问,或维护旧版 Java 代码 |
stream().findFirst() | 返回空 Optional | 空集合是正常分支,调用方需要继续组合流程 |
如果调用方需要一个可组合的“可能不存在”结果,可以用 findFirst()。它的返回类型把缺失状态放到类型里;如果调用方需要严格的前置条件,getFirst() 则会更早暴露错误。
import java.util.List;
import java.util.Optional;
public class FirstOptionalDemo {
static String displayFirst(List values) {
// findFirst 把空列表建模为 Optional.empty,而不是抛出取值异常。
Optional first = values.stream().findFirst();
// 默认值只在没有首元素时使用,不覆盖真实的首元素文本。
return first.orElse("未提供");
}
}
这里不建议为了“看起来安全”而在所有地方都捕获 NoSuchElementException。异常捕获适合跨边界兜底;对普通业务分支,isEmpty() 或 findFirst() 更能说明空列表是预期状态。
把策略放进批量处理流程
在批量任务里,列表可能来自查询、配置解析或上游过滤。我的做法是把空列表处理固定成一个阶段:接收输入后记录数量,数量为零时写入明确的“无首元素”结果;只有数量大于零时才进入 getFirst()。这样既不依赖异常作为流程控制,也不会把空列表误记成一个有效首元素。

import java.util.List;
public class BatchFirstPolicy {
static String process(List values) {
// 记录数量有助于把空输入与首元素为 null 分开排查。
int count = values.size();
if (count == 0) {
return "count=0, result=DEFAULT";
}
try {
// 已经完成数量判断;这里仍保留异常边界,防止并发或自定义集合实现破坏假设。
return "count=" + count + ", first=" + values.getFirst();
} catch (RuntimeException ex) {
// 记录失败原因后交给上层决定重试、告警或拒绝本批数据。
return "count=" + count + ", result=ERROR, type=" + ex.getClass().getSimpleName();
}
}
}
如果列表在检查和读取之间可能被其他线程修改,就不要把普通的可变 ArrayList 当成并发快照。更稳妥的做法是让上游传入不可变快照,或者在进入处理阶段时复制出明确的输入版本;这属于数据所有权问题,不是 getFirst() 自己提供的并发保证。
常见问题
Java 8 能直接调用 List.getFirst 吗?
不能把它当成 Java 8 的 List 方法使用。getFirst() 来自 Java 21 引入的有序集合接口演进;需要兼容旧版运行环境时,应保留 get(0) 并自己约定空列表策略,或者升级编译和运行环境。
List.of() 为空时为什么不是返回 null?
List.of() 创建的是空列表,集合里没有“首元素”。getFirst() 按契约抛出 NoSuchElementException,这是“没有元素”的信号;只有非空且首元素本身允许为空时,才会出现元素值为 null 的情况。
不可变列表可以调用 getFirst 吗?
可以。getFirst() 是读取操作,不要求列表支持添加或删除。真正需要修改时,才要另外检查列表是否支持对应的变更操作。
应该优先使用 getFirst 还是 findFirst?
空集合是程序错误或已经被前置条件排除时,用 getFirst() 能尽早暴露问题;空集合是正常业务分支并且需要默认值或继续组合时,用 findFirst() 更合适。关键是让返回策略和业务契约一致。
总结一下:List.getFirst() 解决的是“按顺序读取第一个元素”的表达问题,不负责替你定义空集合的业务含义。先用 isEmpty()、findFirst() 或入口校验确定空列表策略,再调用它,代码会比统一捕获异常更容易维护。
Java Character.isEmoji 怎样按 Unicode 码点判断 Emoji
- 上一篇
- Java Character.isEmoji 怎样按 Unicode 码点判断 Emoji
- 下一篇
- Java ArrayList.ensureCapacity 怎样减少扩容次数
-
- 文章 · java教程 | 20分钟前 |
- Java Files.newBufferedReader 怎样指定字符集
- 240浏览 收藏
-
- 文章 · java教程 | 20分钟前 | Java · java URI getRawPath getPath 百分号转义
- Java URI.getRawPath 怎样保留路径中的百分号转义
- 180浏览 收藏
-
- 文章 · java教程 | 22分钟前 | java 夏令时 ZonedDateTime ZoneId ZoneOffset
- Java ZoneOffset 与 ZoneId 的使用差异
- 343浏览 收藏
-
- 文章 · java教程 | 25分钟前 | Java · java ArrayList ensureCapacity
- Java ArrayList.ensureCapacity 怎样减少扩容次数
- 345浏览 收藏
-
- 文章 · java教程 | 30分钟前 |
- Java Character.isEmoji 怎样按 Unicode 码点判断 Emoji
- 497浏览 收藏
-
- 文章 · java教程 | 35分钟前 |
- Java 虚拟线程为何可能被 synchronized 固定
- 351浏览 收藏
-
- 文章 · java教程 | 38分钟前 | java Parse compareTo 模块版本 ModuleDescriptor.Version
- Java ModuleDescriptor.Version 怎样比较模块版本
- 310浏览 收藏
-
- 文章 · java教程 | 53分钟前 | 异常处理 · 内存管理 · java try-with-resources release ByteBuffer ModuleReader ModuleReference 模块资源
- Java ModuleReader 读取模块资源后怎样释放 ByteBuffer
- 294浏览 收藏
-
- 文章 · java教程 | 1小时前 | 字符串 · Java · API · unicode · java stringbuilder unicode UTF-16 appendCodePoint 码点
- Java StringBuilder appendCodePoint 怎样追加 Unicode 码点
- 388浏览 收藏
-
- 文章 · java教程 | 1小时前 |
- Java instanceof 模式变量怎样避免重复强制转换
- 108浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 1029次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 1030次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 1173次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 1134次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 973次使用
-
- Java 时间格式兼容多个输入格式的方法
- 2026-10-18 501浏览
-
- Java try-with-resources 多个资源关闭顺序是什么
- 2026-09-10 501浏览
-
- 矩阵主副对角线快速定位技巧
- 2026-05-31 501浏览
-
- Java多态优化流程代码与行为分发改进
- 2026-05-26 501浏览
-
- JVM 类元数据双亲委派链表深度解析
- 2026-05-21 501浏览

