Как проверить, что дубликаты не добавляются в 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)
метод. Когда вы получите сообщение, поместите его в эту обертку и поместите эту обертку в коллекцию.