001 // License: GPL. For details, see LICENSE file. 002 package org.openstreetmap.josm.tools; 003 004 import java.util.AbstractCollection; 005 import java.util.Collection; 006 import 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 */ 017 public 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 public boolean hasNext() { 044 findNext(); 045 return current != null; 046 } 047 048 public T next() { 049 findNext(); 050 S old = current; 051 current = null; 052 // we are save because predicate only accepts objects of type T 053 @SuppressWarnings("unchecked") T res = (T) old; 054 return res; 055 } 056 057 public void remove() { 058 throw new UnsupportedOperationException(); 059 } 060 } 061 062 public SubclassFilteredCollection(Collection<? extends S> collection, Predicate<? super S> predicate) { 063 this.collection = collection; 064 this.predicate = predicate; 065 } 066 067 @Override 068 public Iterator<T> iterator() { 069 return new FilterIterator(collection.iterator()); 070 } 071 072 @Override 073 public int size() { 074 if (size == -1) { 075 size = 0; 076 Iterator<T> it = iterator(); 077 while (it.hasNext()) { 078 size++; 079 it.next(); 080 } 081 } 082 return size; 083 } 084 085 @Override 086 public boolean isEmpty() { 087 return !iterator().hasNext(); 088 } 089 090 }