IteratorCachingResultSet extends WrappedResultSet<O> { @Override public Iterator<O> iterator() { if (cachedIterator != null) { return cachedIterator; } final Iterator<O> backingIterator = wrappedResultSet.iterator(); Iterator<O> wrappingIterator = new Iterator<O>() { @Override public boolean hasNext() { return backingIterator.hasNext(); } @Override public O next() { cachedIterator = null; return backingIterator.next(); } @Override public void remove() { cachedIterator = null; backingIterator.remove(); } }; this.cachedIterator = wrappingIterator; return wrappingIterator; } IteratorCachingResultSet(ResultSet<O> backingResultSet); @Override Iterator<O> iterator();  }
@Test @SuppressWarnings("unchecked") public void testIteratorCaching() { ResultSet<Car> backingResultSet = mock(ResultSet.class); when(backingResultSet.iterator()).thenReturn(mock(Iterator.class), mock(Iterator.class), mock(Iterator.class), mock(Iterator.class), mock(Iterator.class), mock(Iterator.class), mock(Iterator.class)); IteratorCachingResultSet<Car> iteratorCachingResultSet = new IteratorCachingResultSet<Car>(backingResultSet); Iterator<Car> i1 = iteratorCachingResultSet.iterator(); Iterator<Car> i2 = iteratorCachingResultSet.iterator(); assertSame(i1, i2); i2.hasNext(); i2.hasNext(); Iterator<Car> i3 = iteratorCachingResultSet.iterator(); assertSame(i1, i3); i3.next(); Iterator<Car> i4 = iteratorCachingResultSet.iterator(); assertNotSame(i3, i4); i4.remove(); Iterator<Car> i5 = iteratorCachingResultSet.iterator(); assertNotSame(i4, i5); i5.hasNext(); i5.hasNext(); Iterator<Car> i6 = iteratorCachingResultSet.iterator(); assertSame(i5, i6); iteratorCachingResultSet.isEmpty(); iteratorCachingResultSet.isNotEmpty(); Iterator<Car> i7 = iteratorCachingResultSet.iterator(); assertSame(i6, i7); }