Java Comparable

Java Comparable

When it comes to programming in virtually any language, a common requirement is to sort and manipulate data. For example we might have a list of player ranks in a game server.

 

Often times you will want to rank these players from the highest score (lets say 100%) to the lowest score (0%) in order to provide statistics on which players are performing the best. This would add a competitive advantage to your server! An example could be a racing game where points are given for the number of races won based on 1st, 2nd, or 3rd place. The values are compared against each other, to determine the range of different scores and display it back to the users.

 

In Java we have the following operators used to compare number values.

 

  • Greater than: > (5 > 4)
  • Less than: < (1 < 3)
  • Greater than or equal to: >= (5 >= 5)
  • Less than or equal to: <= (4 <= 4)
  • Equal to: == (2 == )

 

You can also sort values by lexicographical order, otherwise known as alphabetic order. In this case a < b when referring to which letter comes first in the alphabet.

 

There can also be sorting by the length of a string in Java, such as “small” > “big”, in which the word small has fewer letters than big. There are endless ways of comparing strings, numbers, and all other data types. These are fundamental constructs of mathematics and programming in general.

 

In the Java programming language, these conditional operators allow for comparisons among different types of data. They check the condition of an expression such as 5 > 4 and if the result is true, it will return a boolean value of true or false. For instance, 4 > 5 would result in false. You could use a Arrays.sort() to automatically sort the scores of each player by their current rank. This is easy and straight forward, but what happens when you want to sort objects that represent each player? We could have a PlayerEntity class with a variable such as playerPoints and we need to rank each PlayerEntity object by number of points. We could easily compare and sort integers by value, but a method such as sort will only know how to compare the memory reference value of an object, not the variables contained within it.

 

The problem that we run into is how do we sort, arrange, or otherwise categorize all these same classes?

 

Lets start by providing sourcecode as example.

Here is an example of what a student class might look like:

package com.jasont.compare;

public class PlayerEntity {
    private String playerName;
    private int id;
    private double playerPoints;

    Student(String playerName, int id, double playerPoints) {
        this.playerName= playerName;
        this.id = id;
        this.playerPoints = playerPoints;
    }
    //Setter and getter methods below...
}

Once we have a class defined such as PlayerEntity, we can begin creating different instances of those players by instantiating the class. This is where we actually create an individual objects in memory from the PlayerEntity class.

Continuing with our player example, we will need an instance (one object) of a PlayerEntity class for every single player in the class. For example, we would have 30 PlayerEntity objects for a class of 30 players.

 

Now lets examine how to create multiple PlayerEntity objects within our main driver.

 

package com.jasont.compare;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class RacingGame {
    public static void main(String[] args) {
        List<PlayerEntity> playerList = new ArrayList<>();

        playerList.add(new PlayerEntity("topXRacer", 1, 56.30));
        playerList.add(new PlayerEntity("NiKo44", 3, 578.44));
        playerList.add(new PlayerEntity("Leeroy Jenkins", 2, 103.00));
        playerList.add(new PlayerEntity("anotherPlayer", 5, 255.20));
        playerList.add(new PlayerEntity("anotherPlayer2", 4, 23.37)); 
        System.out.println(playerList.toString().replaceAll("[,\\[\\]]","").replace(" N", "N")); 
    }
}

 

Output:

Player NameIDPlayer Score
topXRacer156.30
NiKo443578.44
Leeroy Jenkins2103.00
anotherPlayer5255.20
anotherPlayer2423.37

In our main driver program we declare and instantiate a new array list which holds our PlayerEntity objects. Then five players are added to the list, by creating a new PlayerEntity object constructor for each element of the array list. Finally the player list is displayed to the console.

 

Internally array lists have a toString() method that will automatically format the data inside of the list as a string for output. The replace and replaceAll methods are just added to remove commas, square brackets, and unneeded spaces which are added automatically by the array list. This will make the output look cleaner.

 

Now say you are a game developer and have a huge list of players and would like to list the players in order of their points.

 

How would you go about sorting these player objects?

 

The most commons way to sort a collection is through the Collections.sort() method, which would work great on wrapper data types or strings, but…

how will the sort method figure out how to sort an object containing multiple types of data?

 

The answer is… sort() doesn’t know, but we have a solution!

We can implement the Comparable interface.

 


Implementing Comparable

Comparable is a functional interface located within java.lang and only has one method to be overridden… called compareTo(). You may write the definition for this method to naturally order any object by the values of variables within.

 

Implementing this interface directly within your class allows you to do the following.

 

  1. Call Collections.sort() and Collections.binarySearch() upon a list of custom objects.
  2. Use Arrays.sort() and Arrays.binarySearch() on an array of custom objects.
  3. Adding objects as you key value inside of a TreeMap, which will automatically order your elements on insertion.
  4. Add objects inside of a TreeSet, which will sort your elements automatically.

 

The comparable interface is useful when we want meaningful way to have our objects ordered. There are only two changes you must make to your student class.

 

  1. Append implements Comparable<PlayerEntity> to the end of your student class.
  2. Override the “compareTo()” method contained inside Comparable.

 

Here is an example of comparable being implemented within the student class.

 

package com.jasont.compare;

public class Student implements Comparable<PlayerEntity> {
    private String playerName;
    private int id;
    private double playerPoints;

    PlayerEntity(String playerName, int id, double playerPoints) {
        this.playerName = playerName;
        this.id = id;
        this.playerPoints = playerPoints;
    }

    public int compareTo(PlayerEntity pEnt) {
        if(this.playerPoints < pEnt.getplayerPoints()) {
		return 1;
	} else if (this.playerPoints > pEnt.getplayerPoints()) {
		return -1;
	} else {
		return 0;
	}
    }
    //Setter and getter methods below...
}

How does compareTo work?

 

  1. compareTo() returns an integer type that can be positive 1, negative 1, and zero.
  2. If the current variable inside our object is smaller than the one we are comparing against, we return 1.
  3. If the current variable inside our object is larger than the one we are comparing against, return -1.
  4. Otherwise return 0 for an equal value.
  5. This gives a naturally descending list of values from largest to smallest. Exactly what we needed!

 

Now lets run our main driver with a statement to sort out collection!

 

 

package com.jasont.compare;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class RacingGame {
    public static void main(String[] args) {
        List<PlayerEntity> playerList = new ArrayList<>();

        playerList.add(new PlayerEntity("topXRacer", 1, 56.30));
        playerList.add(new PlayerEntity("NiKo44", 3, 578.44));
        playerList.add(new PlayerEntity("Leeroy Jenkins", 2, 103.00));
        playerList.add(new PlayerEntity("anotherPlayer", 5, 255.20));
        playerList.add(new PlayerEntity("anotherPlayer2", 4, 23.37)); 
        Collections.sort(playerList);
        System.out.println(playerList.toString().replaceAll("[,\\[\\]]","").replace(" N", "N")); 
    }
}

 

Output:

Player NameIDPlayer Score
NiKo443578.44
anotherPlayer5255.20
Leeroy Jenkins2103.00
topXRacer156.30
anotherPlayer2423.37

 

Now our PlayerEntity objects are sorted with the player’s having the most points coming first! This is great for displaying players by the amount of points they have, but…

What if you want to start giving statistics menus sorted for ID or by player name?

Posted in Programming.

Leave a Reply