Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have a ConcurrentLinkedQueue where I put some mails in. Now I have a visual page where I want to see what's in the Queue, but of course I do not permit that they alter the Queue in any way.

I put a getter, but instead of the Queue, I return a List. We know that the mail does disappear while we are watching, the use case permits that a refresh of the screen is enough to see the new status.

Code at the moment:

private final ConcurrentLinkedQueue<MimeMessage> mailsToSend = new ConcurrentLinkedQueue<MimeMessage>();

public List<MimeMessage> getMailsToSend() {
    return Collections.unmodifiableList(Lists.newArrayList(mailsToSend.iterator()));
}

I know, it's a very small code fragment and much review isn't there, but if there are better ways to convert it to an unmodifiable list, I'd like to hear it.

share|improve this question
up vote 2 down vote accepted

The tools in the java.util.concurrent package provide very convenient access to complicated structures that can save a lot of development time. The tools all come with a caveat though - their behaviour when accessed by multiple threads concurrently is deterministic, but not necessarily intuitive. In your code you use:

Lists.newArrayList(mailsToSend.iterator())

This converts the elements of the queue to a List... or, does it? What are the elements of the queue? By the definition of this class, the iterator is guaranteed to return all the elements in the queue at the time the iterator was created, but it may also, if it wants, return elements that were added after the iterator was created, and before it completes. Officially, it is weakly consistent:

they are guaranteed to traverse elements as they existed upon construction exactly once, and may (but are not guaranteed to) reflect any modifications subsequent to construction.

When I use tools in the concurrent library I prefer taking point-in-time copies of the data when I need it, unless I have a good reason not to. In your case, a point-in-time snapshot is what you want.

For this purpose, I prefer the toArray(...) call, which guarantees a copy of the data at the time it was called. Because you cannot tell what size the array will be, you should pas it an empty one in the constructor and it will return a bigger one if needed:

MimeMessage[] messages = mailsToSend.toArray(new MimeMessage[0]);

I would normally return this as a raw array - I like arrays. It also makes it clear that it is a defensive copy of the data.

If you want, though, you can wrap that array in a different format:

return Arrays.asList(messages);

or, even:

return Collections.unmodifiableList(Arrays.asList(mailsToSend.toArray(new MimeMessage[0])));
share|improve this answer
    
rolfl, thx for your very explaining answer. I didn't check the class documentation and I should do this do a lot more, even for "simple" things. It's maybe more consuming then @rachetfreak his answer, but I do like this approach more. I need indeed a time snapshot just for seeing what's still in the queue. (Today the queue was after a batch still 2hr busy with sending mails, so a check was wanted to see what's still need to send.) – chillworld Apr 23 '15 at 12:34

Lists.newArrayList will allocate a new list (as the name indicates) so there is no reason to wrap it in a Collections.unmodifiableList.

What you have is a defensive copy. This won't allow propagation of changes back to the queue, but requires you to get a new list each time you want an update.

If you still want a queue backed view then you should return Collections.unmodifiableCollection:

public Collection<MimeMessage> getMailsToSend() {
    return Collections.unmodifiableCollection(mailsToSend);
}

This has the downside that only way to get all items from a generic Collection is using the iterator or the toArray methods. Though each time you call it on them you get an up to date view (with the same caveats of the same methods of the queue).

share|improve this answer
    
Actually you are correct, a collection is also good. – chillworld Apr 23 '15 at 10:39

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.