Data Structures in Java: Part 11

Baldwin shows you how to use a Comparator to cause a TreeSet collection to be sorted in descending order while preserving the impact of differences in case.

The Comparator Interface, Part 3

Published:  August 20, 2001
By Richard G. Baldwin

Java Programming, Lecture Notes # 1370


Preface

A miniseries

This is the eleventh lesson in a miniseries on Java data structures and the Java Collections Framework.  The first lesson in the miniseries was entitled Data Structures in Java: Part 1, Getting Started.  The previous lesson was entitled Data Structures in Java: Part 10, The Comparator Interface, Part 2.

The purpose of this miniseries is to help you learn the essential features of Object-Oriented data structures in Java using the Collections Framework.

A sub-series

This is also the third lesson in a sub-series on the Comparator interface.  The purpose of the lessons in this sub-series is to teach you about the interactions between the Comparator interface and the Collections Framework, particularly with respect to the Set, SortedSet, and SortedMap interfaces of the Collections Framework.  This lesson discusses Set and SortedSet.  A discussion of SortedMap will be deferred for inclusion in a subsequent lesson.

Viewing tip

You may find it useful to open another copy of this lesson in a separate browser window.  That will make it easier for you to scroll back and forth among the different listings while you are reading about them.

Supplementary material

I recommend that you also study the other lessons in my extensive collection of online Java tutorials.  You will find those lessons published at Gamelan.com.  However, as of the date of this writing, Gamelan doesn't maintain a consolidated index of my Java tutorial lessons, and sometimes they are difficult to locate there.  You will find a consolidated index at Baldwin's Java Programming Tutorials.

Preview

In this lesson, I will teach you how to use a Comparator to cause a TreeSet collection to be sorted in descending order while preserving the impact of differences in case.  We might refer to this as reverse natural order.  In other words, the sorting order is the same as the natural order except that the order is descending instead of ascending.

Discussion and Sample Program

Beginning with a quiz

Let's begin with a little quiz to test your prior knowledge of the Collections Framework.

What output is produced by the program shown in Listing 1?

//File Comparator04.java
//Copyright 2001, R.G.Baldwin

import java.util.*;
import java.io.Serializable;

public class Comparator04{
  public static void main(
                        String args[]){
    new Worker().doIt();
  }//end main()
}//end class Comparator04

class Worker{
  public void doIt(){
    Iterator iter;
    Collection ref;

    ref = new TreeSet(
                  new TheComparator());
    Populator.fillIt(ref);
    iter = ref.iterator();
    while(iter.hasNext()){
      System.out.print(
                    iter.next() + " ");
    }//end while loop
    System.out.println();

  }//end doIt()
}// end class Worker

class Populator{
  public static void fillIt(
                       Collection ref){
    ref.add("Joe");
    ref.add("Bill");
    ref.add("Tom");
    ref.add("JOE");
    ref.add("BILL");
    ref.add("TOM");
  }//end fillIt()
}//end class Populator

class TheComparator  
    implements Comparator,Serializable{
      
  public int compare(
                  Object o1,Object o2){
    if(!(o1 instanceof String))
        throw new ClassCastException();
    if(!(o2 instanceof String))
        throw new ClassCastException();

    int result = ((String)o1).
               compareTo(((String)o2));
    return result*(-1);
  }//end compare()
    
  public boolean equals(Object o){
    if(!(o instanceof TheComparator))
        return false;
    else return true;
  }//end overridden equals()
}//end class TheComparator

Listing 1

If you selected the following, you are correct:

D.  Tom TOM Joe JOE Bill BILL

Similar to previous programs

The overall structure of this program is very similar to programs that I have discussed in previous lessons.  Therefore, I will concentrate on those aspects of this program that differentiate it from the programs in previous lessons.

A new TreeSet object with a Comparator

The code in Listing 2 instantiates a new TreeSet object, by providing a reference to an anonymous object that implements the Comparator interface.  That object is instantiated from the class named TheComparator.  It is the Comparator object that will be of most interest to us in this lesson.
 
    Collection ref;

    ref = new TreeSet(
                  new TheComparator());
    Populator.fillIt(ref);

    iter = ref.iterator();
    while(iter.hasNext()){
      System.out.print(
                    iter.next() + " ");
    }//end while loop

Listing 2

Populating the TreeSet collection

After the TreeSet object is instantiated, it is passed to a method named fillIt where the TreeSet collection is populated with the names of several people.

Display the contents of the TreeSet collection

As shown by the code in Listing 2, after the TreeSet collection is populated, an Iterator is obtained for that collection and used to display the contents of the collection.  The output produced by the program is shown below:

Tom TOM Joe JOE Bill BILL

Analyzing the contents of the TreeSet collection

We will need to compare this output with the names used to populate the collection to appreciate the true significance of the use of the Comparator object.

At this point, it is worth pointing out that the six names contained in the collection are returned by the iterator in descending order, taking the significance of upper and lower case into account.  In other words, names beginning with letters that are high in the alphabet occur before names beginning with letters that are lower in the alphabet.  In addition, names containing lower case characters appear before the same names containing only upper case characters.

Method used to populate the collection

Listing 3 shows the method named fillIt that was used to populate the collection with references to six String objects.  As you can see, the names weren't added in any particular order.

As you can also see by comparing Listing 3 with the output shown above, all six names that were added to the collection were displayed in the output, but in a different order from the order in which they were added. (Names with the same spelling but different case were not considered to be duplicates insofar as the contract for the set was concerned.)
 
  public static void fillIt(
                       Collection ref){
    ref.add("Joe");
    ref.add("Bill");
    ref.add("Tom");
    ref.add("JOE");
    ref.add("BILL");
    ref.add("TOM");
  }//end fillIt()

Listing 3

Implementing the Comparator interface

That brings us to the class from which the Comparator object was instantiated.  The beginning portion of that class is shown in Listing 4.
 
class TheComparator  
    implements Comparator,Serializable{
      
  public int compare(
                  Object o1,Object o2){
    if(!(o1 instanceof String))
        throw new ClassCastException();
    if(!(o2 instanceof String))
        throw new ClassCastException();

Listing 4

The code in Listing 4 isn't particularly interesting.  That code simply throws an exception if either of the references passed to the compare method refer to an object of some type other than String.

The interesting code

The interesting code is shown in Listing 5.  The first statement in Listing 5 uses the compareTo method of the string class to compare the two objects in an ascending natural ordering sense.  The behavior of this method is more formally described as follows:

"Returns:  the value 0 if the argument is a string lexicographically equal to this string; a value less than 0 if the argument is a string lexicographically greater than this string; and a value greater than 0 if the argument is a string lexicographically less than this string."
    int result = ((String)o1).
               compareTo(((String)o2));

    return result*(-1);

Listing 5

Converting to reverse natural order

The most interesting line of code in this entire program is the return statement shown in Listing 5.  This line of code changes the sign on the value returned by the compareTo method before returning it as the return value for the compare method.  The effect of changing the sign is to return a value that causes the TreeSet collection to arrange the elements in reverse natural order instead of the normal ascending natural order.

As a result, the use of an iterator to access and display the contents of the collection is as follows:

Tom TOM Joe JOE Bill BILL

For comparison, if the names were arranged in ascending natural order, the output would be as shown below:

BILL Bill JOE Joe TOM Tom
 

Summary

In this lesson, I taught you how to use a Comparator to cause a TreeSet collection to be sorted in reverse natural order.  In other words, the sorting order is the same as the natural order except that the order is descending instead of ascending.

What's Next?

In the next lesson, I will show you how to use a Comparator object to sort the contents of an array.


Copyright 2001, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor and private consultant whose primary focus is a combination of Java and XML. In addition to the many platform-independent benefits of Java applications, he believes that a combination of Java and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects involving Java, XML, or a combination of the two.  He frequently provides onsite Java and/or XML training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Java Programming Tutorials, which has gained a worldwide following among experienced and aspiring Java programmers. He has also published articles on Java Programming in Java Pro magazine.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

baldwin.richard@iname.com

-end-