Sunday, May 4, 2008

Beautiful enums

Whatever complaints you may have against java, I think you have to grant that at least enums are a thing of beauty. Consider this code line:

Collections.sort(myChildren, Child.Order.ByAge.descending());

The best part is that this started to appear as a side effect of another rational structuring of code, creating a synergy effect of two positive drives together. This kind of synergy always appeals to my aesthetic sense. Here's the Child class:

public final class Child {
private final Integer age;
private final String name;
...
public static enum Order implements Comparator {
ByAge() {
public int compare(Child lhs, Child rhs) {
return lhs.age.compareTo(rhs.age);
}
},
ByName() {
public int compare(Child lhs, Child rhs) {
// TODO: Should really use a collator.
return lhs.name.compareTo(rhs.name);
}
};

public abstract int compare(Child lhs, Child rhs);

public Comparator ascending() {
return this;
}

public Comparator descending() {
return Collections.reverseOrder(this);
}
}
}

Lovely! Other examples of the synergy effect I've seen recently are my earlier posted thread safe state pattern and this blog entry. In both those cases the synergy was better code structure and better performance.

7 comments:

Daniel said...

The only odd thing about it that strikes me is the use of PascalCase in the enum variable names, rather than the conventional all-caps. Other than that, quite nice!

Casper Bang said...

Completely agree. Easily my favorite part of Java 5 - funny it should take 10 years and a lot of pattern workarounds to get this into the language.

@Daniel: What do you mean? We user all upper case for our enums at work (since they are basically a group of constants), also, Sun examples seem to follow an all cap standard:
http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

paulk said...

Very nice. If we had closures we might even have nicer mechanisms. This is Groovy but you will get the idea:

class Child {
  def age, name
  static ByAge = { lhs, rhs ->
    lhs.age <=> rhs.age }
  static ByName = { lhs, rhs ->
    lhs.name <=> rhs.name }
  String toString() {
    "Child: $name of age $age"
  }
}

def myChildren = [
  new Child(name:'foo', age:3),
  new Child(name:'bar', age:5)
]
println myChildren.sort(Child.ByAge).reverse()
// => [Child: bar of age 5, Child: foo of age 3]

pimeja said...

Thank you that you exposed very nice idiom. It looks really useful, straightforward for a people who reads such code. You did a good job.

I can only add that if it's java 5 than Comparator should be parametrized. And also seems that declaration of abstract method in a Order enum is unnecessary.

Krishna Kumar J said...

I have list of Order objects and these order objects needs to be sorted.

Scenario:
===========
An order has 3 orderlines and these orderlines should be sorted based orderLineSeq in ascending order.

class Sample{
private Integer orderId;
private Integer orderLineId;
private Integer orderLineSeq;
}

End Result should be like the foll:
-----------------------------------

orderId orderLineId orderLineSeq
O001 OL01 1
O001 OL02 2
O001 OL03 3
----------------------------------
O002 OL11 1
O002 OL12 2
O002 OL13 3
----------------------------------
O003 OL31 1
O003 OL32 2
O003 OL33 3
----------------------------------

How to achieve this using compartor?

Thanks in advance.

ankitkinra said...

@Krishna Kumar J
Try using org.apache.commons.collections.comparators.ComparatorChain

Kvic Kaizen said...

Thanks a lots.