WeakHashSet.java Source code

Java tutorial

Introduction

Here is the source code for WeakHashSet.java

Source

/*
 * Copyright 2004 (C) TJDO.
 * All rights reserved.
 *
 * This software is distributed under the terms of the TJDO License version 1.0.
 * See the terms of the TJDO License in the documentation provided with this software.
 *
 * $Id: WeakHashSet.java,v 1.1 2004/08/09 23:53:35 jackknifebarber Exp $
 */

import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.WeakHashMap;

/**
 * A <tt>Set</tt> implementation with <em>weak elements</em>.
 * This class implements the <tt>Set</tt> interface, backed by a hash table with
 * weak keys (actually a <tt>WeakHashMap</tt> instance).
 * An element in a <tt>WeakHashSet</tt> will automatically be removed when it
 * is no longer in ordinary use.
 * More precisely, the presence of an element will not prevent it from being
 * discarded by the garbage collector, that is, made finalizable, finalized,
 * and then reclaimed.
 * When a element has been discarded it is effectively removed from the set,
 * so this class behaves somewhat differently than other <tt>Set</tt>
 * implementations.
 * <p>
 * The null element is supported.
 * This class has performance characteristics similar to those of the
 * <tt>HashSet</tt> class, and has the same efficiency parameters of
 * <em>initial capacity</em> and <em>load factor</em>.
 * <p>
 * Like most collection classes, this class is not synchronized.
 * A synchronized <tt>WeakHashSet</tt> may be constructed using the
 * <tt>Collections.synchronizedSet</tt> method.
 * <p>
 * This class is intended primarily for use with objects whose
 * <tt>equals</tt> methods test for object identity using the
 * <tt>==</tt> operator.
 * Once such an object is discarded it can never be recreated, so it is
 * impossible to do a lookup of that key in a <tt>WeakHashSet</tt> at some later
 * time and be surprised that its entry has been removed.
 * This class will work perfectly well with objects whose <tt>equals</tt>
 * methods are not based upon object identity, such as <tt>String</tt>
 * instances.
 * With such recreatable objects however, the automatic removal of
 * <tt>WeakHashSet</tt> elements that have been discarded may prove to be
 * confusing.
 * <p>
 * The behavior of the <tt>WeakHashSet</tt> class depends in part upon the
 * actions of the garbage collector, so several familiar (though not required)
 * <tt>Set</tt> invariants do not hold for this class.
 * Because the garbage collector may discard elements at any time, a
 * <tt>WeakHashSet</tt> may behave as though an unknown thread is silently
 * removing elements.
 * In particular, even if you synchronize on a <tt>WeakHashSet</tt> instance and
 * invoke none of its mutator methods, it is possible for the <tt>size</tt>
 * method to return smaller values over time, for the <tt>isEmpty</tt> method to
 * return <tt>false</tt> and then <tt>true</tt>, for the <tt>contains</tt>
 * method to return <tt>true</tt> and later <tt>false</tt> for a given object,
 * for the <tt>add</tt> method to return <tt>true</tt> and the <tt>remove</tt>
 * method to return <tt>false</tt> for an element that previously appeared to be
 * in the set, and for successive examinations of the set to yield successively
 * smaller numbers of elements.
 * <p>
 * Each element in a <tt>WeakHashSet</tt> is stored indirectly as the referent
 * of a weak reference.
 * Therefore an element will automatically be removed only after the weak
 * references to it, both inside and outside of the set, have been cleared by
 * the garbage collector.
 * <p>
 * The iterators returned by this class are <i>fail-fast</i>: if the set is
 * structurally modified at any time after the iterator is created, in any way
 * except through the iterator's own <tt>remove</tt> or <tt>add</tt> methods,
 * the iterator will throw a <tt>ConcurrentModificationException</tt>.
 * Thus, in the face of concurrent modification, the iterator fails quickly and
 * cleanly, rather than risking arbitrary, non-deterministic behavior at an
 * undetermined time in the future.
 * <p>
 * Note that the fail-fast behavior of an iterator cannot be guaranteed
 * as it is, generally speaking, impossible to make any hard guarantees in the
 * presence of unsynchronized concurrent modification.
 * Fail-fast iterators throw <tt>ConcurrentModificationException</tt> on a
 * best-effort basis.
 * Therefore, it would be wrong to write a program that depended on this
 * exception for its correctness:  <i>the fail-fast behavior of iterators
 * should be used only to detect bugs.</i>
 *
 *
 * @author  <a href="mailto:mmartin5@austin.rr.com">Mike Martin</a> (borrowing
 *          liberally from java.util.HashSet)
 * @version $Revision: 1.1 $
 */

public class WeakHashSet extends AbstractSet implements Set {
    /* Dummy value to associate with an Object in the backing Map. */
    private static final Object PRESENT = new Object();

    private final WeakHashMap map;

    /**
     * Constructs a new, empty set; the backing <tt>WeakHashMap</tt> instance has
     * default initial capacity (16) and load factor (0.75).
     */
    public WeakHashSet() {
        map = new WeakHashMap();
    }

    /**
     * Constructs a new set containing the elements in the specified
     * collection.  The <tt>WeakHashMap</tt> is created with default load factor
     * (0.75) and an initial capacity sufficient to contain the elements in
     * the specified collection.
     *
     * @param c the collection whose elements are to be placed into this set.
     * @throws NullPointerException   if the specified collection is null.
     */

    public WeakHashSet(Collection c) {
        map = new WeakHashMap(Math.max((int) (c.size() / .75f) + 1, 16));
        addAll(c);
    }

    /**
     * Constructs a new, empty set; the backing <tt>WeakHashMap</tt> instance has
     * the specified initial capacity and the specified load factor.
     *
     * @param      initialCapacity   the initial capacity of the hash map.
     * @param      loadFactor        the load factor of the hash map.
     * @throws     IllegalArgumentException if the initial capacity is less
     *             than zero, or if the load factor is nonpositive.
     */

    public WeakHashSet(int initialCapacity, float loadFactor) {
        map = new WeakHashMap(initialCapacity, loadFactor);
    }

    /**
     * Constructs a new, empty set; the backing <tt>WeakHashMap</tt> instance has
     * the specified initial capacity and default load factor, which is
     * <tt>0.75</tt>.
     *
     * @param      initialCapacity   the initial capacity of the hash table.
     * @throws     IllegalArgumentException if the initial capacity is less
     *             than zero.
     */

    public WeakHashSet(int initialCapacity) {
        map = new WeakHashMap(initialCapacity);
    }

    /**
     * Returns an iterator over the elements in this set.  The elements
     * are returned in no particular order.
     *
     * @return an Iterator over the elements in this set.
     * @see "java.util.ConcurrentModificationException"
     */

    public Iterator iterator() {
        return map.keySet().iterator();
    }

    /**
     * Returns the number of elements in this set (its cardinality).
     *
     * @return the number of elements.
     */

    public int size() {
        return map.size();
    }

    /**
     * Indicates whether the set is empty.
     *
     * @return <code>true</code> if the set contains no elements.
     */

    public boolean isEmpty() {
        return map.isEmpty();
    }

    /**
     * Indicates whether the set contains the specified element.
     *
     * @param o the element to specify.
     * @return <code>true</code> if the set contains the specified element.
     */

    public boolean contains(Object o) {
        return map.containsKey(o);
    }

    /**
     * Adds the specified element to the set if it is not already
     * present.
     *
     * @param o the element to be added.
     * @return <code>true</code> if the set did not already contain the specified
     * element.
     */

    public boolean add(Object o) {
        return map.put(o, PRESENT) == null;
    }

    /**
     * Removes the specified element from the set if it is present.
     *
     * @param o the element to be removed.
     * @return <code>true</code> if the set contained the specified element.
     */

    public boolean remove(Object o) {
        return map.remove(o) == PRESENT;
    }

    /**
     * Removes all of the elements from the set.
     */

    public void clear() {
        map.clear();
    }
}