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