Over a million developers have joined DZone.

NetBeans in the Classroom: Mandatory Methods for Beans (Part 3)

· Java Zone

Learn more about how the Java language, tools and frameworks have been the foundation of countless enterprise systems, brought to you in partnership with Salesforce.

Ken Fogel is the Program Coordinator and Chairperson of the Computer Science Technology program at Dawson College in Montreal, Canada. He is also a Program Consultant to and part-time instructor in the Computer Institute of Concordia University's School of Extended Learning. He blogs at omniprogrammer.com and tweets @omniprof. His regular columns about NetBeans in education are listed here.


In this next article about beans and beginners, following on from part 1 and part 2, I will examine the Comparable interface and the compareTo method. In the previous article I added the interface to the bean and a placeholder method.

public class MyCarBean implements Comparable<MyCarBean> {
  @Override
  public int compareTo(MyCarBean o) {
     throw new UnsupportedOperationException("Not supported yet."); 
  }

Two operations that are frequently carried out when working with multiple instances of objects are searching and sorting. Searching is supported by the equals and hashCode methods. Sorting is supported by the compareTo method. If my beans are in an array then the Arrays.sort method will expect to find a compareTo method.

The compareTo method receives an object of the same type as itself and it is up to you to determine what rules will determine the result. The method equals returns a boolean and therefore can return one of two possible states. The hashCode method returns the calculated hash value which to me is just a single state.  The compareTo method returns one of three possible values and so has three states. These are less than, equal to and greater than.

The usual assumption is that the three values are -1, 0 and +1. This assumption is wrong. A value of 0 does indicate that the object you are comparing yourself to is the same. However, the values to indicate the other two states are based on the sign (positive or negative) of the result and not the actual value of the result. This is important to remember because you should write code such that all the comparisons are relative to zero.

// Wrong way, look at the else if
if (carBean1.compareTo(carBean2) == 0) { // equal
  System.out.println("Bean1 is the same as Bean2");
} else if (carBean1.compareTo(carBean2) == 1) { // Comparing to +1
  System.out.println("Bean1 is the greater than Bean2");
} else { // Not 0 or +1 so must be -1
  System.out.println("Bean1 is the less than Bean2");
}
// Right way
if (carBean1.compareTo(carBean2) == 0) { // equal
  System.out.println("Bean1 is the same as Bean2");
} else if (carBean1.compareTo(carBean2) > 0) { // positive >
  System.out.println("Bean1 is the greater than Bean2");
} else { // negative <
  System.out.println("Bean1 is the less than Bean2");
}

Now all that is left to do is to write the compareTo method. When NetBeans writes the equals method for us it writes code that compares every member of the class. We can then remove any members compared if they are not relevant for equality. Since compareTo is not written for us we must decide right away how we will determine the ordering of the object. We will rarely use every member of the class to make this determination unless the class has only one member.

My example in these articles has been a bean to represent the information most commonly found in advertising for cars. If I created beans for ten different cars and then added them to an array then what order should I expect if I sorted the array? You can think of this decision in one of two ways. If only a single field is used then it is akin to deciding what the primary key will be for a relational database table. If you are using two or more fields then you are creating something akin to a master/detail report. It is the master/detail that I have chosen.

I will use two members of the class, manufacturer and model. This way all cars from a manufacturer will be grouped together and within each group they will be ordered by model. Manufacturer and model are String objects and Strings overload compareTo.

In the event that the object passed to compareTo is null then the NullPointerException will be thrown when code that access a member of the object executes. It would be nice to use a throws clause but as the Comparable interface does not then I cannot. This is why the method header contains a @throws tag to inform the user of this possibility. Null references should rarely be inserted into an array or collection.

/**
 * Orders by the String for manufacturer and if they are the same then
 * order by the model. String objects implement the Comparable interface
 *
 * @param otherbean is a non-null MyCarBean object\
 * @return <0, 0 or >0
 * @throws NullPointerException if otherBean is null
 */
@Override
public int compareTo(MyCarBean otherBean) {
  int retVal = 0; // See the paragraph after this code
  // Step 1: Check if we are comparing the bean to itself
  if (this == otherBean) {
    retVal = 0;
  } else { // Step 2: Check the manufacturer, continuing if it is equal 
    int comparison = 
      this.manufacturer.compareTo(otherBean.manufacturer);
    if (comparison != 0) { // Not equal so no need to look at the model
      retVal = comparison;
    } else {  // Step 3: Manufacturers were the same so compare the model
      retVal = this.model.compareTo(otherBean.model);
    }
 }
 return retVal;
}

I started coding during the structured era. One ideal of that approach is that every methodor function should have one entry point and one exit point. Therefore I teach my students the technique you see in this method where I use a variable called retVal that holds what will be returned. By using if/else my code can have a single exit point. I am slowly accepting that this ideal has been abandoned by most programmers. Therefore the code is more likely to look like:

@Override
public int compareTo(MyCarBean otherBean) {
    // Step 1: Check if we are comparing the bean to itself
    if (this == otherBean) {
        return 0;
    }
    // Step 2: Check the manufacturer, continuing if it is equal 
    int comparison
            = this.manufacturer.compareTo(otherBean.manufacturer);
    // Not equal so no need to look at the model
    if (comparison != 0) {
        return comparison;
    }
    // Step 3: Manufacturers were the same so compare the model
    return this.model.compareTo(otherBean.model);
}

I have long recognized that there are two approached to coding. The academic and the pragmatic. A single return is academic and a gaggle of returns is pragmatic. I will continue to be academic and when my students graduate they can become pragmatic.

Discover how the Force.com Web Services Connector (WSC) is a code-generation tool and runtime library for use with Force.com Web services, brought to you in partnership with Salesforce.

Topics:

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}