Skip to content

Instantly share code, notes, and snippets.

@kkleidal
Created November 28, 2014 22:40
Show Gist options
  • Save kkleidal/af3ef3d7e73105a36412 to your computer and use it in GitHub Desktop.
Save kkleidal/af3ef3d7e73105a36412 to your computer and use it in GitHub Desktop.
Java Pair class
package util;
/**
* Creates a pair of two objects
*
* @param <T1> the type of object 1
* @param <T2> the type of object 2
*/
public class Pair<T1, T2> {
/**
* The first object
*/
private final T1 obj1;
/**
* The second object
*/
private final T2 obj2;
/**
* Creates a new pair of objects
*
* @param first the first object
* @param second the second object
*/
public Pair(T1 first, T2 second) {
this.obj1 = first;
this.obj2 = second;
}
/**
* @return the first object
*/
public T1 getFirst() {
return this.obj1;
}
/**
* @return the second object
*/
public T2 getSecond() {
return this.obj2;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof Pair<?,?>)) {
return false;
}
Pair<?,?> otherObj = (Pair<?,?>)other;
return otherObj.obj1.equals(obj1) && otherObj.obj2.equals(obj2);
}
/**
* The number of bits per bytes
*/
private static final int BITS_PER_BYTES = 8;
/**
* The number of bytes in the hash
*/
private static final int NUMBER_BITS = Integer.BYTES * BITS_PER_BYTES;
/**
* The number of bytes in the hash
*/
private static final int HALF_NUMBER_BITS = NUMBER_BITS / 2;
/**
* 0's for the first half of the int, 1's for the second half of the int
*/
private static final int EMPTY_FULL = (1 << (HALF_NUMBER_BITS + 1)) - 1;
/**
* 1's for the first half of the int, 0's for the second half of the int
*/
private static final int FULL_EMPTY = EMPTY_FULL << HALF_NUMBER_BITS;
@Override
public int hashCode() {
int firstHash = this.obj1.hashCode();
int first16Bits = (EMPTY_FULL & firstHash) ^ ((FULL_EMPTY & firstHash) >> HALF_NUMBER_BITS);
int secondHash = this.obj2.hashCode();
int second16Bits = (EMPTY_FULL & secondHash) ^ ((FULL_EMPTY & secondHash) >> HALF_NUMBER_BITS);
return (first16Bits << HALF_NUMBER_BITS) | second16Bits;
}
@Override
public String toString() {
return String.format("Pair<%s, %s>", this.obj1.toString(),
this.obj2.toString());
}
}
package util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.*;
/**
* Tests for the Pair class
*/
public class PairTest {
/*
* Testing strategy
*
* - creation
* - access to elements
* - nested pairs
* - equality/hash code
* - equal object
* - non-equal objects
*/
/**
* Tests creation of basic pair
*/
@Test
public void pairCreation() {
Pair<Integer, String> examplePair =
new Pair<Integer, String>(42, "the answer to life the universe and everything");
assertEquals(42, examplePair.getFirst().intValue());
assertEquals("the answer to life the universe and everything", examplePair.getSecond());
}
/**
* Tests creation of nested pair
*/
@Test
public void nestedPirCreation() {
Pair<Integer, Pair<String, String>> nestedPair =
new Pair<Integer, Pair<String, String>>(42, new Pair<String, String>("the answer to life", "the universe and everything"));
assertEquals(42, nestedPair.getFirst().intValue());
assertEquals("the answer to life", nestedPair.getSecond().getFirst());
assertEquals("the universe and everything", nestedPair.getSecond().getSecond());
}
/**
* Tests equality and hashing for two equal objects
*/
@Test
public void equalityEqual() {
Pair<Integer, Pair<String, String>> nestedPair1 =
new Pair<Integer, Pair<String, String>>(42, new Pair<String, String>("the answer to life", "the universe and everything"));
Pair<Integer, Pair<String, String>> nestedPair2 =
new Pair<Integer, Pair<String, String>>(42, new Pair<String, String>("the answer to life", "the universe and everything"));
assertTrue(nestedPair1.equals(nestedPair2));
assertTrue(nestedPair2.equals(nestedPair1));
assertTrue(nestedPair1.hashCode() == nestedPair2.hashCode());
}
/**
* Tests equality and hashing for two inequal objects
*/
@Test
public void equalityInequal() {
Pair<Integer, Pair<String, String>> nestedPair1 =
new Pair<Integer, Pair<String, String>>(42, new Pair<String, String>("the answer to life", "the universe and everything"));
Pair<Integer, Pair<String, String>> nestedPair2 =
new Pair<Integer, Pair<String, String>>(42, new Pair<String, String>("the answer to life", "he universe and everything"));
assertFalse(nestedPair1.equals(nestedPair2));
assertFalse(nestedPair2.equals(nestedPair1));
if (nestedPair1.hashCode() == nestedPair2.hashCode()) {
System.err.println("Warning: hash collision between " + nestedPair1.toString() + " and " + nestedPair2.toString());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment