Search code examples
javaloopsblockingqueue

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!


Solution

  • 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:


    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);
    }