Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/util/HashSet.java
38829 views
/*1* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.util;2627import java.io.InvalidObjectException;28import sun.misc.SharedSecrets;2930/**31* This class implements the <tt>Set</tt> interface, backed by a hash table32* (actually a <tt>HashMap</tt> instance). It makes no guarantees as to the33* iteration order of the set; in particular, it does not guarantee that the34* order will remain constant over time. This class permits the <tt>null</tt>35* element.36*37* <p>This class offers constant time performance for the basic operations38* (<tt>add</tt>, <tt>remove</tt>, <tt>contains</tt> and <tt>size</tt>),39* assuming the hash function disperses the elements properly among the40* buckets. Iterating over this set requires time proportional to the sum of41* the <tt>HashSet</tt> instance's size (the number of elements) plus the42* "capacity" of the backing <tt>HashMap</tt> instance (the number of43* buckets). Thus, it's very important not to set the initial capacity too44* high (or the load factor too low) if iteration performance is important.45*46* <p><strong>Note that this implementation is not synchronized.</strong>47* If multiple threads access a hash set concurrently, and at least one of48* the threads modifies the set, it <i>must</i> be synchronized externally.49* This is typically accomplished by synchronizing on some object that50* naturally encapsulates the set.51*52* If no such object exists, the set should be "wrapped" using the53* {@link Collections#synchronizedSet Collections.synchronizedSet}54* method. This is best done at creation time, to prevent accidental55* unsynchronized access to the set:<pre>56* Set s = Collections.synchronizedSet(new HashSet(...));</pre>57*58* <p>The iterators returned by this class's <tt>iterator</tt> method are59* <i>fail-fast</i>: if the set is modified at any time after the iterator is60* created, in any way except through the iterator's own <tt>remove</tt>61* method, the Iterator throws a {@link ConcurrentModificationException}.62* Thus, in the face of concurrent modification, the iterator fails quickly63* and cleanly, rather than risking arbitrary, non-deterministic behavior at64* an undetermined time in the future.65*66* <p>Note that the fail-fast behavior of an iterator cannot be guaranteed67* as it is, generally speaking, impossible to make any hard guarantees in the68* presence of unsynchronized concurrent modification. Fail-fast iterators69* throw <tt>ConcurrentModificationException</tt> on a best-effort basis.70* Therefore, it would be wrong to write a program that depended on this71* exception for its correctness: <i>the fail-fast behavior of iterators72* should be used only to detect bugs.</i>73*74* <p>This class is a member of the75* <a href="{@docRoot}/../technotes/guides/collections/index.html">76* Java Collections Framework</a>.77*78* @param <E> the type of elements maintained by this set79*80* @author Josh Bloch81* @author Neal Gafter82* @see Collection83* @see Set84* @see TreeSet85* @see HashMap86* @since 1.287*/8889public class HashSet<E>90extends AbstractSet<E>91implements Set<E>, Cloneable, java.io.Serializable92{93static final long serialVersionUID = -5024744406713321676L;9495private transient HashMap<E,Object> map;9697// Dummy value to associate with an Object in the backing Map98private static final Object PRESENT = new Object();99100/**101* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has102* default initial capacity (16) and load factor (0.75).103*/104public HashSet() {105map = new HashMap<>();106}107108/**109* Constructs a new set containing the elements in the specified110* collection. The <tt>HashMap</tt> is created with default load factor111* (0.75) and an initial capacity sufficient to contain the elements in112* the specified collection.113*114* @param c the collection whose elements are to be placed into this set115* @throws NullPointerException if the specified collection is null116*/117public HashSet(Collection<? extends E> c) {118map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));119addAll(c);120}121122/**123* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has124* the specified initial capacity and the specified load factor.125*126* @param initialCapacity the initial capacity of the hash map127* @param loadFactor the load factor of the hash map128* @throws IllegalArgumentException if the initial capacity is less129* than zero, or if the load factor is nonpositive130*/131public HashSet(int initialCapacity, float loadFactor) {132map = new HashMap<>(initialCapacity, loadFactor);133}134135/**136* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has137* the specified initial capacity and default load factor (0.75).138*139* @param initialCapacity the initial capacity of the hash table140* @throws IllegalArgumentException if the initial capacity is less141* than zero142*/143public HashSet(int initialCapacity) {144map = new HashMap<>(initialCapacity);145}146147/**148* Constructs a new, empty linked hash set. (This package private149* constructor is only used by LinkedHashSet.) The backing150* HashMap instance is a LinkedHashMap with the specified initial151* capacity and the specified load factor.152*153* @param initialCapacity the initial capacity of the hash map154* @param loadFactor the load factor of the hash map155* @param dummy ignored (distinguishes this156* constructor from other int, float constructor.)157* @throws IllegalArgumentException if the initial capacity is less158* than zero, or if the load factor is nonpositive159*/160HashSet(int initialCapacity, float loadFactor, boolean dummy) {161map = new LinkedHashMap<>(initialCapacity, loadFactor);162}163164/**165* Returns an iterator over the elements in this set. The elements166* are returned in no particular order.167*168* @return an Iterator over the elements in this set169* @see ConcurrentModificationException170*/171public Iterator<E> iterator() {172return map.keySet().iterator();173}174175/**176* Returns the number of elements in this set (its cardinality).177*178* @return the number of elements in this set (its cardinality)179*/180public int size() {181return map.size();182}183184/**185* Returns <tt>true</tt> if this set contains no elements.186*187* @return <tt>true</tt> if this set contains no elements188*/189public boolean isEmpty() {190return map.isEmpty();191}192193/**194* Returns <tt>true</tt> if this set contains the specified element.195* More formally, returns <tt>true</tt> if and only if this set196* contains an element <tt>e</tt> such that197* <tt>(o==null ? e==null : o.equals(e))</tt>.198*199* @param o element whose presence in this set is to be tested200* @return <tt>true</tt> if this set contains the specified element201*/202public boolean contains(Object o) {203return map.containsKey(o);204}205206/**207* Adds the specified element to this set if it is not already present.208* More formally, adds the specified element <tt>e</tt> to this set if209* this set contains no element <tt>e2</tt> such that210* <tt>(e==null ? e2==null : e.equals(e2))</tt>.211* If this set already contains the element, the call leaves the set212* unchanged and returns <tt>false</tt>.213*214* @param e element to be added to this set215* @return <tt>true</tt> if this set did not already contain the specified216* element217*/218public boolean add(E e) {219return map.put(e, PRESENT)==null;220}221222/**223* Removes the specified element from this set if it is present.224* More formally, removes an element <tt>e</tt> such that225* <tt>(o==null ? e==null : o.equals(e))</tt>,226* if this set contains such an element. Returns <tt>true</tt> if227* this set contained the element (or equivalently, if this set228* changed as a result of the call). (This set will not contain the229* element once the call returns.)230*231* @param o object to be removed from this set, if present232* @return <tt>true</tt> if the set contained the specified element233*/234public boolean remove(Object o) {235return map.remove(o)==PRESENT;236}237238/**239* Removes all of the elements from this set.240* The set will be empty after this call returns.241*/242public void clear() {243map.clear();244}245246/**247* Returns a shallow copy of this <tt>HashSet</tt> instance: the elements248* themselves are not cloned.249*250* @return a shallow copy of this set251*/252@SuppressWarnings("unchecked")253public Object clone() {254try {255HashSet<E> newSet = (HashSet<E>) super.clone();256newSet.map = (HashMap<E, Object>) map.clone();257return newSet;258} catch (CloneNotSupportedException e) {259throw new InternalError(e);260}261}262263/**264* Save the state of this <tt>HashSet</tt> instance to a stream (that is,265* serialize it).266*267* @serialData The capacity of the backing <tt>HashMap</tt> instance268* (int), and its load factor (float) are emitted, followed by269* the size of the set (the number of elements it contains)270* (int), followed by all of its elements (each an Object) in271* no particular order.272*/273private void writeObject(java.io.ObjectOutputStream s)274throws java.io.IOException {275// Write out any hidden serialization magic276s.defaultWriteObject();277278// Write out HashMap capacity and load factor279s.writeInt(map.capacity());280s.writeFloat(map.loadFactor());281282// Write out size283s.writeInt(map.size());284285// Write out all elements in the proper order.286for (E e : map.keySet())287s.writeObject(e);288}289290/**291* Reconstitute the <tt>HashSet</tt> instance from a stream (that is,292* deserialize it).293*/294private void readObject(java.io.ObjectInputStream s)295throws java.io.IOException, ClassNotFoundException {296// Read in any hidden serialization magic297s.defaultReadObject();298299// Read capacity and verify non-negative.300int capacity = s.readInt();301if (capacity < 0) {302throw new InvalidObjectException("Illegal capacity: " +303capacity);304}305306// Read load factor and verify positive and non NaN.307float loadFactor = s.readFloat();308if (loadFactor <= 0 || Float.isNaN(loadFactor)) {309throw new InvalidObjectException("Illegal load factor: " +310loadFactor);311}312313// Read size and verify non-negative.314int size = s.readInt();315if (size < 0) {316throw new InvalidObjectException("Illegal size: " +317size);318}319// Set the capacity according to the size and load factor ensuring that320// the HashMap is at least 25% full but clamping to maximum capacity.321capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f),322HashMap.MAXIMUM_CAPACITY);323324// Constructing the backing map will lazily create an array when the first element is325// added, so check it before construction. Call HashMap.tableSizeFor to compute the326// actual allocation size. Check Map.Entry[].class since it's the nearest public type to327// what is actually created.328329SharedSecrets.getJavaOISAccess()330.checkArray(s, Map.Entry[].class, HashMap.tableSizeFor(capacity));331332// Create backing HashMap333map = (((HashSet<?>)this) instanceof LinkedHashSet ?334new LinkedHashMap<E,Object>(capacity, loadFactor) :335new HashMap<E,Object>(capacity, loadFactor));336337// Read in all elements in the proper order.338for (int i=0; i<size; i++) {339@SuppressWarnings("unchecked")340E e = (E) s.readObject();341map.put(e, PRESENT);342}343}344345/**346* Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>347* and <em>fail-fast</em> {@link Spliterator} over the elements in this348* set.349*350* <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and351* {@link Spliterator#DISTINCT}. Overriding implementations should document352* the reporting of additional characteristic values.353*354* @return a {@code Spliterator} over the elements in this set355* @since 1.8356*/357public Spliterator<E> spliterator() {358return new HashMap.KeySpliterator<E,Object>(map, 0, -1, 0, 0);359}360}361362363