Как проверить, что дубликаты не добавляются в LinkedBlockingQueue?

Я получаю сообщения от нескольких учетных записей Gmail, используя почтовый API Java. Различные учетные записи обрабатываются разными потоками, и я использую LinkedBlockingQueue хранить электронные письма. Однако я не хочу, чтобы одно и то же письмо неоднократно добавлялось в Queue, Это код, который я до сих пор:

public synchronized void readMail(){
    try {
        boolean alreadyAdded = false;
        Folder inbox = store.getFolder("Inbox");
        inbox.open(Folder.READ_ONLY);
        Message [] received = inbox.getMessages();

        if(messages.isEmpty()){
            for(Message newMessage:received){
                System.out.println("Queue empty, adding messages");
                messages.put(newMessage);
            }
        }

        else{
            for(Message existingMessage:messages){
                for(Message newMessage:received){
                    if (alreadyAdded == true)
                        break;

                    else{
                        if(existingMessage.getSubject().equals(newMessage.getSubject())){
                            alreadyAdded = true;
                            System.out.println("boolean changed to true, message "+newMessage.getSubject()+"won't be added");
                        }

                        else{
                            alreadyAdded = false;
                            System.out.println("Non-duplicate message "+newMessage.getSubject());
                            messages.put(newMessage);
                        }
                    }
                }
            }
        }
    } 
    catch (MessagingException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

У меня проблема в том, else блок после if проверка, если очередь пуста. Я хочу, чтобы он проверил набор только что прочитанных сообщений и сравнил их с сообщениями, уже находящимися в Queue, Если сообщение находится в Queue не добавляй это снова. Я не могу просто использовать .contains(), так как каждый раз, когда сообщения загружаются, им присваивается другое место в памяти, поэтому, хотя Message объект может фактически быть тем же самым (например, имеет тот же предмет, содержание и т. д.), он не будет иметь одинаковую подпись (например, при первой загрузке он может быть Messagehgshsh676767 но в следующий раз это может быть Messageyyetwt8965).

Я ударил кирпичную стену, кто-нибудь может предложить способ убедиться, что дубликаты не добавляются?

2 ответа

Вы можете создать класс-оболочку для ваших сообщений, который будет содержать правильный метод equals, основанный, например, на теме

public class MyMessage {
    final private Message msg;

    public MyMessage (final Message msg) {
        this.msg = msg;
    }

    public boolean equals (final Object other) {
        if (!(other instanceof MyMessage)) {
            return false;
        }

        final MyMessage otherMessage = (MyMessage) other;
        return msg.getSubject ().equals (otherMessage.getSubject ());
    }

    public Message getMessage () {
        return msg;
    }
}

Если вас не волнует порядок, вы можете использовать некоторую многопоточную реализацию Set

final Set<MyMessage> messages = Collections.synchronizedSet (new HashSet<MyMessage> ());

Message [] received = inbox.getMessages();
for (final Message msg : reveived) {
    messages.add (msg);
}    

Таким образом, у вас не будет дубликатов.

Если вы заботитесь о заказе, используйте SortedSet, например:

public class MyMessage implements Comparable<MyMessage> {
    ... //the same as above

    public int compareTo (final MyMessage otherMessage) {
        return msg.getReceivedDate ().compareTo (otherMessage.getReceivedDate ());
    }
}


final Set<MyMessage> messages = Collections.synchronizedSet (new TreeSet<MyMessage> ());
if(!queue.contains(element)) {
    queue.add(element);
}

Если вы хотите установить Set, вы можете расширить LinkedBlockingQueue и переопределить add:

public boolean add(E e)
    if(!this.contains(e)) {
        return super.add(e);
    } else {
        return false;
    }
}

но вы должны либо сделать это и использовать его локально, либо переопределить его должным образом - все методы и конструкторы, которые могут добавлять элементы к нему.

Что касается проблемы с содержимым, создайте оболочку для полученного сообщения и правильно внедрите public boolean equals(Object o) метод. Когда вы получите сообщение, поместите его в эту обертку и поместите эту обертку в коллекцию.

Другие вопросы по тегам