source: josm/trunk/src/org/openstreetmap/josm/tools/SubclassFilteredCollection.java@ 16552

Last change on this file since 16552 was 16061, checked in by simon04, 4 years ago

SubclassFilteredCollection: use spliteratorUnknownSize() to avoid expensive call to size()

  • Property svn:eol-style set to native
File size: 3.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import java.util.AbstractCollection;
5import java.util.Collection;
6import java.util.Iterator;
7import java.util.NoSuchElementException;
8import java.util.Objects;
9import java.util.Spliterator;
10import java.util.Spliterators;
11import java.util.function.Predicate;
12
13/**
14 * Filtered view of a collection.
15 * (read-only collection, but elements can be changed, of course)
16 * Lets you iterate through those elements of a given collection that satisfy a
17 * certain condition (imposed by a predicate).
18 * <p>
19 * The behaviour of this class is undefined if the underlying collection is changed.
20 * @param <S> element type of the underlying collection
21 * @param <T> element type of filtered collection (and subclass of S). The predicate
22 * must accept only objects of type T.
23 * @since 3147
24 */
25public class SubclassFilteredCollection<S, T extends S> extends AbstractCollection<T> {
26
27 private final Collection<? extends S> collection;
28 private final Predicate<? super S> predicate;
29 private int size = -1;
30
31 private class FilterIterator implements Iterator<T> {
32
33 private final Iterator<? extends S> iterator;
34 private S current;
35
36 FilterIterator(Iterator<? extends S> iterator) {
37 this.iterator = iterator;
38 }
39
40 private void findNext() {
41 if (current == null) {
42 while (iterator.hasNext()) {
43 current = iterator.next();
44 if (predicate.test(current))
45 return;
46 }
47 current = null;
48 }
49 }
50
51 @Override
52 public boolean hasNext() {
53 findNext();
54 return current != null;
55 }
56
57 @SuppressWarnings("unchecked")
58 @Override
59 public T next() {
60 if (!hasNext())
61 throw new NoSuchElementException();
62 S old = current;
63 current = null;
64 // we are save because predicate only accepts objects of type T
65 return (T) old;
66 }
67
68 @Override
69 public void remove() {
70 throw new UnsupportedOperationException();
71 }
72 }
73
74 /**
75 * Constructs a new {@code SubclassFilteredCollection}.
76 * @param collection The base collection to filter
77 * @param predicate The predicate to use as filter
78 * @see #filter(Collection, Predicate) for an alternative way to construct this.
79 */
80 public SubclassFilteredCollection(Collection<? extends S> collection, Predicate<? super S> predicate) {
81 this.collection = Objects.requireNonNull(collection);
82 this.predicate = Objects.requireNonNull(predicate);
83 }
84
85 @Override
86 public Iterator<T> iterator() {
87 return new FilterIterator(collection.iterator());
88 }
89
90 @Override
91 public Spliterator<T> spliterator() {
92 return Spliterators.spliteratorUnknownSize(iterator(), 0);
93 }
94
95 @Override
96 public int size() {
97 if (size == -1) {
98 size = 0;
99 forEach(t -> size++);
100 }
101 return size;
102 }
103
104 @Override
105 public boolean isEmpty() {
106 return !iterator().hasNext();
107 }
108
109 /**
110 * Create a new filtered collection without any constraints on the predicate type.
111 * @param <T> The collection type.
112 * @param collection The collection to filter.
113 * @param predicate The predicate to filter for.
114 * @return The filtered collection. It is a {@code Collection<T>}.
115 */
116 public static <T> SubclassFilteredCollection<T, T> filter(Collection<? extends T> collection, Predicate<T> predicate) {
117 return new SubclassFilteredCollection<>(collection, predicate);
118 }
119}
Note: See TracBrowser for help on using the repository browser.