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