Creating General Java Comparators in Scala

Posted on

I have been using Scala for Android development for awhile now. Furthermore, I have been using ArrayLists to hold collections of objects, which I need to occasionally sort. I started using a convenient Java Collections library which gives a nice method sort that takes a list as an argument and sorts it based on the comparator provided. At first everything was simple. I created a simple Comparator like the following.

class ObjectComparatorByTitle extends Comparator[Object] {
  def compare(p1: Object, p2: Object): Int = {
    ... your implementation
  }
}

I could use the comparator to sort the objects

val objectList: ArrayList[Object] = new ArrayList()
Collections.sort(objectList, new ObjectComparatorByTitle())

This was working very well so I made few others like ObjectComparatorByCreatedDate and ObjectComparatorByOwner. Then, in my project I had to add a similar type object that was similar to original. So, I created base object class and had both objects inherit from it. The problems began when I wanted to make general comparator that uses the base class.

Here is the situation

class Animal(val strength: Int, var hunger: Int)
class Dog(strength: Int, hunger:Int, val tail: Boolean, val name: String) extends Animal(strength, hunger)
class Cat(strength: Int, hunger:Int, val name: String) extends Animal(strength, hunger)

class AnimalComparatorByStrength extends Comparator[Animal] {
  def compare(p1: Animal, p2: Animal): Int = {
    //... your implementation
  }
}

The problem is that if you do the following, you will get an error even though both Dog class and Cat class is sub-class of Animal.

val catList: ArrayList[Cat] = new ArrayList()
Collections.sort(catList, new AnimalComparatorByStrength())

val dogList: ArrayList[Dog] = new ArrayList()
Collections.sort(dogList, new AnimalComparatorByStrength())

I was confused and it took me couple hours to figure out how to go about this. The solution is quite simple, yet elegant. First you have to slightly change the comparator method.

Here is the updated version.

class AnimalComparatorByStrength[A <: Animal] extends Comparator[A] {
  def compare(p1: A, p2: A): Int = {
    //... your implementation
  }
}

As you can see not much changed, but I added a wildcard which allows to insert sub-classes of Animal. Furthermore, there is one more change when using this method. When creating the Comparator you have to specify the type.

Collections.sort(catList, new AnimalComparatorByStrength[Cat]())
Collections.sort(dogList, new AnimalComparatorByStrength[Dog]())

As you can see the change was quite subtle, but it allows you to make more generic comparators. This can save a lot of repetition in the long term. I hope that this snippet helps you in your coding quest. By the way, let me know if you have any questions or any suggestions. Thanks!

Tags: , , , ,


Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>