4.3. Reversing a Comparator

Problem

You need to reverse the effects of a Comparator. You need to return less than when this Comparator returns greater than, and greater than when it returns less than.

Solution

Use ReverseComparator to reverse the effects of a Comparator. Supply an existing Comparator to the constructor of ReverseComparator, and it reverses the effects of that Comparator. The following example demonstrates the use of ReverseComparator to reverse the result of a custom MyComparator instance:

Comparator myComparator = new MyComparator( );

Comparator reverseComparator = new ReverseComparator( myComparator );

Book book1 = new Book( );
Book book2 = new Book( );

int comparison = myComparator.compare( book1, book2 );
int reversedComparison = reverseComparator( book1, book2);

The value of reversedComparison is simply the negative of comparison; if MyComparator decides that book1 is less than book2, the ReverseComparator returns the opposite result—greater than. ReverseComparator simply wraps the original Comparator and multiplies the result by negative one.

Discussion

Example 4-1 is an implementation of a Comparator that is reversed using the ReverseComparator. This BookComparator compares two Book objects by the name and author bean properties. Sorting a list of books using this Comparator results in a list sorted alphabetically by book name and author name; if two books have the same name, they are sorted by author name.

Example 4-1. A Comparator that compares Book objects by name and author

package com.discursive.jccook.collections.compare;

import java.util.*;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.collections.comparators.ReverseComparator;

public class BookComparator implements Comparator {
    
    public int compare(Object o1, Object o2) {
         int comparison = -1;

        if( o1 instanceof Book && o2 instanceof Book ) {
            Book b1 = (Book) o1;
            Book b2 = (Book) o2;
        
             String b1Name = b1.getName( );
             String b2Name = b2.getName( );

             String b1Author = b1.getAuthor( );
             String b2Author = b2.getAuthor( );

            if( StringUtils.isNotEmpty( b1Name ) &&
                StringUtils.isNotEmpty( b2Name ) ) {
                comparison = b1Name.compareTo( b2Name );
            }

            if( comparison == 0 &&
                StringUtils.isNotEmpty( b1Author ) &&
                StringUtils.isNotEmpty( b2Author ) ) {
                comparison = b1Author.compareTo( b2Author );
            }   
        }
        return comparison;
    }
}

Example 4-2 sorts an array of Book objects in reverse order.

Example 4-2. Using ReverseComparator to sort Book objects

package com.discursive.jccook.collections.compare;

import java.util.*;
import org.apache.commons.collections.comparators.ReverseComparator;

public class ReverseExample {

    public static void main(String[] args) throws Exception {
        ReverseExample example = new ReverseExample( );
        example.start( );
    }
    
    public void start( ) throws Exception {

        // Create a Reversed BookComparator
                          Comparator bookCompare = new BookComparator( );
                          Comparator reverseComparator = new ReverseComparator( bookComparator );

        // Create a List of Book objects
        List books = new ArrayList( );

        Book book1 = new Book( );
        book1.setName( "TitleA" );
        book1.setAuthor( "John" );
        books.add( book1 );

        Book book2 = new Book( );
        book2.setName( "TitleB" );
        book2.setAuthor( "Donald" );
        books.add( book2 )

        Book book3 = new Book( );
        book3.setName( "TitleA" );
        book3.setAuthor( "Doug" );
        books.add( book3 );

        // Sort the List of Book objects with the Reversed BookComparator
                          Collections.sort( books, reverseComparator );

    }    
}

After Collections.sort( ), the books array is sorted in reverse alphabetical order by book name and author name: “TitleB by Donald” followed by “TitleA by John” followed by “TitleA by Doug.”

See Also

If you were using a simple Comparator to sort an array, you could sort and reverse the resulting array with Arrays.reverse( ), or you could reverse a List with Collections.reverse( ). Wrapping a Comparator in ReverseComparator may help you avoid the call to reverse( ), but the benefit is miniscule. ReverseComparator makes more sense when used in the context of a ChainedComparator; see Recipe 4.4 for more information about the ChainedComparator.

Note that use of StringUtils.isNotEmpty( ) is used in BookComparator to check if either of the bean properties are null or blank. This utility, is from StringUtils, and it is introduced in Recipe 2.2.

Get Jakarta Commons Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.