Guava Ordering - Part 1

Guava ordering is a powerhouse class that simplifies using java comparator interface. In part one we will show basics on how call reverse, find the min and max, create Ordering object from existing comparator and position nulls within a list.

Detailed Video Notes

Hey everyone, this is Justin from level up lunch in episode 7 we talked about how java 8 has simplified sorting and has removed complexities while using lambda expressions. If you have adopted java 8, which I imagine many of you haven't, guava provides this powerhouse class called Ordering. Ordering is a fluent comparator that allows you to build complex ways to order collections. In this episode we will show a series of basic examples that use the Ordering class. If you haven't used FluentIterable, Guava's FluentIterable provides a rich interface for manipulating Iterables while Ordering class "enriched" version of Comparator.

Ordering Class

A few things to note about the Ordering. The Ordering class implements comparator which allows backwards compatibility with Collections.sort or other classes built that expect a comparator. This will still allow you to take advantage of features such as chaining, compounding multiple comparators, and creating an Ordering class from an existing comparator you might have. So if you are an architect that gets a little excited about introducing new classes or libraries, guava's Ordering should meet your check mark.

Setup

List<Integer> numbers;

@Before
public void setUp() {
    numbers = Lists.newArrayList(6, 4, 8, 6, 2, 3);
}

Natural Order

[1:35]

For our first series of examples we will create a list of numbers and populate the list with random integers. The first snippet we will show how to order an arraylist in natural order of elements. We will create an Ordering object by calling the Ordering.natural() which will order numbers by least to greatest or lowest to highest.

@Test
public void order_natural() {

    Collections.sort(numbers, Ordering.natural());

    System.out.println(numbers); 
}

Output

[2, 3, 4, 6, 6, 8]

Reverse elements

[2:12]

By calling Ordering.natural().reversed() we can create a comparator in reverse order which will sort the arraylist from highest to lowest or greatest to least values. Chaining these operations together allows a very natural way to pass comparators to Collections.sort.

@Test
public void reverse() {

    Collections.sort(numbers, Ordering.natural().reversed());
    
    System.out.println(numbers); 
}

Output

[8, 6, 6, 4, 3, 2]

Min/Max

[2:38]

Next is min max so if you want to find the maximum value in a collection or minimum value in a collection you can do so by Ordering.natural().max() which should return the greatest value in a collection. Same thing with the minimum by calling Ordering.natural().min() which should return the least value in the collection.

@Test
public void min_max() {

    Integer maxValue = Ordering.natural().max(numbers);

    Integer minValue = Ordering.natural().min(numbers);

    System.out.println(maxValue); 
    System.out.println(minValue);
}

Output

8
2

Create Ordering from Comparator

[3:13]

The next snippet will create an Ordering object based on an existing Comparator. We have created a comparator that will sort Strings by length and a list of strings. Calling Ordering.from and passing in the byLength we will create an Ordering instance based on the comparator. The Ordering class is smart enough to start from an existing comparator which allows you to consume it. Below we call .reversed() or chain another operation which will allows us to sort a list of strings with the longest value first.

Comparator<String> byLength = new Comparator<String>() {
    public int compare(String left, String right) {
        return Integer.compare(left.length(), right.length());
    }
};

@Test
public void from_existing_comparator() {

    List<String> random = Lists.newArrayList("welcome", "to",
            "leveluplunch");

    Comparator<String> reversedByLength = Ordering.from(byLength).reversed();
    Collections.sort(random, reversedByLength);

    System.out.println(random); 
}

Output

[leveluplunch, welcome, to]

Check if a collection is ordered

[4:20]

A neat feature is the Ordering class has the ability to check if a collection is ordered based on a comparator by calling the Ordering.isOrdered. So if you are writing a lot of comparators and you want to write a unit test, this gives you a easy way to validate comparators are working.

assertTrue(Ordering.from(reversedByLength).isOrdered(random));

NullsFirst/NullsLast

[4:50]

Using Ordering chaining mechanism, we can call nullsFirst which will order nulls before non-null elements or nullLast which will order null after all non-null values.

@Test
public void nulls_last_least_of() {

    List<String> random = Lists.newArrayList(null, "welcome", "to",
            "leveluplunch", null, null);

    System.out.println(Ordering.from(byLength).nullsLast().sortedCopy(random));
}

Output

[to, welcome, leveluplunch, null, null, null]

leastOf/greatestOf

[6:26]

Ordering.leastOf will return the a specified number of elements in the beginning of the given iterable according to this ordering. This is is similar taking a limit of a collection or taking a number of elements in an arrayList. Ordering.greatestOf is just the opposite where it will take N number of elements from the end of the collection.

@Test
public void nulls_last_least_of() {

    List<String> random = Lists.newArrayList(null, "welcome", "to",
            "leveluplunch", null, null);

    List<String> firstTwo = Ordering.from(byLength).nullsLast()
            .leastOf(random, 2);

    System.out.println(firstTwo);
}

Output

[to, welcome]

While we we just scratched the surface of guava's Ordering we hope this screencast provided you with a high level look at the features it provides. Thanks for joining in today's level up lunch.