在 Java 中查询队列首元素并移除有多种方式,具体取决于使用的队列类型。以下是详细的实现方法:

1. Queue 接口的标准方法

poll() 方法(推荐)

import java.util.LinkedList;
import java.util.Queue;

public class PollExample {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();
        queue.offer("A");
        queue.offer("B");
        queue.offer("C");
        
        System.out.println("原始队列: " + queue); // [A, B, C]
        
        // 查询并移除首元素
        String firstElement = queue.poll();
        System.out.println("移除的元素: " + firstElement); // A
        System.out.println("剩余队列: " + queue); // [B, C]
        
        // 队列为空时返回 null
        Queue<String> emptyQueue = new LinkedList<>();
        String result = emptyQueue.poll();
        System.out.println("空队列poll结果: " + result); // null
    }
}

remove() 方法

import java.util.LinkedList;
import java.util.Queue;

public class RemoveExample {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();
        queue.offer("A");
        queue.offer("B");
        
        System.out.println("原始队列: " + queue); // [A, B]
        
        // 查询并移除首元素
        String firstElement = queue.remove();
        System.out.println("移除的元素: " + firstElement); // A
        System.out.println("剩余队列: " + queue); // [B]
        
        // 队列为空时抛出异常
        try {
            Queue<String> emptyQueue = new LinkedList<>();
            emptyQueue.remove(); // 抛出 NoSuchElementException
        } catch (Exception e) {
            System.out.println("异常: " + e.getClass().getSimpleName());
        }
    }
}

2. 阻塞队列的方法

take() 方法(阻塞等待)

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class TakeExample {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> queue = new LinkedBlockingQueue<>();
        
        // 生产者线程
        Thread producer = new Thread(() -> {
            try {
                Thread.sleep(1000); // 延迟1秒后添加元素
                queue.put("数据A");
                System.out.println("生产者: 添加了数据A");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        // 消费者线程
        Thread consumer = new Thread(() -> {
            try {
                System.out.println("消费者: 等待获取数据...");
                String data = queue.take(); // 阻塞直到有数据
                System.out.println("消费者: 获取到数据: " + data);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        consumer.start();
        producer.start();
        
        consumer.join();
        producer.join();
    }
}

poll(timeout) 方法(带超时)

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class PollTimeoutExample {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> queue = new LinkedBlockingQueue<>();
        
        // 尝试获取元素,最多等待2秒
        String result = queue.poll(2, TimeUnit.SECONDS);
        System.out.println("2秒后结果: " + result); // null
        
        // 添加元素后再尝试
        queue.offer("测试数据");
        result = queue.poll(1, TimeUnit.SECONDS);
        System.out.println("有数据时结果: " + result); // 测试数据
    }
}

3. 双端队列(Deque)的方法

pollFirst() 和 pollLast()

import java.util.ArrayDeque;
import java.util.Deque;

public class DequePollExample {
    public static void main(String[] args) {
        Deque<String> deque = new ArrayDeque<>();
        deque.offerLast("A");
        deque.offerLast("B");
        deque.offerLast("C");
        
        System.out.println("原始队列: " + deque); // [A, B, C]
        
        // 从头部移除
        String first = deque.pollFirst();
        System.out.println("移除头部: " + first); // A
        System.out.println("剩余队列: " + deque); // [B, C]
        
        // 从尾部移除
        String last = deque.pollLast();
        System.out.println("移除尾部: " + last); // C
        System.out.println("剩余队列: " + deque); // [B]
    }
}

4. 优先级队列

import java.util.PriorityQueue;
import java.util.Queue;

public class PriorityQueuePollExample {
    public static void main(String[] args) {
        // 最小堆(自然顺序)
        Queue<Integer> minHeap = new PriorityQueue<>();
        minHeap.offer(5);
        minHeap.offer(1);
        minHeap.offer(3);
        
        System.out.println("优先级队列内容(无序): " + minHeap);
        
        // 按优先级顺序移除
        while (!minHeap.isEmpty()) {
            Integer element = minHeap.poll();
            System.out.println("移除: " + element);
        }
        
        // 自定义优先级(最大堆)
        Queue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);
        maxHeap.offer(5);
        maxHeap.offer(1);
        maxHeap.offer(3);
        
        System.out.println("\n最大堆移除顺序:");
        while (!maxHeap.isEmpty()) {
            System.out.println("移除: " + maxHeap.poll());
        }
    }
}

5. 线程安全的并发队列

ConcurrentLinkedQueue

import java.util.concurrent.ConcurrentLinkedQueue;

public class ConcurrentPollExample {
    public static void main(String[] args) {
        ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
        queue.offer("任务1");
        queue.offer("任务2");
        queue.offer("任务3");
        
        // 多线程安全地移除元素
        Runnable task = () -> {
            String item;
            while ((item = queue.poll()) != null) {
                System.out.println(Thread.currentThread().getName() + " 处理: " + item);
            }
        };
        
        Thread t1 = new Thread(task, "线程1");
        Thread t2 = new Thread(task, "线程2");
        
        t1.start();
        t2.start();
        
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

6. 延迟队列(DelayQueue)

import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

class DelayedItem implements Delayed {
    private final String data;
    private final long expireTime;
    
    public DelayedItem(String data, long delayMs) {
        this.data = data;
        this.expireTime = System.currentTimeMillis() + delayMs;
    }
    
    @Override
    public long getDelay(TimeUnit unit) {
        long diff = expireTime - System.currentTimeMillis();
        return unit.convert(diff, TimeUnit.MILLISECONDS);
    }
    
    @Override
    public int compareTo(Delayed other) {
        return Long.compare(this.expireTime, ((DelayedItem) other).expireTime);
    }
    
    @Override
    public String toString() {
        return data;
    }
}

public class DelayQueuePollExample {
    public static void main(String[] args) throws InterruptedException {
        DelayQueue<DelayedItem> queue = new DelayQueue<>();
        
        queue.offer(new DelayedItem("任务A", 3000)); // 3秒后可用
        queue.offer(new DelayedItem("任务B", 1000)); // 1秒后可用
        queue.offer(new DelayedItem("任务C", 2000)); // 2秒后可用
        
        System.out.println("开始处理延迟任务...");
        
        while (!queue.isEmpty()) {
            DelayedItem item = queue.poll(); // 只返回已到期的元素
            if (item != null) {
                System.out.println("处理: " + item);
            } else {
                System.out.println("没有到期任务,等待...");
                Thread.sleep(500);
            }
        }
    }
}

7. 实用工具方法

import java.util.LinkedList;
import java.util.Queue;

public class QueueUtils {
    
    /**
     * 安全地获取并移除队列首元素(避免异常)
     */
    public static <T> T safePoll(Queue<T> queue) {
        return queue != null ? queue.poll() : null;
    }
    
    /**
     * 批量处理队列元素
     */
    public static <T> void processQueue(Queue<T> queue, int batchSize) {
        for (int i = 0; i < batchSize && !queue.isEmpty(); i++) {
            T element = queue.poll();
            if (element != null) {
                System.out.println("处理: " + element);
            }
        }
    }
    
    /**
     * 转移队列元素到另一个队列
     */
    public static <T> void transferQueue(Queue<T> source, Queue<T> target, int maxElements) {
        for (int i = 0; i < maxElements && !source.isEmpty(); i++) {
            T element = source.poll();
            if (element != null) {
                target.offer(element);
            }
        }
    }
    
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();
        queue.offer("A");
        queue.offer("B");
        queue.offer("C");
        
        System.out.println("批量处理:");
        processQueue(queue, 2);
        System.out.println("剩余队列: " + queue);
    }
}

8. 方法对比总结

方法 行为 空队列时 适用场景
poll() 移除并返回首元素 返回 null 推荐使用,避免异常
remove() 移除并返回首元素 抛出异常 需要明确处理空队列
take() 阻塞直到有元素 一直阻塞 生产消费模式
poll(timeout) 带超时的等待 超时返回 null 需要控制等待时间

最佳实践建议:

  • 大多数情况下使用 poll() 方法
  • 生产消费场景使用阻塞队列的 take() 方法
  • 需要超时控制时使用 poll(timeout) 方法
  • 只在确定队列不为空时使用 remove() 方法
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐