001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.tools; 003 004import java.util.AbstractCollection; 005import java.util.Collection; 006import java.util.Iterator; 007 008/** 009 * Filtered view of a collection. 010 * (read-only collection, but elements can be changed, of course) 011 * Lets you iterate through those elements of a given collection that satisfy a 012 * certain condition (imposed by a predicate). 013 * @param <S> element type of the underlying collection 014 * @param <T> element type of filtered collection (and subclass of S). The predicate 015 * must accept only objects of type T. 016 */ 017public class SubclassFilteredCollection<S, T extends S> extends AbstractCollection<T> { 018 019 private final Collection<? extends S> collection; 020 private final Predicate<? super S> predicate; 021 int size = -1; 022 023 private class FilterIterator implements Iterator<T> { 024 025 private final Iterator<? extends S> iterator; 026 private S current; 027 028 public FilterIterator(Iterator<? extends S> iterator) { 029 this.iterator = iterator; 030 } 031 032 private void findNext() { 033 if (current == null) { 034 while (iterator.hasNext()) { 035 current = iterator.next(); 036 if (predicate.evaluate(current)) 037 return; 038 } 039 current = null; 040 } 041 } 042 043 @Override 044 public boolean hasNext() { 045 findNext(); 046 return current != null; 047 } 048 049 @Override 050 public T next() { 051 findNext(); 052 S old = current; 053 current = null; 054 // we are save because predicate only accepts objects of type T 055 @SuppressWarnings("unchecked") T res = (T) old; 056 return res; 057 } 058 059 @Override 060 public void remove() { 061 throw new UnsupportedOperationException(); 062 } 063 } 064 065 public SubclassFilteredCollection(Collection<? extends S> collection, Predicate<? super S> predicate) { 066 this.collection = collection; 067 this.predicate = predicate; 068 } 069 070 @Override 071 public Iterator<T> iterator() { 072 return new FilterIterator(collection.iterator()); 073 } 074 075 @Override 076 public int size() { 077 if (size == -1) { 078 size = 0; 079 Iterator<T> it = iterator(); 080 while (it.hasNext()) { 081 size++; 082 it.next(); 083 } 084 } 085 return size; 086 } 087 088 @Override 089 public boolean isEmpty() { 090 return !iterator().hasNext(); 091 } 092 093}