FilteringStateChangeListenable implements StateChangeListenable<C> { @Override public UnmodifiableIterator<C> iterator() { return new UnmodifiableIterator<C>() { private final UnmodifiableIterator<T> backingIterator = backingListenable.iterator(); private @CheckForNull C nextValue = backingNext(); @Override public boolean hasNext() { return nextValue != null; } @Override public C next() { C c = nextValue; if (c == null) { throw new NoSuchElementException(); } nextValue = backingNext(); return c; } private C backingNext() { C c = null; while (c == null && backingIterator.hasNext()) { c = mapAndFilter.apply(backingIterator.next()); } return c; } }; } FilteringStateChangeListenable(StateChangeListenable<T> backingListenable, Function<? super T, C> mapAndFilter); @Override T registerCustomIndex(T index); @Override void registerStateAddedOrRemovedListener(Consumer<? super C> consumer); @Override void registerStateChangeListener(CacheStateChangeListener<? super C> listener); @Override void registerStateAddedListener(CacheStateAddedListener<? super C> listener); @Override void registerStateRemovedListener(CacheStateRemovedListener<? super C> listener); @Override Stream<C> stream(); @Override UnmodifiableIterator<C> iterator(); @Override void registerAtomicStateChangeListener(AtomicStateChangeListener<? super C> listener); @Override void removeStateChangeListener(CacheStateChangeListener<? super C> listener);  }
@Test void whenOnlyListeningForExtendedStates_thenIteratorOnlyReturnsThemInOrder() { cache.add(state1); cache.add(extended1); cache.add(state2); cache.add(extended2); UnmodifiableIterator<ExtendedTestState> iterator = (new FilteringStateChangeListenable<>(cache, this::asExtended)).iterator(); assertTrue(iterator.hasNext()); assertEquals(extended1, iterator.next()); assertTrue(iterator.hasNext()); assertEquals(extended2, iterator.next()); assertFalse(iterator.hasNext()); }