diff --git a/src/java.base/share/classes/java/util/Couple.java b/src/java.base/share/classes/java/util/Couple.java new file mode 100644 index 0000000000000..b8eb874ec7729 --- /dev/null +++ b/src/java.base/share/classes/java/util/Couple.java @@ -0,0 +1,162 @@ +package java.util; + +/** + * The {@code Couple} class represents a mutable, ordered Couple of elements. + *

+ * This class mimics the behavior of the C++ Standard Library's `std::Couple`, providing two values, referred to as + * the "first" and the "second" elements, of possibly different types. + *

+ * The {@code Couple} class provides a parameterized constructor to initialize both elements and allows access to them + * through getter and setter methods. + * + * @param the type of the first element + * @param the type of the second element + * + * @author Adarsh Sharma + * @since 1.0 + */ +public class Couple, V extends Comparable> + implements Comparable> { + private K first; + private V second; + + /** + * Constructs a new Couple with the specified values. + * + * @param first the first element of the Couple + * @param second the second element of the Couple + */ + public Couple(K first, V second) { + this.first = first; + this.second = second; + } + + /** + * Returns the first element of the Couple. + * + * @return the first element of the Couple + */ + public K getFirst() { + return first; + } + + /** + * Sets the first element of the Couple. + * + * @param first the first element of the Couple + */ + public void setFirst(K first) { + this.first = first; + } + + /** + * Returns the second element of the Couple. + * + * @return the second element of the Couple + */ + public V getSecond() { + return second; + } + + /** + * Sets the second element of the Couple. + * + * @param second the second element of the Couple + */ + public void setSecond(V second) { + this.second = second; + } + + /** + * Compares this Couple with the specified Couple for order. + *

+ * Comparison is based first on the {@code first} elements, and if they are equal, + * then on the {@code second} elements. Both elements are compared using their natural ordering, + * unless they are {@code null}, in which case {@code null} is considered less than non-null. + *

+ * This method is {@code null}-safe and consistent with equals when both elements are non-null. + * + * @param other the Couple to be compared + * @return a negative integer, zero, or a positive integer as this Couple + * is less than, equal to, or greater than the specified Couple + * @throws NullPointerException if {@code other} is {@code null} + */ + @Override + public int compareTo(Couple other) { + if (other == null) { + throw new NullPointerException("Compared Couple must not be null"); + } + + int cmp = compareNullable(this.first, other.first); + if (cmp != 0) { + return cmp; + } + + return compareNullable(this.second, other.second); + } + + /** + * Helper method to compare two Comparable objects, handling nulls. + * {@code null} is considered less than any non-null value. + * + * @param a first value + * @param b second value + * @return comparison result + */ + @SuppressWarnings("unchecked") + private > int compareNullable(T a, T b) { + if (a == b) return 0; + if (a == null) return -1; + if (b == null) return 1; + return a.compareTo(b); + } + + /** + * Returns a string representation of this Couple in the format {@code (first, second)}. + * + * @return a string representation of this Couple + */ + @Override + public String toString() { + return "(" + first + ", " + second + ")"; + } + + /** + * Checks if this Couple is equal to another object. Two Couples are considered equal if both the first and second + * elements are equal. + * + * @param o the object to compare this Couple with + * @return {@code true} if this Couple is equal to the specified object + */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Couple Couple = (Couple) o; + return Objects.equals(first, Couple.first) && Objects.equals(second, Couple.second); + } + + /** + * Returns the hash code for this Couple, computed based on the hash codes of the first and second elements. + * + * @return the hash code for this Couple + */ + @Override + public int hashCode() { + return Objects.hash(first, second); + } + + /** + * Creates a new {@code Couple} with the given first and second elements. + * + * @param first the first element of the Couple + * @param second the second element of the Couple + * @param the type of the first element, must be Comparable + * @param the type of the second element, must be Comparable + * @return a new {@code Couple} containing the given elements + */ + public static , V extends Comparable> + Couple makeCouple(K first, V second) { + return new Couple<>(first, second); + } +} diff --git a/test/jdk/java/util/Couple/CoupleTest.java b/test/jdk/java/util/Couple/CoupleTest.java new file mode 100644 index 0000000000000..393bdcb934502 --- /dev/null +++ b/test/jdk/java/util/Couple/CoupleTest.java @@ -0,0 +1,190 @@ +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.util.Objects; +import java.util.Stack; + +/** + * Unit tests for the {@link Couple} class. + *

+ * This class validates all functionalities of the {@code Couple} class including construction, getters/setters, + * equality, comparison, hash code generation, string representation, and utility methods like {@code swap} and + * {@code makeCouple}. It ensures correct behavior across different data types and edge cases (nulls, identity, etc.). + *

+ * + * @author Adarsh Sharma + * @since 1.0 + */ +public class CoupleTest { + + /** + * Verifies that the constructor initializes the first and second elements correctly. + */ + @Test + public void testConstructor() { + Couple Couple = new Couple<>(1, "one"); + Assert.assertEquals(Couple.getFirst(), Integer.valueOf(1)); + Assert.assertEquals(Couple.getSecond(), "one"); + } + + /** + * Verifies that the getter and setter methods update and retrieve values as expected. + */ + @Test + public void testGettersAndSetters() { + Couple Couple = new Couple<>(1, "one"); + Couple.setFirst(2); + Couple.setSecond("two"); + Assert.assertEquals(Couple.getFirst(), Integer.valueOf(2)); + Assert.assertEquals(Couple.getSecond(), "two"); + } + + /** + * Verifies that the {@code equals} method correctly evaluates object equality. + */ + @Test + public void testEquals() { + Couple Couple1 = new Couple<>(1, "one"); + Couple Couple2 = new Couple<>(1, "one"); + Couple Couple3 = new Couple<>(2, "two"); + + Assert.assertTrue(Couple1.equals(Couple2)); + Assert.assertFalse(Couple1.equals(Couple3)); + Assert.assertFalse(Couple1.equals(null)); + Assert.assertFalse(Couple1.equals("not a Couple")); + Assert.assertTrue(Couple1.equals(Couple1)); // Self-comparison + } + + /** + * Verifies equality behavior when one or both elements are {@code null}. + */ + @Test + public void testEqualsWithNullElements() { + Couple Couple1 = new Couple<>(null, "one"); + Couple Couple2 = new Couple<>(null, "one"); + Assert.assertTrue(Couple1.equals(Couple2)); + Couple Couple3 = new Couple<>(null, null); + Couple Couple4 = new Couple<>(null, null); + Assert.assertTrue(Couple1.equals(Couple2)); + Assert.assertTrue(Couple2.equals(Couple1)); + } + + /** + * Validates that {@code hashCode} is consistent for equal Couples. + */ + @Test + public void testHashCode() { + Couple Couple1 = new Couple<>(1, "one"); + Couple Couple2 = new Couple<>(1, "one"); + Assert.assertEquals(Couple1.hashCode(), Couple2.hashCode()); + } + + /** + * Ensures {@code hashCode} handles {@code null} elements correctly. + */ + @Test + public void testHashCodeWithNulls() { + Couple Couple = new Couple<>(null, null); + Assert.assertEquals(Couple.hashCode(), Objects.hash(null, null)); + } + + /** + * Validates the static factory method {@code makeCouple} creates an equivalent {@code Couple}. + */ + @Test + public void testMakeCouple() { + Couple Couple = Couple.makeCouple(1, "one"); + Assert.assertEquals(Couple.getFirst(), Integer.valueOf(1)); + Assert.assertEquals(Couple.getSecond(), "one"); + } + + /** + * Tests usage of {@code Couple} with custom objects such as {@code Stack}. + */ + @Test + public void testCustomObjects() { + Couple, String> Couple = new Couple<>(new Stack<>(), "test"); + Couple.getFirst().push(1); + Couple.getFirst().push(2); + Assert.assertEquals(Couple.getFirst().size(), 2); + Assert.assertEquals(Couple.getSecond(), "test"); + } + + /** + * Validates the {@code toString} representation for non-null elements. + */ + @Test + public void testToString() { + Couple Couple = new Couple<>(1, "one"); + Assert.assertEquals(Couple.toString(), "(1, one)"); + } + + /** + * Validates the {@code toString} representation when both elements are {@code null}. + */ + @Test + public void testToStringWithNulls() { + Couple Couple = new Couple<>(null, null); + Assert.assertEquals(Couple.toString(), "(null, null)"); + } + + /** + * Validates that {@code compareTo} returns zero for equal Couples. + */ + @Test + public void testCompareToEqual() { + Couple Couple1 = new Couple<>("a", "b"); + Couple Couple2 = new Couple<>("a", "b"); + Assert.assertEquals(Couple1.compareTo(Couple2), 0); + } + + /** + * Validates that {@code compareTo} returns a negative or positive value + * when the first elements differ. + */ + @Test + public void testCompareToFirstDifferent() { + Couple Couple1 = new Couple<>("a", "b"); + Couple Couple2 = new Couple<>("b", "b"); + Assert.assertTrue(Couple1.compareTo(Couple2) < 0); + Assert.assertTrue(Couple2.compareTo(Couple1) > 0); + } + + /** + * Validates that {@code compareTo} evaluates second elements when first are equal. + */ + @Test + public void testCompareToSecondDifferent() { + Couple Couple1 = new Couple<>("a", "b"); + Couple Couple2 = new Couple<>("a", "c"); + Assert.assertTrue(Couple1.compareTo(Couple2) < 0); + } + + /** + * Tests {@code compareTo} behavior when one or both elements are {@code null}. + */ + @Test + public void testCompareToWithNulls() { + Couple Couple1 = new Couple<>(null, "b"); + Couple Couple2 = new Couple<>("a", "b"); + Assert.assertTrue(Couple1.compareTo(Couple2) < 0); + + Couple Couple3 = new Couple<>("a", null); + Couple Couple4 = new Couple<>("a", "b"); + Assert.assertTrue(Couple3.compareTo(Couple4) < 0); + + Couple Couple5 = new Couple<>(null, null); + Couple Couple6 = new Couple<>(null, null); + Assert.assertEquals(Couple5.compareTo(Couple6), 0); + // null is considered less than non-null for comparison + } + + /** + * Verifies that passing {@code null} to {@code compareTo} throws {@code NullPointerException}. + */ + @Test(expectedExceptions = NullPointerException.class) + public void testCompareToNull() { + Couple Couple = new Couple<>("a", "b"); + Couple.compareTo(null); + } +}