View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections4.set;
18  
19  import java.io.Serializable;
20  import java.util.Collection;
21  import java.util.Iterator;
22  import java.util.Map;
23  import java.util.Objects;
24  import java.util.Set;
25  import java.util.function.Predicate;
26  
27  /**
28   * Decorates a {@code Map} to obtain {@code Set} behavior.
29   * <p>
30   * This class is used to create a {@code Set} with the same properties as
31   * the key set of any map. Thus, a ReferenceSet can be created by wrapping a
32   * {@code ReferenceMap} in an instance of this class.
33   * </p>
34   * <p>
35   * Most map implementation can be used to create a set by passing in dummy values.
36   * Exceptions include {@code BidiMap} implementations, as they require unique values.
37   * </p>
38   *
39   * @param <E> the type of the elements in this set
40   * @param <V> the dummy value type in this map
41   * @since 3.1
42   */
43  public final class MapBackedSet<E, V> implements Set<E>, Serializable {
44  
45      /** Serialization version */
46      private static final long serialVersionUID = 6723912213766056587L;
47  
48      /**
49       * Factory method to create a set from a map.
50       *
51       * @param <E> the element type
52       * @param <V> the dummy value type in the map
53       * @param map  the map to decorate, must not be null
54       * @return a new map backed set
55       * @throws NullPointerException if map is null
56       * @since 4.0
57       */
58      public static <E, V> MapBackedSet<E, V> mapBackedSet(final Map<E, ? super V> map) {
59          return mapBackedSet(map, null);
60      }
61  
62      /**
63       * Factory method to create a set from a map.
64       *
65       * @param <E> the element type
66       * @param <V> the dummy value type in the map
67       * @param map  the map to decorate, must not be null
68       * @param dummyValue  the dummy value to use
69       * @return a new map backed set
70       * @throws NullPointerException if map is null
71       * @since 4.0
72       */
73      public static <E, V> MapBackedSet<E, V> mapBackedSet(final Map<E, ? super V> map, final V dummyValue) {
74          return new MapBackedSet<>(map, dummyValue);
75      }
76  
77      /** The map being used as the backing store */
78      private final Map<E, ? super V> map;
79  
80      /** The dummyValue to use */
81      private final V dummyValue;
82  
83      /**
84       * Constructor that wraps (not copies).
85       *
86       * @param map  the map to decorate, must not be null
87       * @param dummyValue  the dummy value to use
88       * @throws NullPointerException if map is null
89       */
90      private MapBackedSet(final Map<E, ? super V> map, final V dummyValue) {
91          this.map = Objects.requireNonNull(map, "map");
92          this.dummyValue = dummyValue;
93      }
94  
95      @Override
96      public boolean add(final E obj) {
97          final int size = map.size();
98          map.put(obj, dummyValue);
99          return map.size() != size;
100     }
101 
102     @Override
103     public boolean addAll(final Collection<? extends E> coll) {
104         final int size = map.size();
105         for (final E e : coll) {
106             map.put(e, dummyValue);
107         }
108         return map.size() != size;
109     }
110 
111     @Override
112     public void clear() {
113         map.clear();
114     }
115 
116     @Override
117     public boolean contains(final Object obj) {
118         return map.containsKey(obj);
119     }
120 
121     @Override
122     public boolean containsAll(final Collection<?> coll) {
123         return map.keySet().containsAll(coll);
124     }
125 
126     @Override
127     public boolean equals(final Object obj) {
128         return map.keySet().equals(obj);
129     }
130 
131     @Override
132     public int hashCode() {
133         return map.keySet().hashCode();
134     }
135 
136     @Override
137     public boolean isEmpty() {
138         return map.isEmpty();
139     }
140 
141     @Override
142     public Iterator<E> iterator() {
143         return map.keySet().iterator();
144     }
145 
146     @Override
147     public boolean remove(final Object obj) {
148         final int size = map.size();
149         map.remove(obj);
150         return map.size() != size;
151     }
152 
153     @Override
154     public boolean removeAll(final Collection<?> coll) {
155         return map.keySet().removeAll(coll);
156     }
157 
158     /**
159      * @since 4.4
160      */
161     @Override
162     public boolean removeIf(final Predicate<? super E> filter) {
163         return map.keySet().removeIf(filter);
164     }
165 
166     @Override
167     public boolean retainAll(final Collection<?> coll) {
168         return map.keySet().retainAll(coll);
169     }
170 
171     @Override
172     public int size() {
173         return map.size();
174     }
175 
176     @Override
177     public Object[] toArray() {
178         return map.keySet().toArray();
179     }
180 
181     @Override
182     public <T> T[] toArray(final T[] array) {
183         return map.keySet().toArray(array);
184     }
185 
186 }