Превращаем Java Enums в Groovy Ranges

Рубрика: Groovy, Java | 7 April 2008, 15:09 | Vadim Voituk

Идея заметки не моя, но очень мне понравилась.
Оригинал тут: Turning Java enums into Groovy ranges

Предположим что у нас есть простой Java Enum:
[java]

public enum Season {
  WINTER, SPRING, SUMMER, FALL
}

[/java]

Так как enum-ы реализуют интерфейс Comparable, то в них есть метод compareTo().
Тем не менее их значения нельзя использовать с операторами < и >.
Потому такой Java-код даже не скомпилируется
[java]if (Season.WINTER > Season.FALL) { … }[/java]

Напротив, в Groovy же, для любого класса, который реализует Comparable можно использовать операторы < и >. Потому такой Groovy-код, работает как и ожидается:
[java]assert Season.FALL > Season.WINTER[/java]

Так как enum уже реализует Comparable, то для того, чтоб превратить его в Groovy Range, осталось добавить только методы next() и previous().
Вот один из способов сделать это, используя метод ordinal() enum-а:

[java]

public enum Season {
    WINTER, SPRING, SUMMER, FALL;

    Season next() {
        Season[] vals = Season.values();
        return vals[(this.ordinal() + 1) % vals.length];
    }

    Season previous() {
        Season[] vals = Season.values();
        return vals[(this.ordinal() - 1 + vals.length) % vals.length];
    }
}

[/java]

Теперь в Groovy можно написать так:
[java]

(Season.WINTER..Season.FALL).each {
    println it
}
// ...
for (s in Season.values()) {
    println (s++)
}
// ...
for (s in Season.values()) {
    println (s--)
}

[/java]

Налицо использование, принятой в Groovy, концепции Duck Typing, когда нас не обязуют декларировать реализацию интерфейся для использования с языковыми операторами (в данном случае “больше-меньше”). Достаточно только реализовать необходимые методы, без указания какого-либо дополнительного implements в сигнатуре класса.

Кстати в Java есть метод EnumSet.range(), который возвращает коллекцию значений enum-а, которая в свою очередь может быть использована в Java5 for-each цикле:
[java]for (Season s : EnumSet.range(Season.WINTER, Season.FALL) { … }[/java]
Но в в таком случае использование операторов < и > все равно не допускается.

Оставьте комментарий!

Leave a Reply