package solutions; import java.util.Comparator; import java.util.function.IntBinaryOperator; import static org.junit.Assert.assertEquals; import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import model.Person; /** * Exercises to create comparators using lambda expressions * and using the Comparator combinators. Some of the exercises * use a Person class, which is a simple POJO containing a last * name, first name, and age, with the obvious constructors and * getters. */ public class B_Comparators { final Person michael = new Person("Michael", "Jackson", 51); final Person rod = new Person("Rod", "Stewart", 71); final Person paul = new Person("Paul", "McCartney", 74); final Person mick = new Person("Mick", "Jagger", 73); final Person jermaine = new Person("Jermaine", "Jackson", 61); /** * Write a Comparator that compares instances of Person using their lastName. */ @Test public void comparator1() { //TODO//Comparator<Person> comparebyLastName = null; //BEGINREMOVE Comparator<Person> comparebyLastName = Comparator.comparing(Person::getLastName); //ENDREMOVE assertTrue(comparebyLastName.compare(michael, rod) < 0); assertTrue(comparebyLastName.compare(paul, paul) == 0); assertTrue(comparebyLastName.compare(michael, jermaine) == 0); } // Hint: // <editor-fold defaultstate="collapsed"> // Check the static factory methods of the Comparator interface. Remember // how you implemented functions in the previous exercises. Write it using // a method reference. // </editor-fold> /** * Write a Comparator that compares instances of Person using their * lastName, and if their last name is the same, uses their first name. */ @Test public void comparator2() { //TODO//Comparator<Person> comparebyLastNameThenFirstName = null; //BEGINREMOVE Comparator<Person> comparebyLastNameThenFirstName = Comparator.comparing(Person::getLastName) .thenComparing(Person::getFirstName); //ENDREMOVE assertTrue(comparebyLastNameThenFirstName.compare(michael, rod) < 0); assertTrue(comparebyLastNameThenFirstName.compare(paul, paul) == 0); assertTrue(comparebyLastNameThenFirstName.compare(michael, jermaine) > 0); } // Hint: // <editor-fold defaultstate="collapsed"> // Use the previous comparator and check the default methods of the Comparator interface. // </editor-fold> /** * Write a Comparator that compares the people in the reversed order than * the one you wrote in the comparator2() exercise. */ @Test public void comparator3() { //TODO//Comparator<Person> comparebyLastNameThenFirstNameReversed = null; //BEGINREMOVE Comparator<Person> comparebyLastNameThenFirstNameReversed = Comparator.comparing(Person::getLastName) .thenComparing(Person::getFirstName) .reversed(); //ENDREMOVE assertFalse(comparebyLastNameThenFirstNameReversed.compare(michael, rod) < 0); assertTrue(comparebyLastNameThenFirstNameReversed.compare(paul, paul) == 0); assertFalse(comparebyLastNameThenFirstNameReversed.compare(michael, jermaine) > 0); } // Hint: // <editor-fold defaultstate="collapsed"> // Use the previous comparator and check the default methods of the Comparator interface. // </editor-fold> /** * Write a Comparator that compares the people in the same order than the * one you wrote in comparator2(), but that supports null values. The null * values should be considered greater than any non-null values. */ @Test public void comparator4() { //TODO//Comparator<Person> comparebyLastNameThenFirstNameWithNull = null; //BEGINREMOVE Comparator<Person> comparebyLastNameThenFirstNameWithNull = Comparator.nullsLast( Comparator.comparing(Person::getLastName) .thenComparing(Person::getFirstName)); //ENDREMOVE assertTrue(comparebyLastNameThenFirstNameWithNull.compare(michael, rod) < 0); assertTrue(comparebyLastNameThenFirstNameWithNull.compare(paul, paul) == 0); assertTrue(comparebyLastNameThenFirstNameWithNull.compare(michael, jermaine) > 0); assertTrue(comparebyLastNameThenFirstNameWithNull.compare(mick, null) < 0); assertTrue(comparebyLastNameThenFirstNameWithNull.compare(null, mick) > 0); } // Hint: // <editor-fold defaultstate="collapsed"> // Use the previous comparator and check the static methods of the Comparator interface. // </editor-fold> /** * Write a Comparator that compares two people by age. * Try to write the comparator so as to avoid boxing of primitives. */ @Test public void comparator5() { //TODO//Comparator<Person> comparebyAge = null; //BEGINREMOVE Comparator<Person> comparebyAge = Comparator.comparingInt(Person::getAge); //ENDREMOVE assertTrue(comparebyAge.compare(michael, rod) < 0); assertTrue(comparebyAge.compare(paul, paul) == 0); assertTrue(comparebyAge.compare(mick, jermaine) > 0); } // Hint: // <editor-fold defaultstate="collapsed"> // Look for static methods on the Comparator interface that // have primitive specializations. // </editor-fold> /** * Write a lambda expression that compares two int values and returns an * int result that is less than, equal to, or greater than zero, like * a comparator. Watch out for overflow. The Comparator interface takes * two objects, but in this case we are comparing int primitives, so the * functional interface we use is IntBinaryOperator. */ @Test public void comparator6() { //TODO//IntBinaryOperator intCompare = null; //BEGINREMOVE IntBinaryOperator intCompare = (a, b) -> (a < b) ? -1 : (a > b) ? 1 : 0; // Avoid the following as it is susceptible to overflow: // IntBinaryOperator intCompare = (a, b) -> a - b; //ENDREMOVE assertTrue(intCompare.applyAsInt(0, 1) < 0); assertTrue(intCompare.applyAsInt(1, 1) == 0); assertTrue(intCompare.applyAsInt(2, 1) > 0); assertTrue(intCompare.applyAsInt(Integer.MIN_VALUE, Integer.MAX_VALUE) < 0); assertTrue(intCompare.applyAsInt(Integer.MAX_VALUE, Integer.MIN_VALUE) > 0); } // Hint: // <editor-fold defaultstate="collapsed"> // Use a ternary operator (cond ? result1 : result2) instead of subtraction. // </editor-fold> /** * Write a method reference that compares two int values and returns an * int result that is less than, equal to, or greater than zero, like * a comparator. */ @Test public void comparator7() { //TODO//IntBinaryOperator intCompare = null; //BEGINREMOVE IntBinaryOperator intCompare = Integer::compare; //ENDREMOVE assertTrue(intCompare.applyAsInt(0, 1) < 0); assertTrue(intCompare.applyAsInt(1, 1) == 0); assertTrue(intCompare.applyAsInt(2, 1) > 0); assertTrue(intCompare.applyAsInt(Integer.MIN_VALUE, Integer.MAX_VALUE) < 0); assertTrue(intCompare.applyAsInt(Integer.MAX_VALUE, Integer.MIN_VALUE) > 0); } // Hint: // <editor-fold defaultstate="collapsed"> // Use a method reference to a static method on the Integer class. // </editor-fold> interface DoubleToIntBiFunction { int applyAsInt(double a, double b); } /** * Write a method reference that compares two double values and returns an * int result that is less than, equal to, or greater than zero, like * a comparator. There functional interface that takes two doubles and returns * an int, so we define one here. Comparing double values introduces * special cases such NaN. Consider all NaN values to be equal to each other * and greater than any non-NaN value. */ @Test public void comparator8() { //TODO//DoubleToIntBiFunction doubleCompare = null; //BEGINREMOVE DoubleToIntBiFunction doubleCompare = Double::compare; //ENDREMOVE assertTrue(doubleCompare.applyAsInt(0.0, 1.0) < 0); assertTrue(doubleCompare.applyAsInt(1.0, 1.0) == 0); assertTrue(doubleCompare.applyAsInt(2.0, 1.0) > 0); assertTrue(doubleCompare.applyAsInt(Double.NaN, Double.NaN) == 0); assertTrue(doubleCompare.applyAsInt(Double.NaN, 0.0) > 0); assertTrue(doubleCompare.applyAsInt(0.0, Double.NaN) < 0); } // Hint: // <editor-fold defaultstate="collapsed"> // Use a method reference to a static method on the Double class. // </editor-fold> }