0

I'm very new to java. I know that the Java Comparable interface has only one method, which has an int return type. However, I'm not sure what I am actually doing when I want to override the compareTo method. It's important to me to understand programming and not just memorizing it.

For example, in the following code we have an int variable "spaceshipClassComparison", which is equal to "this.spaceshipClass.compareTo(other.spaceshipClass)". I know that that this method returns the values of 1,0,-1, but I don't understand what we are doing when we call compareTo() again for this.spaceship but this time with a new object and how does it turn to integer?

public class Spaceship implements Comparable<Spaceship> {

    private String spaceshipClass = null;
    private String registrationNo = null;

    public Spaceship(String spaceshipClass, String registrationNo) {
        this.spaceshipClass = spaceshipClass;
        this.registrationNo = registrationNo;
    }

    @Override
    public int compareTo(Spaceship other) {
        int spaceshipClassComparison =
                this.spaceshipClass.compareTo(other.spaceshipClass);

        if(spaceshipClassComparison != 0) {
            return spaceshipClassComparison;
        }
        
        return this.registrationNo.compareTo(other.registrationNo);
    }
}    
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • 1
    Did you try debugging it to see the flow? Anyway, this code uses `String.compareTo()` implementation, if `spaceshipClass` comparison is not 0, then return the result, otherwise compare `registrationNo` and return result. If you want to understand how to use `compareTo()` it would be best to start with reading the docs for [Comparable](https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html). – Chaosfire May 08 '22 at 12:33
  • i knew what the code does and what it means i dont why we write it in that way . why we call compareTo and it produce 1,-1,0 ? – Vanillo.schnitzel May 08 '22 at 12:35
  • As long as it produces a positive number, a negative number or 0, all is fine. It doesn’t have to be 1 and -1. – Ole V.V. May 08 '22 at 12:50
  • 2
    The result of comparing two elements of a set (i.e. two instances of a class) can be one of `less-than (LT)`, `equal (EQ)` or `greater-than (GT)`. To encode these 3 different scenarios, the convention was to return a signed `int` value that would be negative (LT), `0` (EQ) or positive (GT). Why is this needed? Look at the [`Collections.sort()` utility](https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#sort(java.util.List)), that can take a list of _anything that is Comparable_ and will sort it "naturally" (using `compareTo()` to establish the relative order of elements). – Costi Ciudatu May 08 '22 at 12:58

2 Answers2

0

The compareTo method is used to establish a natural ordering among the elements of a class. Here is a link which expands the concept of natural ordering.

https://docs.oracle.com/javase/tutorial/collections/interfaces/order.html

To get back to your example, I think you're having troubles in understanding the idea of it because you're comparing two String objects which are in turn invoking their compareTo implementation which does other operations under the hood. Basically, they just perform an alphabetical comparison to establish if the current string is lower, equal or greater than the given parameter.

Let's make a simpler example with another class, though. Let's say we have a Person class with just name, last name and age, and that we want to establish its natural ordering by comparing people by their age.

class Person implements Comparable<Person> {
    private String name, lastName;
    private int age;

    public Person(String name, String lastName, int age) {
        this.name = name;
        this.lastName = lastName;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }

    @Override
    public int compareTo(Person otherPerson) {
        //If the current person's age is lower than otherPerson's age than we return -1, as the current person is "lower" than the other (ordering-wise)
        if (age < otherPerson.getAge()) {
            return -1;
        }

        //If the current person's age is equal to the otherPerson's age than we return 0, as the current person is "equal" to the other (ordering-wise)
        if (age == otherPerson.getAge()) {
            return 0;
        }

        //Here, there are no other cases left so the current person's age is greater than the otherPerson's age, so we return 1.
        return 1;
    }

    public static void main(String[] args) {
        Person p1 = new Person("Matt", "O'Brien", 20);
        Person p2 = new Person("Matt", "O'Brien", 25);
        Person p3 = new Person("George", "Lucas", 25);

        System.out.println(p1.compareTo(p2));   //Prints -1 because 20 is lower than 25
        System.out.println(p2.compareTo(p1));   //Prints 1 because 25 is greater than 20
        System.out.println(p2.compareTo(p2));   //Prints 0 because 20 is equal to 20 even though we're comparing different people, because in the comprateTo we're only confronting the age
    }
}

What you're doing in your compareTo example is basically establishing a natural ordering between Spaceship elements, first by their class and then by their number. In fact, if the alphabetical order of their class is different from 0, then this value is immediately returned. Otherwise, if their class is the same, another comparison is performed (by registration number) and its value returned.

public int compareTo(Spaceship other) {
    //Saving the comparison value between the spaceships' class
    int spaceshipClassComparison =
            this.spaceshipClass.compareTo(other.spaceshipClass);

    //If they are already different by class we return the ordering value (no point in comparing also the number)
    if(spaceshipClassComparison != 0) {
        return spaceshipClassComparison;
    }
    
    //If the spaceships have the same class then we return the comparison between their registration number
    return this.registrationNo.compareTo(other.registrationNo);
}
Dan
  • 3,647
  • 5
  • 20
  • 26
  • hey, thanks for your amazing explanation . What i didn't know about compareTo methode before reading the documentation, was it's concept of x.compareTo(y). let's say we have to String variables with value of "1234" and "5678" how do they compare together? – Vanillo.schnitzel May 08 '22 at 12:44
  • @Vanillo.schnitzel they perform an alphabetical comparison which means that they both start from their respective first character, compare it and if it's equal keep moving to the next character until they don't match of one or both strings end. This means that the first string starts from the character '1' while the second string from the character '5'. The method sees that 1 is lower than 5 (as the first string is invoking the method, string1.compareTo(string2), I'm assuming) and then a negative int is returned, since string1 is lower than string2. – Dan May 08 '22 at 12:46
0

In cases when we compare obvious things like numbers, we don't need a custom compareTo method. So for example, if we want to know if 2 is greater than 1 we just use the appropriate operator: 2 > 1

However when we're dealing with things that aren't obviously comparable, like objects and spaceships (in your example), we need to explain to the compiler what criterion is used to say that one spaceship is "bigger" than another.

This is where writing a custom (@Override) compareTo method comes in. By default the compareTo method returns either 1, 0 or -1. There is no inherent meaning to these numbers, in fact they can be any numbers you like (as long as they are different). Their purpose is to match three cases when two things are compared:

  • thing 1 is greater than thing 2
  • thing 1 is equal to thing 2
  • thing 1 is less than thing 2

The compareTo method in your example specifies that when we compare two spaceships we are going to use the string value of their spaceshipClass. Furthermore, the compareTo method in your example uses the default implementation of comparing strings: This means that the strings are compared lexicographically (you can think of it as alphabetical).

Andrew
  • 80
  • 7