Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove elements from a queue in Java with a loop

I have a data structure like this:

BlockingQueue mailbox = 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?

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!

like image 361
Josh Avatar asked Oct 21 '14 04:10

Josh


People also ask

How do I remove a specific element from a queue in Java?

Queue remove() method in Java The remove() method of Queue Interface returns and removes the element at the front of the container. It deletes the head of the container. The method throws an NoSuchElementException when the Queue is empty. Returns: This method returns the head of the Queue.

Can I remove element while iterating list Java?

An element can be removed from a Collection using the Iterator method remove(). This method removes the current element in the Collection. If the remove() method is not preceded by the next() method, then the exception IllegalStateException is thrown. A program that demonstrates this is given as follows.

Can you remove elements in a for each loop?

The program needs access to the iterator in order to remove the current element. The for-each loop hides the iterator, so you cannot call remove . Therefore, the for-each loop is not usable for filtering.


1 Answers

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:

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.

More info:

  • Java BlockingQueue take() vs poll()
  • LinkedBlockingQueue put vs offer

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);
}
like image 167
Luiggi Mendoza Avatar answered Oct 09 '22 12:10

Luiggi Mendoza