[Groovy] Spaceship operator (<=>)

by 스뎅(thDeng) on

Spaceship operator

Groovy에는 우주선 연산자(spaceship operator)가 있다. <=> 생긴게 우주선 같아서 그런 이름을 붙였는지 모르겠지만, 이걸 처음 본 순간 무슨 일을 하는 녀석인지 도저히 감이 안 오는 처음 보는 녀석 T_T ruby, php 등에서는 많이 지원되는 연산자인 것 같다.

이 spaceship operator는 compareTo를 호출(delegate)해 준다.

assert (1 <=> 1) == 0
assert (1 <=> 2) == -1
assert (2 <=> 1) == 1
assert ('a' <=> 'z') == -1

연산자 왼쪽에 있는 녀석의 compareTo를 delegate 해주는 녀석이기 때문에 좌항의 compareTo가 호출되는 형태이다. 따라서 좌항의 compareTo 파라미터로 우항의 클래스 타입이 없다면 예외가 발생한다.

1 <=> "ABC" // java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
1 <=> 1.2 // -1. 오호

(Integer) 1과 (String) “ABC”의 비교는 “ABC”를 Integer(Number)로 캐스팅할 수 없기 때문에 예외가 발생한다. 하지만 신기하게도 Integer#compareTo(Double) 메소드는 없는데도 예외가 발생하지 않고 잘 동작한다. 그건 groovy가 숫자 비교를 편하게 해주는 compareTo를 많이 지원해 주기 때문이다. (org.codehaus.groovy.runtime.DefaultGroovyMethods#compareTo(java.lang.Number, java.lang.Number))

Compare with null

참 착하게도 null을 비교할 때는 NullPointerException이 발생하지 않게 해주어서 고맙다.

assert ("ABCD" <=> null) == 1
assert (null <=> "ABCD") == -1
assert (null <=> null) == 0

Sort

이 연산자를 어디에 많이 쓰는고 하면..

def arr = [1, 7, 5, 3, 8, 2, 9, 6]
Comparator ascComparator = { a, b -> a <=> b }
Collections.sort(arr, ascComparator)
assert arr == [1, 2, 3, 5, 6, 7, 8, 9]

// 귀찮은 null check가 없어도 문제 없다. (null first)
def arr = [1, 7, null, -2, 9]
Comparator ascComparator = { a, b -> a <=> b }
Collections.sort(arr, ascComparator)
assert arr == [null, -2, 1, 7, 9]

참고

별도로 명시하지 않을 경우, 이 블로그의 포스트는 다음 라이선스에 따라 사용할 수 있습니다: Creative Commons License CC Attribution-NonCommercial-ShareAlike 4.0 International License