如何使用循环从 Java 中的队列中删除元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26479052/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to remove elements from a queue in Java with a loop
提问by Josh
I have a data structure like this:
我有一个这样的数据结构:
BlockingQueue mailbox = new LinkedBlockingQueue();
BlockingQueue 邮箱 = new LinkedBlockingQueue();
I'm trying to do this:
我正在尝试这样做:
for(Mail mail: mailbox)
{
if(badNews(mail))
{
mailbox.remove(mail);
}
}
Obviously the contents of the loop interfere with the bounds and a error is triggered, so I would normally do this:
显然循环的内容会干扰边界并触发错误,所以我通常会这样做:
for(int i = 0; i < mailbox.size(); i++)
{
if(badNews(mailbox.get(i)))
{
mailbox.remove(i);
i--;
}
}
But sadly BlockingQueue's don't have a function to get or remove an element by index, so I'm stuck. Any ideas?
但遗憾的是 BlockingQueue 没有通过索引获取或删除元素的功能,所以我被卡住了。有任何想法吗?
Edit - A few clarifications: One of my goals is the maintain the same ordering so popping from the head and putting it back into the tail is no good. Also, although no other threads will remove mail from a mailbox, they will add to it, so I don't want to be in the middle of an removal algorithm, have someone send me mail, and then have an exception occur.
编辑 - 一些澄清:我的目标之一是保持相同的顺序,因此从头部弹出并将其放回尾部是不好的。此外,虽然没有其他线程会从邮箱中删除邮件,但它们会添加到邮箱中,所以我不想处于删除算法的中间,有人给我发送邮件,然后发生异常。
Thanks in advance!
提前致谢!
采纳答案by Luiggi Mendoza
You may p?o?p? poll
and p?u?s?h? offer
all the elements in your queue until you make a complete loop over your queue. Here's an example:
你可以 p?o?p? poll
p?u?s?h? offer
队列中的所有元素,直到您对队列进行完整循环。下面是一个例子:
Mail firstMail = mailbox.peek();
Mail currentMail = mailbox.pop();
while (true) {
//a base condition to stop the loop
Mail tempMail = mailbox.peek();
if (tempMail == null || tempMail.equals(firstMail)) {
mailbox.offer(currentMail);
break;
}
//if there's nothing wrong with the current mail, then re add to mailbox
if (!badNews(currentMail)) {
mailbox.offer(currentMail);
}
currentMail = mailbox.poll();
}
Note that this approach will work only if this code is executed in a single thread and there's no other thread that removes items from this queue.
请注意,此方法仅在此代码在单个线程中执行并且没有其他线程从该队列中删除项目时才有效。
Maybe you need to check if you really want to poll or take the elements from the BlockingQueue. Similar for offer and put.
也许您需要检查是否真的要轮询或从 BlockingQueue 中获取元素。类似的报价和看跌。
More info:
更多信息:
Another less buggy approach is using a temporary collection, not necessarily concurrent, and store the elements you still need in the queue. Here's a kickoff example:
另一种错误较少的方法是使用临时集合,不一定是并发的,并将您仍然需要的元素存储在队列中。这是一个启动示例:
List<Mail> mailListTemp = new ArrayList<>();
while (mailbox.peek() != null) {
Mail mail = mailbox.take();
if (!badNews(mail)) {
mailListTemp.add(mail);
}
}
for (Mail mail : mailListTemp) {
mailbox.offer(mail);
}
回答by Josh
I looked over the solutions posted and I think I found a version that serves my purposes. What do you think about this one?
我查看了发布的解决方案,我想我找到了一个符合我目的的版本。你怎么看这个?
int size = mailbox.size();
for(int i = 0; i < size; i++)
{
Mail currentMail = mailbox.poll();
if (!badNews(currentMail))
mailbox.offer(currentMail);
}
Edit: A new solution that may be problem free. What you guys think?
编辑:一个可能没有问题的新解决方案。大家怎么看?
while(true)
{
boolean badNewRemains = false;
for(Mail mail: mailbox)
{
if(badNews(mail))
{
badNewRemains = true;
mailbox.remove(mail);
break;
}
}
if(!badNewRemains)
break;
}
回答by nullptr
You can easily implement queue for your need. And you will need to, if API provided doesn't have such features.
您可以根据需要轻松实现队列。如果提供的 API 没有此类功能,您将需要这样做。
One like:
一个喜欢:
import java.util.Iterator;
import java.util.LinkedList;
class Mail {
boolean badMail;
}
class MailQueue {
private LinkedList<Mail> backingQueue = new LinkedList<>();
private final Object lock = new Object();
public void push(Mail mail){
synchronized (lock) {
backingQueue.addLast(mail);
if(backingQueue.size() == 1){
// this is only element in queue, i.e. queue was empty before, so invoke if any thread waiting for mails in queue.
lock.notify();
}
}
}
public Mail pop() throws InterruptedException{
synchronized (lock) {
while(backingQueue.isEmpty()){
// no elements in queue, wait.
lock.wait();
}
return backingQueue.removeFirst();
}
}
public boolean removeBadMailsInstantly() {
synchronized (lock) {
boolean removed = false;
Iterator<Mail> iterator = backingQueue.iterator();
while(iterator.hasNext()){
Mail mail = iterator.next();
if(mail.badMail){
iterator.remove();
removed = true;
}
}
return removed;
}
}
}
The implemented queue will be thread-safe, whether push or pop. Also you can edit queue for more operations. And it will allow to access removeBadMailsInstantly
method by multiple threads (thread-safe). And you will also learn concepts of multithreading.
实现的队列将是线程安全的,无论是推送还是弹出。您也可以编辑队列以进行更多操作。并且它将允许removeBadMailsInstantly
通过多个线程(线程安全)访问方法。您还将学习多线程的概念。