Stackoverflow翻译(1)-java-为什么LinkedList有add()、offer()和offerLast()这三个相同效果的方法?

这篇博客详细解释了Java中`offer`和`add`方法的区别,以及为何在`Deque`接口中引入`offerFirst`和`offerLast`。`offer`方法主要用于队列,可能因队列满等原因返回`false`,而`add`方法仅在元素已存在时返回`false`。`offerLast`的引入主要是为了保持接口的对称性,尽管在实际操作中它与`addLast`并无实质区别,都是将元素添加到双端队列的末尾。博客还讨论了`Deque`接口的实现如`LinkedList`,并指出这些方法的源码实现主要是为了接口的完整性和一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我的理解

一、add和offer的不同在于,返回false的原因有无限制。

add 当且仅当该元素已经存在时返回false

offer 可出于任何原因返回false,例如 队列已满

其他是一样的。

二、为什么要加offerLast:

从offerLast的用法和效果来说,完全是和offer一样的。增加它的目的,是在Java 6增加了Deque接口后,为了实现双端队列,需要增加-first 和 -last变体,也就要增加offerFirst和offerLast。(Deque继承Queue,而Queue是单端队列,先进后出,所以只有offer()和add()方法)为了用冗余换对称性——例如add/addFirst/addLast,如果offer有offer和offerFirst,却没有offerLast,就没有“编程之美”了——所以还是增加了一个offerLast()。

而Deque接口有三种实现方式,分别是LinkedList、ArrayDeque、LinkedBlockingDeque,其中LinkedList是最常用的。

三、源码解析

因此,事实上,如果我们从源码去看的话。就以用LinkedList实现的Deque举例,可以发现

    /**
     * Appends the specified element to the end of this list.
     *
     * <p>This method is equivalent to {@link #add}.
     *
     * @param e the element to add
     */
    public void addLast(E e) {
        linkLast(e);
    }

    /**
     * Appends the specified element to the end of this list.
     *
     * <p>This method is equivalent to {@link #addLast}.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        linkLast(e);
        return true;
    }    

    /**
     * Adds the specified element as the tail (last element) of this list.
     *
     * @param e the element to add
     * @return {@code true} (as specified by {@link Queue#offer})
     * @since 1.5
     */
    public boolean offer(E e) {
        return add(e);
    }

    /**
     * Inserts the specified element at the end of this list.
     *
     * @param e the element to insert
     * @return {@code true} (as specified by {@link Deque#offerLast})
     * @since 1.6
     */
    public boolean offerLast(E e) {
        addLast(e);
        return true;
    }

可以清楚地从Java源码中的注释看到,offer方法其实是用于实现Deque接口的额外方式,而它仅仅是简单调用add里的对应方法而已:offer = add, offerLast = addLast + return true。而add其实都是对应linkLast()方法,addLast = linkLast, add = linkLast + return true。所以offer和offerLast是完全相同的方法!仅仅是为了实现对称性。(看到这里,突然觉得《编程之美》还是有必要拜读一下。)

 

原文:

The Queue interface was added in Java 5. It defined the offer method, which adds an element at the end.

(The offer method and the add method both return booleans. They differ in that add is permitted to reject the element and return false only if the element is already present in the collection. The offer method can reject the element for other reasons, such as the queue being full.)

With Queue.offer, there is little question about the semantics, as elements are generally added to the tail of a queue and removed from the head.

The Deque interface was added in Java 6. A deque allows elements to be added to and removed from both the head and tail, so Deque defines offerFirst and offerLast methods. A deque is also a queue, so Deque is a sub-interface of Queue. Thus it inherits the offer method from Queue. That's how Deque ends up with both offer and offerLast.

We probably could have gotten by without adding offerLast, but that would have left asymmetries in the Deque interface. Many operations work on both the head and the tail (add, get, offer, peek, poll, remove) so it makes sense for all of them to have -first and -last variants, even though this adds redundancy. This redundancy occurs with other Queue methods as well, such as add and addLastpeek and peekFirstpoll and pollFirst, and remove and removeFirst.

 

写在最后:

这个系列是我在国内百度搜不到回答和解决方法的情况下,在Google找到回答和解决方法后,搬运回国的。不一定只有Stackoverflow的内容,也可能包含其他来源的答案;翻译也不一定是按原文翻译,是我基于对原文的理解给出的最简洁的解释。只要是国内百度解决不了而必须翻墙找的问题,我都会发在这个专栏。

### 频繁调用 `new` 导致异常的原因 频繁调用 `new` 可能会引发多种类型的异常,主要取决于内存分配的情况以及对象初始化逻辑的设计。以下是可能的原因: 1. **OutOfMemoryError**: 如果程序频繁创建大量对象而未及时释放无用的对象,则可能导致堆内存耗尽,从而触发 `java.lang.OutOfMemoryError`[^4]。 2. **StackOverflowError**: 当通过构造函数或其他方法递归调用 `new` 创建对象时,可能会超出 JVM 的栈空间限制,进而抛出 `java.lang.StackOverflowError`[^5]。 3. **IllegalStateException 或其他自定义异常**: 若某些资源(如文件句柄、数据库连接等)在实例化过程中未能正确获取或配置不当,也可能导致特定业务场景中的异常发生。 --- ### 解决方案 针对上述问题,可以从以下几个方面入手优化代码并减少因频繁调用 `new` 而产生的异常风险: #### 1. 使用对象池技术降低开销 对于需要频繁创建销毁短生命周期对象的情形,可采用对象池模式来复用已存在的实例而非每次都执行新的分配动作。这样不仅能够节省内存还能提高性能效率。例如,在多线程环境下管理数据库连接时常运用此策略[^6]: ```java public class ObjectPool<T> { private final Queue<T> pool; public ObjectPool(int size, Supplier<T> factory) { this.pool = new LinkedList<>(); for (int i=0;i<size;i++) { pool.add(factory.get()); } } public synchronized T acquire() { return pool.poll(); } public synchronized void release(T obj){ if(obj != null && !pool.contains(obj)){ pool.offer(obj); } } } ``` #### 2. 合理调整JVM参数控制内存大小 适当增加最大堆容量(-Xmx),或者调节新生代与老年代比例(-XX:NewRatio=N),使得GC更高效地回收垃圾数据,避免因为物理内存不足而导致OOM错误的发生[^7]. #### 3. 检查是否存在不必要的循环引用或深层嵌套结构 如果发现某个类内部存在复杂的数据成员关系链路较长的话,应该重新审视其设计思路看能否简化关联程度以便于更快完成清理工作;另外也要注意防范死锁现象出现影响正常退出流程造成资源泄露等问题的存在[^8]. #### 4. 对象懒加载机制的应用 延迟到真正需要用到的时候再去构建实际实体而不是一开始就全部准备好等待后续使用的机会到来再决定是否真的有必要这样做可以有效缓解前期压力过大情况下的崩溃隐患[^9]. ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值