I love vacation: a chance to stretch my coding fingers free of work! Here is a code snack I thought of while daydreaming today—enjoy!
public final class BlockingIterable { public static <E> Until<E> over(final BlockingQueue<E> queue) { return new Until<E>(queue); } public static class Until<E> { private final BlockingQueue<E> queue; private Until(final BlockingQueue<E> queue) { this.queue = queue; } public Iterable<E> until(final E poison) { return new Iterable<E>() { @Override public Iterator<E> iterator() { return new Iterator<E>() { private E next = poison; @Override public boolean hasNext() { try { return poison != (next = queue.take()); } catch (final InterruptedException e) { currentThread().interrupt(); next = poison; return false; } } @Override public E next() { if (poison == next) throw new NoSuchElementException(); return next; } @Override public void remove() { throw new UnsupportedOperationException(); } }; } }; } } }
3 comments:
Might as well take in a Queue rather than a BlockingQueue and allow it to apply to more cases, no?
@Bryan: I picked the blocking variety to avoid handling an empty but not yet poisoned queue. Hence, I can use take() and wait until an element arrives.
I am a little lost what to do with general Queue for the empty case. Iterator is not, generally speaking, a good interface for threaded use. The disconnection between hasNext() and next() requires callers to coordinate instead of the iterator to handle it internally.
That, in fact, is a blog post I'm thinking about writing up soon, an how non-local break in a closure solves it neatly. :)
Ah, good points. I now understand the purpose of this code better.
Post a Comment