poll()返回null、remove()抛异常,因前者视空队列为正常分支,后者视为错误需强制处理;peek()与element()同理;add()假设无限容量,offer()面向有界场景返回false;arraydeque禁null以提升性能并避免歧义。

poll() 和 remove() 为什么一个返回 null,一个抛异常?
核心就一条:你是否愿意为“队列为空”这个常见情况写 try-catch。remove() 把空队列当成错误场景,强制你处理;poll() 把它当成正常分支,直接返回 null 让你判断。
- 常见错误现象:
remove()在空Queue上调用,立刻炸出NoSuchElementException,线上日志里突然冒一堆这个,八成是忘了判空 - 使用场景:
poll()更适合循环取任务(比如消费者线程),你本来就要检查是否取到元素;remove()适合你**100% 确认队列非空**的场合,比如刚offer()了一个元素马上要拿走 - 性能影响:两者底层逻辑几乎一样,差异只在空值处理路径,性能可忽略不计
peek() 和 element() 的 null vs 异常之争
和上面一对是镜像关系:peek() 安全地“瞄一眼”,element() 是“必须看到头元素,看不到就翻脸”。
- 常见错误现象:
element()在空队列上调用,同样抛NoSuchElementException,但比remove()更隐蔽——因为没删元素,你以为只是读操作不会出事 - 使用场景:做 BFS 遍历时,常用
queue.peek() != null判断是否继续循环;而element()几乎只出现在单元测试断言里,比如assertThat(queue.element()).isEqualTo(42) - 兼容性注意:
ArrayDeque和LinkedList都支持null入队(虽然不推荐),但PriorityQueue明确禁止null,用peek()或element()都会触发NullPointerException
add() 和 offer() 不只是“抛异常 or 返回 false”的区别
表面看是异常策略不同,但背后藏着容量语义的根本分歧。
-
add()假设队列“理论上无限”——LinkedList和ArrayDeque确实如此,所以它几乎不会失败;但一旦你换成有界队列(比如ArrayBlockingQueue),add()就成了定时炸弹 -
offer()是为真实世界设计的:它不假设容量,也不隐藏失败。返回false就是明确告诉你“这次塞不进去了”,你可以重试、降级或打告警 - 容易踩的坑:用
add()往PriorityQueue插入null,会直接抛NullPointerException(不是IllegalStateException)——因为PriorityQueue对null是零容忍,这点offer()也一样
为什么 ArrayDeque 是默认首选,但它不让你存 null?
不是它“故意刁难”,而是设计取舍:去掉对 null 的分支判断,换来更快的 offer()/poll() 性能,且避免 peek() 返回 null 时分不清“队列空”还是“存了个 null”。
- 实际影响:
ArrayDeque的poll()和peek()返回null,只代表队列空;而LinkedList允许存null,导致peek() == null无法区分是空队列还是队首刚好是null - 迁移提醒:如果你旧代码依赖
LinkedList存null,切到ArrayDeque会编译不过(offer(null)直接报错),别等运行时报 NPE 才发现 - 替代方案:真需要存
null,用LinkedList;但更建议把null包装成一个哨兵对象(比如Optional.empty()),语义更清晰
PriorityQueue 不守 FIFO,ArrayDeque 拒绝 null,ConcurrentLinkedQueue 的 size() 还不准。别光记接口,得盯住手里的那个具体类。










