You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by "Hope, Matthew" <Ma...@capitalone.com> on 2003/08/21 10:01:59 UTC

RE: [collections]SingleElementCollection (was Questions....)

inlined as attachment was stripped...

import java.util.*;

/**
 * Quick and simple implementation of a single element collection. The
collection
 * starts with one entry and always keeps it that way, therefore
modification
 * operations will result in UnsupportedOperationException. The class is
 * unsynchronized. The collection can hold null and will treat it in a
similar
 * fashion to List. Details of this are by each method.
 *
 * @author   Matt Hope
 */
public class SingleElementCollection implements Collection
{

    private class SingleIterator implements Iterator
    {
        private boolean nextHasBeenCalled = false;

        /**
         * contract of Iterator#hasNext() maintained
         *
         * @return
         */
        public boolean hasNext()
        {
            if (nextHasBeenCalled) {
                return false;
            }
            return true;
        }

        /**
         * contract of Iterator#next() maintained
         *
         * @return
         */
        public Object next()
        {
            if (nextHasBeenCalled) {
                throw new NoSuchElementException("only one entry defined");
            } else {
                nextHasBeenCalled = true;
                return theElement;
            }
        }

        /**
         * This will throw an UnsupportedOperationException since the
underlying
         * Colelction does not support removal
         */
        public void remove()
        {
            throw new UnsupportedOperationException("SingleElementCollection
does not supprt the removal of elements");
        }

    }

    private Object theElement;

    /**
     * Constructor for the SingleElementCollection object
     *
     * @param o  the Object to use in the collection. null is allowed
     */
    public SingleElementCollection(Object o)
    {
        theElement = o;
    }

    /**
     * This will always be 1
     *
     * @return
     */
    public int size()
    {
        return 1;
    }

    /**
     * this will always be false
     *
     * @return   The empty
     */
    public boolean isEmpty()
    {
        return false;
    }

    /**
     * True iff (o==null ? theElement==null : o.equals(e)) as for
     * List#contains()
     *
     * @return
     * @param o  the object for comparison
     */
    public boolean contains(Object o)
    {
        return o == null ? theElement == null : o.equals(theElement);
    }

    /**
     * returns an Iterator which will return the element in the collection.
It
     * does not support removal
     *
     * @return
     */
    public Iterator iterator()
    {
        return new SingleElementCollection.SingleIterator();
    }

    /**
     * converts the collection to an Object array of length 1
     *
     * @return
     */
    public Object[] toArray()
    {
        return new Object[]{theElement};
    }

    /**
     * as for Collection#toArray(Object[])
     *
     * @return
     * @param a
     */
    public Object[] toArray(Object[] a)
    {
        if (a.length < 1) {
            a = (Object[]) java.lang.reflect.Array.newInstance(
                    a.getClass().getComponentType(), 1);
        }

        System.arraycopy(toArray(), 0, a, 0, 1);

        if (a.length > 1) {
            a[1] = null;
        }

        return a;
    }

    /**
     * modification not allowed - UnsupportedOperationException will be
thrown
     *
     * @return
     * @param o
     */
    public boolean add(Object o)
    {
        throw new java.lang.UnsupportedOperationException("Method add() not
supported - collection content is immutable");
    }

    /**
     * modification not allowed - UnsupportedOperationException will be
thrown
     *
     * @return
     * @param o
     */
    public boolean remove(Object o)
    {
        throw new java.lang.UnsupportedOperationException("Method remove()
not supported - collection content is immutable");
    }

    /**
     * as for Collection#containsAll(c)
     *
     * @return
     * @param c
     */
    public boolean containsAll(Collection c)
    {
        if (c.size() != 1) {
            return false;
        } else {
            return c.contains(theElement);
        }
    }

    /**
     * modification not allowed - UnsupportedOperationException will be
thrown
     *
     * @return
     * @param c  The All to be added
     */
    public boolean addAll(Collection c)
    {
        throw new java.lang.UnsupportedOperationException("Method addAll()
not supported - collection content is immutable");
    }

    /**
     * modification not allowed - UnsupportedOperationException will be
thrown
     *
     * @return
     * @param c
     */
    public boolean removeAll(Collection c)
    {
        throw new java.lang.UnsupportedOperationException("Method addAll()
not supported - collection content is immutable");
    }

    /**
     * Makes no effort to check if the operation would do nothing (and hence
not
     * violate the immutable invariant. It just throws
     * UnsupportedOperationException
     *
     * @return
     * @param c
     */
    public boolean retainAll(Collection c)
    {
        throw new java.lang.UnsupportedOperationException("Method
retainAll() not supported - collection content is immutable");
    }

    /**
     * modification not allowed - UnsupportedOperationException will be
thrown
     */
    public void clear()
    {
        throw new java.lang.UnsupportedOperationException("Method clear()
not supported - collection content is immutable");
    }

    /**
     * returns true if the Object is an instance of SingleElementCollection
     * which contains an element equal to this one.
     *
     * @return
     * @param o
     */
    public boolean equals(Object o)
    {
        if (o instanceof SingleElementCollection) {
            SingleElementCollection other = (SingleElementCollection) o;
            return containsAll(other);
        }
        return false;
    }

    /**
     * returns the hashcode of the element or zero is null
     *
     * @return
     */
    public int hashCode()
    {
        return theElement == null ? 0 : theElement.hashCode();
    }
}

import java.util.*;
import junit.framework.*;

/**
 * Quick and simple implementation of an immutable single element
colection.<br>
 * The collection starts with one entry and always keeps it that way,
therefore
 * certain operations will result in UnsupportedOperationException. <br>
 * The collection is unsynchronized.<br>
 * The collection can hold null and will treat it in a similar fashion to
List.
 * Details of this are by each method.
 *
 * @author   Matt Hope
 */
public class TestSingleElementCollection extends TestCase
{
    private final Object TEST_ELEMENT = new Object();

    public TestSingleElementCollection(String name)
    {
        super(name);
    }

    public void testSize()
    {
        assertEquals(1, new SingleElementCollection(TEST_ELEMENT).size());
        assertEquals(1, new SingleElementCollection(null).size());
    }

    public void testIsEmpty()
    {
        assertFalse(new SingleElementCollection(TEST_ELEMENT).isEmpty());
        assertFalse(new SingleElementCollection(null).isEmpty());
    }

    public void testContains()
    {
        assertTrue(new SingleElementCollection(null).contains(null));
        assertTrue(new
SingleElementCollection(TEST_ELEMENT).contains(TEST_ELEMENT));
        assertTrue(new SingleElementCollection(new Integer(1)).contains(new
Integer(1)));
        assertFalse(new
SingleElementCollection(null).contains(TEST_ELEMENT));
        assertFalse(new
SingleElementCollection(TEST_ELEMENT).contains(null));
    }

    public void testIterator()
    {
        assertTrue(new
SingleElementCollection(TEST_ELEMENT).iterator().hasNext());
        assertTrue(new SingleElementCollection(null).iterator().hasNext());
        assertEquals(TEST_ELEMENT, new
SingleElementCollection(TEST_ELEMENT).iterator().next());
        assertEquals(null, new
SingleElementCollection(null).iterator().next());
        Iterator iter = new
SingleElementCollection(TEST_ELEMENT).iterator();
        iter.next();
        assertFalse(iter.hasNext());
        try {
            iter.next();
            fail("should have thrown NoSuchElementException");
        } catch (NoSuchElementException e) {
            // pass
        }
    }

    public void testToArray()
    {
        assertNull(new SingleElementCollection(null).toArray()[0]);
        assertEquals(1, new SingleElementCollection(null).toArray().length);
        assertEquals(TEST_ELEMENT, new
SingleElementCollection(TEST_ELEMENT).toArray()[0]);
        assertEquals(1, new
SingleElementCollection(TEST_ELEMENT).toArray().length);
    }

    public void testToArray_withParameter()
    {
        assertNull(new SingleElementCollection(null).toArray(new
Object[0])[0]);
        assertEquals(1, new SingleElementCollection(null).toArray(new
Object[0]).length);
        assertEquals(TEST_ELEMENT, new
SingleElementCollection(TEST_ELEMENT).toArray(new Object[0])[0]);
        assertEquals(1, new
SingleElementCollection(TEST_ELEMENT).toArray(new Object[0]).length);
        assertEquals(TEST_ELEMENT, new
SingleElementCollection(TEST_ELEMENT).toArray(new Object[2])[0]);
        assertNull(new SingleElementCollection(TEST_ELEMENT).toArray(new
Object[2])[1]);
        Object[] three = new Object[]{"nought", "one", "two"};
        assertEquals(TEST_ELEMENT, new
SingleElementCollection(TEST_ELEMENT).toArray(three)[0]);
        assertNull(new
SingleElementCollection(TEST_ELEMENT).toArray(three)[1]);
        assertEquals(three[2], new
SingleElementCollection(TEST_ELEMENT).toArray(three)[2]);

    }

    public void testAdd()
    {
        try {
            new SingleElementCollection(TEST_ELEMENT).add("foo");
            fail("should have thrown UnsupportedOperationException");
        } catch (UnsupportedOperationException e) {
            //pass
        }
    }

    public void testRemove()
    {
        try {
            new SingleElementCollection(TEST_ELEMENT).remove(TEST_ELEMENT);
            fail("should have thrown UnsupportedOperationException");
        } catch (UnsupportedOperationException e) {
            //pass
        }
    }

    public void testContainsAll_Set()
    {
        Set equalSet = new HashSet();
        equalSet.add(TEST_ELEMENT);
        Set emptySet = new HashSet();
        Set biggerSet = new HashSet();
        biggerSet.add(TEST_ELEMENT);
        biggerSet.add("foo");
        assertFalse(new
SingleElementCollection(TEST_ELEMENT).containsAll(emptySet));
        assertTrue(new
SingleElementCollection(TEST_ELEMENT).containsAll(equalSet));
        assertFalse(new
SingleElementCollection(TEST_ELEMENT).containsAll(biggerSet));
    }

    public void testContainsAll_List()
    {
        List equalList = new ArrayList();
        equalList.add(TEST_ELEMENT);
        List emptyList = new ArrayList();
        List biggerList = new ArrayList();
        biggerList.add(TEST_ELEMENT);
        biggerList.add("foo");
        assertFalse(new
SingleElementCollection(TEST_ELEMENT).containsAll(emptyList));
        assertTrue(new
SingleElementCollection(TEST_ELEMENT).containsAll(equalList));
        assertFalse(new
SingleElementCollection(TEST_ELEMENT).containsAll(biggerList));
    }

    public void testAddAll()
    {
        try {
            new SingleElementCollection(TEST_ELEMENT).addAll(new HashSet());
            fail("should have thrown UnsupportedOperationException");
        } catch (UnsupportedOperationException e) {
            //pass
        }
    }

    public void testRemoveAll()
    {
        try {
            new SingleElementCollection(TEST_ELEMENT).removeAll(new
HashSet());
            fail("should have thrown UnsupportedOperationException");
        } catch (UnsupportedOperationException e) {
            //pass
        }
    }

    public void testRetainAll()
    {
        try {
            new SingleElementCollection(TEST_ELEMENT).retainAll(new
HashSet());
            fail("should have thrown UnsupportedOperationException");
        } catch (UnsupportedOperationException e) {
            //pass
        }
    }

    public void testClear()
    {
        try {
            new SingleElementCollection(TEST_ELEMENT).clear();
            fail("should have thrown UnsupportedOperationException");
        } catch (UnsupportedOperationException e) {
            //pass
        }
    }

    public void testEquals()
    {
        SingleElementCollection same = new
SingleElementCollection(TEST_ELEMENT);
        Set sameSet = new HashSet();
        sameSet.add(TEST_ELEMENT);
        assertEquals(same, same);
        assertEquals(same, new SingleElementCollection(TEST_ELEMENT));
        assertEquals(new SingleElementCollection(null), new
SingleElementCollection(null));
        assertFalse(new
SingleElementCollection(TEST_ELEMENT).equals(sameSet));
        assertFalse(new SingleElementCollection(TEST_ELEMENT).equals(new
SingleElementCollection(null)));
        assertFalse(new SingleElementCollection(null).equals(new
SingleElementCollection(TEST_ELEMENT)));
        assertFalse(new SingleElementCollection(new Integer(1)).equals(new
SingleElementCollection(new Integer(2))));
        assertEquals(new SingleElementCollection(new Integer(1)), new
SingleElementCollection(new Integer(1)));
    }

    public void testHashCode()
    {
        assertEquals(TEST_ELEMENT.hashCode(), new
SingleElementCollection(TEST_ELEMENT).hashCode());
        assertEquals(0, new SingleElementCollection(null).hashCode());
    }
}



> -----Original Message-----
> From: Hope, Matthew 
> Sent: 20 August 2003 15:16
> To: 'Jakarta Commons Developers List'
> Subject: RE: [collections] Questions....
> 
> 
> I knocked this up - javadocs are crap but is this the sort of 
> thing you were
> thinking of?
> 
> a mutable version is not too hard either.
> 
> Matt
> 
> > -----Original Message-----
> > From: Hope, Matthew 
> > Sent: 20 August 2003 13:18
> > To: 'Jakarta Commons Developers List'
> > Subject: RE: [collections] Questions....
> > 
> > 
> > > -----Original Message-----
> > > From: Takuya Murata [mailto:takusi@manjiro.net] 
> > > Sent: 20 August 2003 12:14
> > > To: Jakarta Commons Developers List
> > > Subject: Re: [collections] Questions....
> > > 
> > > class Singleton implements List {
> > > }
> > > 
> > > ResetableIterator i = new Singleton ("hello, world").iterator ();
> > > ListIterator li = new Singleton ("hello, world").listIterator ();
> > > ListIterator li = new Singleton ("hello, 
> world").listIterator (10);
> > 
> > I personally have a problem with the use of the class name 
> Singleton.
> > Singleton is a well known pattern for only having one 
> > instance of an Object
> > in an environment, this class does not achive this. I would 
> > think a name
> > likeSingleEntryIterator/TrivialIterator/MonoIterator or some 
> > such would be a
> > better descriptive name.
> >  
> > > To me, this solution sounds good. There is no tricky 
> choice whether 
> > > SingletonIterator or SingletonListIterator. And we can 
> avoid a big 
> > > xxxUtil classes instead of small objects and classes, resembling 
> > > traditional imperative languages such as C.
> > 
> > The whole point of Iterator is that it is collection type 
> > independent - no
> > matter what data structure in place iterator should supply 
> > you with every
> > Object in it - ordering appropriately if required.
> > 
> > If it is being used for code expecting a ListIterator I would 
> > say that that
> > code needs to be made more agnostic of the underlying 
> > implementation (given
> > that you would be using this quick method of supplying just 
> > the one value).
> > Though in fairness making it return a ListItertor (but keep 
> > the signature to
> > Iterator) would be no big deal.
> > 
> > > I am not sure if it is valid with the contract of interfaces to 
> > > implement both Set and List because ListIterator doesn't 
> make sense 
> > > with listIterator but it doesn't look elegant to have two 
> > > SingletonList 
> > > and SingletonSet classes.
> > 
> > Perhaps it would be better to create a class 
> > SingleEntryCollection which
> > extends collection and implements the iterator method as well 
> > as the rest.
> > The cost is one additional object for your siple use case but 
> > it may provide
> > a clearer picture of what is being performed...If the 
> > Collection itself
> > implements Iterator then it can just return itself in 
> response to the
> > method. I can't see a name clash except remove() and they are 
> > different
> > signatures in both return type and parameters...
> > 
> > If I'm missing the point of what you're trying to do here 
> let me know
> > 
> > Matt
> >  
> > **************************************************************
> > ************
> > The information transmitted herewith is sensitive information 
> > intended only
> > for use by the individual or entity to which it is addressed. 
> > If the reader
> > of this message is not the intended recipient, you are hereby 
> > notified that
> > any review, retransmission, dissemination, distribution, 
> > copying or other
> > use of, or taking of any action in reliance upon this information is
> > strictly prohibited. If you have received this 
> communication in error,
> > please contact the sender and delete the material from your 
> computer.
> > 
> > 
> ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> > 
>  
> **************************************************************
> ************
> The information transmitted herewith is sensitive information 
> intended only
> for use by the individual or entity to which it is addressed. 
> If the reader
> of this message is not the intended recipient, you are hereby 
> notified that
> any review, retransmission, dissemination, distribution, 
> copying or other
> use of, or taking of any action in reliance upon this information is
> strictly prohibited. If you have received this communication in error,
> please contact the sender and delete the material from your computer.
>     
> 
> 
> 
 
**************************************************************************
The information transmitted herewith is sensitive information intended only
for use by the individual or entity to which it is addressed. If the reader
of this message is not the intended recipient, you are hereby notified that
any review, retransmission, dissemination, distribution, copying or other
use of, or taking of any action in reliance upon this information is
strictly prohibited. If you have received this communication in error,
please contact the sender and delete the material from your computer.