## Comparing based on `boolean`

values¶

Imagine we have the following class which stores information about the environmental impact of a company. A shell of our class might look like

```
public class EnvironmentalImpact {
private String companyName;
private double emissions; // emissions emitted
private int violations; // total violations committed
// Can't just use emissions because
// regulations could differ depending on the company
private boolean meetsRegulations;
// Various constructors and methods
}
```

It would be nice to be able to order these companies based on their environmental impact, so let’s have our class implement the `Comparable`

interface

```
public class EnvironmentalImpact implements Comparable<EnvironmentalImpact> {
private String companyName;
private double emissions;
private int violations;
private boolean meetsRegulations;
// Various constructors and methods
public int compareTo(EnvironmentalImpact other) {
// TODO: decide order/implement this method
}
}
```

Say I want to sort the list of companies by damage to the environment, such that the most damaging ones appear first. Since I have decided this application for the `EnvironmentalImpact`

, we must make `compareTo`

work for it. The application of our class in `Comparable`

situations determines how we should implement our `compareTo`

method.

### Brief review of `compareTo`

ordering¶

Before we implement `compareTo`

for our class, let’s review how `compareTo`

determines ordering. Say we have two objects we are comparing, object `A`

and object `B`

, and a method call `A.compareTo(B)`

. Remember, when we implement `compareTo`

methods in a class, object `A`

will be referred to by the `this`

reference, while object `B`

will be referred to by the parameter reference (usually named `other`

). The call `A.compareTo(B)`

will return:

- A negative number if
`A`

(`this`

object) is considered**less than**`B`

(`other`

object) - A positive number if
`A`

(`this`

object) is considered**greater than**`B`

- 0 if
`A`

(`this`

object) is considered**equal to**`B`

(`other`

object)

### Back to our environmental impact example¶

One way we could order the companies is based on whether or not they meet the environmental regulations that apply to them. Do we want companies that meet regulations to appear earlier or later in a sorted list? Since they aren’t as damaging to the environment, we want them to appear later in the list, so we need our `compareTo`

return to signify that companies that currently meet regulations are considered **greater than** companies that do not meet regulations (remember, an object considered **greater than** another object appears later in a sorted list).

Sometimes students get a bit tripped up when trying to compare `boolean`

values because you can’t subtract `boolean`

values. Subtraction should not be thought of as the way to solve `compareTo`

problems, but more as a special trick that sometimes works for comparing based on `int`

values. `if/else`

structures are the more general tool for solving `compareTo`

problems. The following would be a decent attempt at comparing based on `meetsRegulations`

```
public int compareTo(EnvironmentalImpact other) {
if (this.meetsRegulations && !other.meetsRegulations) {
return 1;
} else if (!this.meetsRegulations && other.meetsRegulations)
return -1;
} else {
return 0;
}
}
```

If the `EnvironmentalImpact`

object referred to by `this`

meets regulations but the one referred to by `other`

does not, then we want to signify that `this`

object **is greater than** the `other`

, so we return `1`

. And vice versa, if the `other`

object meets regulations but `this`

object does not, then we want to signify that `this`

object **is less than** the `other`

, so we return `-1`

. The above two cases cover when the two objects’ `meetsRegulations`

fields differ, so what is left is the case when both objects meet regulations and the case when neither object meets regulations. In these cases, we want to signify that the two objects are considered **equal**, so we return `0`

.

Perhaps you’re thinking that it would be nice to use a bit more of the information in our class to compare companies. Let’s add in a comparison based on the emissions of companies. We want companies to be compared as follows:

- Companies that meet regulations should be considered
**greater than**companies that do not meet regulations - If two companies either both meet regulations or both do not meet regulations, then they should be ordered based on emissions. Companies that emit more emissions should be considered
**less than**companies that emit less emissions

Below is an example of an attempt at a `compareTo`

implementation for the specified behavior

```
public int compareTo(EnvironmentalImpact other) {
if (this.meetsRegulations != other.meetsRegulations) {
// Note: Why don't I need to write this.meetsRegulations && !other.meetsRegulations?
if (this.meetsRegulations)
return 1;
} else {
return -1;
}
} else {
return (int) (other.emissions - this.emissions);
}
}
```

The check for `if (this.meetsRegulations != other.meetsRegulations)`

is what decides whether we should compare the objects based on meeting regulations or based on emissions. If the two `boolean`

values differ, then we want to compare based on meeting regulations.

In the case that the two objects’ `meetsRegulations`

fields are the same, we actually have a bug. What if our emissions differ by `0.1`

? Casting to an `int`

floors this value, so we end up returning `0`

signifying the two objects are equal when they aren’t! Remember, we can’t use the subtraction trick when comparing `double`

values. Below is a revised version of the method, which properly compares the `emissions`

fields of the two objects.

```
public int compareTo(EnvironmentalImpact other) {
if (this.meetsRegulations != other.meetsRegulations) {
if (this.meetsRegulations)
return 1;
} else {
return -1;
}
} else {
double delta = this.emissions - other.emissions;
if (delta < 0) {
return 1;
} else if (delta > 0) {
return -1;
} else {
return 0;
}
}
}
```

### Optional Material: `Math.signum`

¶

There is a convenient method in the `Math`

class that makes comparing by `double`

values much easier. `Math.signum`

takes a `double`

and returns a `double`

, either `-1.0`

if the given parameter is less than `0`

, `0.0`

if the given parameter is `0`

, or `1.0`

if the given parameter is greater than `0`

. For example:

```
double test1 = -4.0;
double test2 = 0;
double test3 = 4.0;
Math.signum(test1); //returns -1.0
Math.signum(test2); //returns 0.0
Math.signum(test3); //returns 1.0
```

`compareTo`

method? Well instead of writing the `if/else`

branches above, we could just write the following line of code (remembering to cast the result of `Math.signum`

to an `int`

) ```
return (int) Math.signum(other.emissions - this.emissions);
```

`Math.signum`

can be a useful tool, but is by no means required when writing `compareTo`

methods.

### Recap¶

In summary, comparing `boolean`

values is similar to comparing any other value type; all we need to do is remember how `compareTo`

orders objects and then return values based on the specified ordering. An above example had the common error of trying to use the subtraction trick when comparing `double`

values. The subtraction trick is just a special trick that can work for comparing `int`

values. In general, it would be better to think of structuring `compareTo`

methods based on a series of `if/else`

branches, as that captures much more accurately the logical process that is performed when comparing objects.

## More practice¶

Try out this problem and this other problem for more practice writing `compareTo`

methods.