ConcreteSet is a basic java.util.Set implementation, very much like java.util.HashSet. Duplicate entries are ignored. Adds, removes, the “contains” method, and data extraction are extremely efficient. The ordering of elements within the set is random and not under the user's control. Unlike a HashSet, there is no need for an “initial capacity” or a “load factor”, and it never needs to allocate large, contiguous blocks of memory. Built using a java.util.TreeMap, it uses more memory as objects are added and releases memory as they are removed.
If what you need is a basic java.util.Set implementation, ConcreteSet is simpler and easier to use than any other Collection or Map. It speeds coding and greatly eases maintenance, and it is faster and makes better use of memory than any collection or map in java.util. (Faster, that is, with the possible exception of HashSet. Hash tables, however, work well only within a narrow range of sizes and memory conditions. You can )
A basic set is useful for storing a bunch of objects when you only want an object stored once, even if you add it several times. It is useful when you do not care about the order. It is useful when names, keys, or other identifiers are not needed, irrelevant, or unavailable. In these cases, ConcreteSet is faster, more flexible, and makes better use of memory than any if the standard Java classes. It was designed for ease of use, speed, and second-by-second scalability.
It is handy for merging collections and discarding duplicates. It can be used as part of a one-time calculation, or maintained to track a set of objects over time. If you commonly use various collections and maps (TreeMap, HashMap, dictionaries) from Java's collections framework, you will want to have ConcreteSet in your library for its simplicity, ease-of-use, and raw speed.
ConcreteSet is a good example of a java.util.Set or java.util.Collection, and follows all the rules. It is written with generics. It is fully Javadoc'ed. It is not inherently thread-safe, and if used with multiple threads it should be accessed only in synchronized blocks, or be used only for reading. Objects placed in it should have well-distributed hash codes.
The source code includes a sample program, which can also serve as tests for any Java Set.
The following usage example is part of the test included with the source code:
package rrc12;
import java.util.*;
import rrc12.util.*;
/** Example of ConcreteSet usage. Puts Sets through their paces. */
public class Example {
/** Class for objects used inside Set instances. Pretty much the
* same as the Integer class, but the hash codes are not so nice,
* with every four possible elements sharing one hash code. */
private static class Entry implements Comparable {
private int value;
private int hashValue;
public Entry( int i ) {
value = i;
hashValue = i >> 2;
}
public Entry( Entry e ) { this( e.value ); }
public int hashCode() { return hashValue; }
public boolean equals( Object o ) {
return (o instanceof Entry && ((Entry) o).value == value);
}
public String toString() { return Integer.toString( value ); }
public int compareTo( Object o ) {
Entry e = (Entry) o;
if (value < e.value) return -1;
if (value > e.value) return 1;
return 0;
}
}
/** The main program. Runs a series of tests and timings on several
* sets, including ConcreteSet and HashSet. */
public static void main( String[] args ) {
ConcreteSet setA = new ConcreteSet();
Set setB = new HashSet( 300 );
Set setC = new TreeSet();
HashSet setD = new HashSet( 45000 );
if (setB.equals( setA ))
System.out.println(
"ConcreteSet equals HashSet after test" );
setA.clear();
setB.clear();
setC.clear();
setD.clear();
runSpeedTest( "ConcreteSet", setA );
runSpeedTest( "HashSet", setB );
runSpeedTest( "TreeSet", setC );
runSpeedTest( "Big HashSet", setD );
if (setA.equals( setD ))
System.out.println(
"ConcreteSet equals HashSet after speed test" );
{
// Test pop method.
int count = 0;
boolean mismatch = false;
for (;;) {
Object entry = setA.pop();
if (entry == null) break;
if (!setD.contains( entry ))
mismatch = true;
count++;
}
if (!mismatch && count == 10000)
System.out.println( "Pop test good." );
}
}
/** Does a generic speed test. */
private static void runSpeedTest( String title, Set set ) {
LinkedList all_list = generate( null, 1, 20000 );
generate( all_list, 10001, 30000 );
LinkedList removelist = generate( null, 10001, 20000 );
LinkedList retainlist = generate( null, 5001, 25000 );
LinkedList containlist = generate( null, 5011, 9090 );
generate( containlist, 20011, 24090 );
boolean accurate = true;
long time = System.currentTimeMillis();
set.addAll( all_list );
if (set.size() != 30000)
accurate = false;
set.removeAll( removelist );
set.retainAll( retainlist );
if (!set.containsAll( containlist ))
accurate = false;
Object[] array = set.toArray();
{
int count = array.length;
if (count != 10000)
accurate = false;
}
System.out.println( title + ": speed time: " +
(System.currentTimeMillis() - time) + " good: " +
accurate );
}
/** Generates a LinkedList containing Entry instances with all values
* between s and f.
* @param list an existing list, to which values will be appended.
* Set null to create a new list.
* @param s the first value.
* @param f the last value.
* @return a LinkedList containing the specified values. */
private static LinkedList
generate( LinkedList list, int s, int f ) {
if (list == null)
list = new LinkedList();
for (int i = s; i <= f; i++)
list.addLast( new Entry( i ) );
return list;
}
}
Questions & Comments