Author: scolebourne Date: Mon Apr 11 17:48:14 2011 New Revision: 1091146 URL: http://svn.apache.org/viewvc?rev=1091146&view=rev Log: Enhance pair classes; Shorten toString form; Javadoc
Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/ImmutablePair.java commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/MutablePair.java commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/Pair.java commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/ImmutablePairTest.java commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/MutablePairTest.java commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/PairTest.java Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/ImmutablePair.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/ImmutablePair.java?rev=1091146&r1=1091145&r2=1091146&view=diff ============================================================================== --- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/ImmutablePair.java (original) +++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/ImmutablePair.java Mon Apr 11 17:48:14 2011 @@ -17,16 +17,23 @@ package org.apache.commons.lang3; /** - * Immutable concrete manifestation of the {@link Pair} type. - * + * <p>An immutable pair consisting of two {@code Object} elements.</p> + * + * <p>Although the implementation is immutable, there is no restriction on the objects + * that may be stored. If mutable objects are stored in the pair, then the pair + * itself effectively becomes mutable. The class is also not {@code final}, so a subclass + * could add undesirable behaviour.</p> + * * <p>#ThreadSafe# if the objects are threadsafe</p> + * + * @param <L> the first element type + * @param <R> the second element type + * * @since Lang 3.0 * @version $Id$ - * - * @param <L> left generic type - * @param <R> right generic type */ public class ImmutablePair<L, R> extends Pair<L, R> { + /** Serialization version */ private static final long serialVersionUID = 4954918890077093841L; @@ -36,10 +43,26 @@ public class ImmutablePair<L, R> extends public final R right; /** - * Create a new ImmutablePair instance. + * <p>Obtains an immutable pair of from two objects inferring the generic types.</p> + * + * <p>This factory allows the pair to be created using inference to + * obtain the generic types.</p> + * + * @param <L> the left element type + * @param <R> the right element type + * @param left the left element, may be null + * @param right the right element, may be null + * @return a pair formed from the two parameters, not null + */ + public static <L, R> ImmutablePair<L, R> of(L left, R right) { + return new ImmutablePair<L, R>(left, right); + } + + /** + * Create a new pair instance. * - * @param left the left value - * @param right the right value + * @param left the left value, may be null + * @param right the right value, may be null */ public ImmutablePair(L left, R right) { super(); @@ -47,6 +70,7 @@ public class ImmutablePair<L, R> extends this.right = right; } + //----------------------------------------------------------------------- /** * {@inheritDoc} */ @@ -64,29 +88,16 @@ public class ImmutablePair<L, R> extends } /** - * {@link java.util.Map.Entry#setValue(Object)} implementation. Because this - * class is immutable the {@code setValue()} operation is not supported. - * Therefore always an exception is thrown. + * <p>Throws {@code UnsupportedOperationException}.</p> + * + * <p>This pair is immutable, so this operation is not supported.</p> * - * @param value the value to set - * @return the old right value + * @param value the value to set + * @return never * @throws UnsupportedOperationException as this operation is not supported */ public R setValue(R value) { throw new UnsupportedOperationException(); } - /** - * Static fluent creation method for an {@link ImmutablePair}<L, R>: - * <code>ImmutablePair.of(left, right)</code> - * - * @param <L> the left generic type - * @param <R> the right generic type - * @param left the let value - * @param right the right value - * @return ImmutablePair<L, R>(left, right) - */ - public static <L, R> ImmutablePair<L, R> of(L left, R right) { - return new ImmutablePair<L, R>(left, right); - } } Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/MutablePair.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/MutablePair.java?rev=1091146&r1=1091145&r2=1091146&view=diff ============================================================================== --- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/MutablePair.java (original) +++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/MutablePair.java Mon Apr 11 17:48:14 2011 @@ -17,55 +17,77 @@ package org.apache.commons.lang3; /** - * Mutable concrete manifestation of the {@link Pair} type. + * <p>A mutable pair consisting of two {@code Object} elements.</p> + * + * <p>Not #ThreadSafe#</p> + * + * @param <L> the first element type + * @param <R> the second element type * - * <p>#ThreadSafe# if the objects are threadsafe</p> * @since Lang 3.0 * @version $Id$ - * - * @param <L> left generic type - * @param <R> right generic type */ public class MutablePair<L, R> extends Pair<L, R> { + /** Serialization version */ private static final long serialVersionUID = 4954918890077093841L; - private L leftElement; - private R rightElement; + /** Left object */ + public L left; + /** Right object */ + public R right; + + /** + * <p>Obtains an immutable pair of from two objects inferring the generic types.</p> + * + * <p>This factory allows the pair to be created using inference to + * obtain the generic types.</p> + * + * @param <L> the left element type + * @param <R> the right element type + * @param left the left element, may be null + * @param right the right element, may be null + * @return a pair formed from the two parameters, not null + */ + public static <L, R> MutablePair<L, R> of(L left, R right) { + return new MutablePair<L, R>(left, right); + } /** - * Create a new MutablePair instance. + * Create a new pair instance of two nulls. */ public MutablePair() { super(); } /** - * Create a new MutablePair instance. + * Create a new pair instance. * - * @param leftElement the left value - * @param rightElement the right value + * @param left the left value, may be null + * @param right the right value, may be null */ - public MutablePair(L leftElement, R rightElement) { + public MutablePair(L left, R right) { super(); - this.leftElement = leftElement; - this.rightElement = rightElement; + this.left = left; + this.right = right; } + //----------------------------------------------------------------------- /** * {@inheritDoc} */ @Override public L getLeftElement() { - return leftElement; + return left; } /** * Set the left element of the pair. - * @param leftElement the value of the left element + * + * @param left the new value of the left element, may be null */ - public void setLeftElement(L leftElement) { - this.leftElement = leftElement; + public void setLeftElement(L left) { + this.left = left; } /** @@ -73,20 +95,23 @@ public class MutablePair<L, R> extends P */ @Override public R getRightElement() { - return rightElement; + return right; } /** * Set the right element of the pair. - * @param rightElement the value of the right element + * + * @param right the value of the right element */ - public void setRightElement(R rightElement) { - this.rightElement = rightElement; + public void setRightElement(R right) { + this.right = right; } /** - * Implement {@link java.util.Map.Entry#setValue(Object)}. - * @param value value (<code>rightElement</code>) to set + * Sets the {@code Map.Entry} value. + * This sets the right element of the pair. + * + * @param value the right value to set, not null * @return the old value for the right element */ public R setValue(R value) { @@ -95,16 +120,4 @@ public class MutablePair<L, R> extends P return result; } - /** - * Static fluent creation method for a {@link MutablePair}<L, R>: - * <code>MutablePair.of(left, right)</code> - * @param <L> the left generic type - * @param <R> the right generic type - * @param left the left value - * @param right the right value - * @return MutablePair<L, R>(left, right) - */ - public static <L, R> MutablePair<L, R> of(L left, R right) { - return new MutablePair<L, R>(left, right); - } } Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/Pair.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/Pair.java?rev=1091146&r1=1091145&r2=1091146&view=diff ============================================================================== --- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/Pair.java (original) +++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/Pair.java Mon Apr 11 17:48:14 2011 @@ -19,79 +19,142 @@ package org.apache.commons.lang3; import java.io.Serializable; import java.util.Map; -import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.CompareToBuilder; /** - * Abstract Pair (or 2-element Tuple). + * <p>A pair consisting of two elements.</p> + * + * <p>This class is an abstract implementation defining the basic API. + * It refers to the elements as 'left' and 'right'. It also implements the + * {@code Map.Entry} interface where the key is 'left' and the value is 'right'.</p> + * + * <p>Subclass implementations may be mutable or immutable. + * However, there is no restriction on the type of the stored objects that may be stored. + * If mutable objects are stored in the pair, then the pair itself effectively becomes mutable.</p> + * + * @param <L> the first element type + * @param <R> the second element type * * @since Lang 3.0 * @version $Id$ */ -public abstract class Pair<L, R> implements Serializable, Map.Entry<L, R> { +public abstract class Pair<L, R> implements Map.Entry<L, R>, Comparable<Pair<L, R>>, Serializable { + /** Serialization version */ private static final long serialVersionUID = 4954918890077093841L; /** - * Get the "left" element of the pair. - * @return L + * <p>Obtains an immutable pair of from two objects inferring the generic types.</p> + * + * <p>This factory allows the pair to be created using inference to + * obtain the generic types.</p> + * + * @param <L> the left element type + * @param <R> the right element type + * @param left the left element, may be null + * @param right the right element, may be null + * @return a pair formed from the two parameters, not null + */ + public static <L, R> Pair<L, R> of(L left, R right) { + return new ImmutablePair<L, R>(left, right); + } + + //----------------------------------------------------------------------- + /** + * <p>Gets the left element from this pair.</p> + * + * <p>When treated as a key-value pair, this is the key.</p> + * + * @return the left element, may be null */ public abstract L getLeftElement(); /** - * Get the "right" element of the pair. - * @return R + * <p>Gets the right element from this pair.</p> + * + * <p>When treated as a key-value pair, this is the value.</p> + * + * @return the right element, may be null */ public abstract R getRightElement(); /** - * Return {@link #getLeftElement()} as a {@link java.util.Map.Entry}'s key. - * @return L + * <p>Gets the key from this pair.</p> + * + * <p>This method implements the {@code Map.Entry} interface returning the + * left element as the key.</p> + * + * @return the left element as the key, may be null */ public final L getKey() { return getLeftElement(); } /** - * Return {@link #getRightElement()} as a {@link java.util.Map.Entry}'s value. - * @return R + * <p>Gets the value from this pair.</p> + * + * <p>This method implements the {@code Map.Entry} interface returning the + * right element as the value.</p> + * + * @return the right element as the value, may be null */ public R getValue() { return getRightElement(); } + //----------------------------------------------------------------------- /** - * {@inheritDoc} + * <p>Compares the pair based on the first element followed by the second element. + * The types must be {@code Comparable}.</p> + * + * @param other the other pair, not null + * @return negative if this is less, zero if equal, positive if greater + */ + public int compareTo(Pair<L, R> other) { + return new CompareToBuilder().append(getLeftElement(), other.getLeftElement()) + .append(getRightElement(), other.getRightElement()).toComparison(); + } + + /** + * <p>Compares this pair to another based on the two elements.</p> + * + * @param obj the object to compare to, null returns false + * @return true if the elements of the pair are equal */ @Override public boolean equals(Object obj) { if (obj == this) { return true; } - if (obj instanceof Pair<?, ?> == false) { - return false; + if (obj instanceof Map.Entry<?, ?>) { + Map.Entry<?, ?> other = (Map.Entry<?, ?>) obj; + return ObjectUtils.equals(getKey(), other.getKey()) + && ObjectUtils.equals(getValue(), other.getValue()); } - Pair<?, ?> other = (Pair<?, ?>) obj; - return ObjectUtils.equals(getLeftElement(), other.getLeftElement()) - && ObjectUtils.equals(getRightElement(), other.getRightElement()); + return false; } /** - * {@inheritDoc} + * <p>Returns a suitable hash code. + * The hash code follows the definition in {@code Map.Entry}.</p> + * + * @return the hash code */ @Override public int hashCode() { - // TODO should the hashCodeBuilder be seeded per concrete type? - return new HashCodeBuilder().append(getLeftElement()).append(getRightElement()) - .toHashCode(); + // see Map.Entry API specification + return (getKey() == null ? 0 : getKey().hashCode()) ^ + (getValue() == null ? 0 : getValue().hashCode()); } /** - * Returns a String representation of the Pair in the form: (L,R) + * <p>Returns a String representation of the Pair in the form: (L,R).</p> + * * @return a string for this object */ @Override public String toString() { - StringBuilder builder = new StringBuilder(this.getClass().getSimpleName()); + StringBuilder builder = new StringBuilder(); builder.append("("); builder.append(getLeftElement()); builder.append(","); @@ -100,16 +163,4 @@ public abstract class Pair<L, R> impleme return builder.toString(); } - /** - * Static fluent creation method for a {@link Pair}<L, R>: - * <code>Pair.of(left, right)</code> - * @param <L> the left generic type - * @param <R> the right generic type - * @param left the left value - * @param right the right value - * @return ImmutablePair<L, R>(left, right) - */ - public static <L, R> Pair<L, R> of(L left, R right) { - return new ImmutablePair<L, R>(left, right); - } } Modified: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/ImmutablePairTest.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/ImmutablePairTest.java?rev=1091146&r1=1091145&r2=1091146&view=diff ============================================================================== --- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/ImmutablePairTest.java (original) +++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/ImmutablePairTest.java Mon Apr 11 17:48:14 2011 @@ -80,10 +80,10 @@ public class ImmutablePairTest { @Test public void testToString() throws Exception { - assertEquals("ImmutablePair(null,null)", ImmutablePair.of(null, null).toString()); - assertEquals("ImmutablePair(null,two)", ImmutablePair.of(null, "two").toString()); - assertEquals("ImmutablePair(one,null)", ImmutablePair.of("one", null).toString()); - assertEquals("ImmutablePair(one,two)", ImmutablePair.of("one", "two").toString()); + assertEquals("(null,null)", ImmutablePair.of(null, null).toString()); + assertEquals("(null,two)", ImmutablePair.of(null, "two").toString()); + assertEquals("(one,null)", ImmutablePair.of("one", null).toString()); + assertEquals("(one,two)", ImmutablePair.of("one", "two").toString()); } @Test Modified: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/MutablePairTest.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/MutablePairTest.java?rev=1091146&r1=1091145&r2=1091146&view=diff ============================================================================== --- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/MutablePairTest.java (original) +++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/MutablePairTest.java Mon Apr 11 17:48:14 2011 @@ -88,10 +88,10 @@ public class MutablePairTest { @Test public void testToString() throws Exception { - assertEquals("MutablePair(null,null)", MutablePair.of(null, null).toString()); - assertEquals("MutablePair(null,two)", MutablePair.of(null, "two").toString()); - assertEquals("MutablePair(one,null)", MutablePair.of("one", null).toString()); - assertEquals("MutablePair(one,two)", MutablePair.of("one", "two").toString()); + assertEquals("(null,null)", MutablePair.of(null, null).toString()); + assertEquals("(null,two)", MutablePair.of(null, "two").toString()); + assertEquals("(one,null)", MutablePair.of("one", null).toString()); + assertEquals("(one,two)", MutablePair.of("one", "two").toString()); } @Test Modified: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/PairTest.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/PairTest.java?rev=1091146&r1=1091145&r2=1091146&view=diff ============================================================================== --- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/PairTest.java (original) +++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/PairTest.java Mon Apr 11 17:48:14 2011 @@ -21,7 +21,9 @@ import static org.junit.Assert.assertFal import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map.Entry; import org.junit.Test; @@ -44,7 +46,7 @@ public class PairTest { } @Test - public void testCompatibility() throws Exception { + public void testCompatibilityBetweenPairs() throws Exception { Pair<Integer, String> pair = ImmutablePair.of(0, "foo"); Pair<Integer, String> pair2 = MutablePair.of(0, "foo"); assertEquals(pair, pair2); @@ -59,8 +61,39 @@ public class PairTest { } @Test + public void testMapEntry() throws Exception { + Pair<Integer, String> pair = ImmutablePair.of(0, "foo"); + HashMap<Integer, String> map = new HashMap<Integer, String>(); + map.put(0, "foo"); + Entry<Integer, String> entry = map.entrySet().iterator().next(); + assertEquals(pair, entry); + assertEquals(pair.hashCode(), entry.hashCode()); + } + + @Test + public void testComparable1() throws Exception { + Pair<String, String> pair1 = Pair.of("A", "D"); + Pair<String, String> pair2 = Pair.of("B", "C"); + assertEquals(true, pair1.compareTo(pair1) == 0); + assertEquals(true, pair1.compareTo(pair2) < 0); + assertEquals(true, pair2.compareTo(pair2) == 0); + assertEquals(true, pair2.compareTo(pair1) > 0); + } + + @Test + public void testComparable2() throws Exception { + Pair<String, String> pair1 = Pair.of("A", "C"); + Pair<String, String> pair2 = Pair.of("A", "D"); + assertEquals(true, pair1.compareTo(pair1) == 0); + assertEquals(true, pair1.compareTo(pair2) < 0); + assertEquals(true, pair2.compareTo(pair2) == 0); + assertEquals(true, pair2.compareTo(pair1) > 0); + } + + @Test public void testToString() throws Exception { Pair<String, String> pair = Pair.of("Key", "Value"); - assertEquals("ImmutablePair(Key,Value)", pair.toString()); + assertEquals("(Key,Value)", pair.toString()); } + }