2007년 09월 13일
최적화인가? 삼항 연산자와 if - else 구문
checkstyle(자바 소스의 코딩 스타일을 분석하여 문제점을 보고하는 도구)로 프로젝트의 소스 코드를 검사하던 중 AvoidInlineConditionals 규칙이 문제가 되었다. AvoidInlineConditionals 규칙란 삼항 연산자(? :)를 사용하여 작성한 구문을 배제하는 checkstyle의 규칙을 말한다. 문서에는 삼항 연산자를 사용하는 구문을 읽기 어려워 하는 사람이 있기 때문에 이를 코딩 표준에서 금지하는 경우도 있다고 설명하고 있다. 우리 팀에는 초보 프로그래머가 많기 때문에 이 규칙을 적용하는 게 좋을 듯 했다. 그러자 팀원 중 한 명이 이의를 제기했다.
삼항 연산자 구문이 if - else 구문보다 효율적으로 동작한다는 게 그 이유였다. 그 팀원이 예전에 프로젝트 진행 중 장애 진단을 받을 때 그런 말을 들었다고 한다. 삼항 연산자가 if - else 구문보다 효율적으로 동작하니 가능한 구문은 모두 바꾸라고 해서 일일이 소스를 뒤져 바꿨다고 한다. JVM 바이트코드에는 삼항 연산자에 해당하는 명령어가 따로 존재하지 않으므로 삼항 연산자 구문은 if - else 구문과 똑같이 번역될 꺼라 생각했지만 그 '컨설턴트'의 말을 함부로 무시할 수는 없었다.
그래서 같은 내용의 if - else 구문과 삼항 연산자 구문이 각기 어떻게 바이트코드로 컴파일되었는지 살펴 보기로 했다. 바이트코드는 Object Web의 Bytecode Outline plugin for Eclipse로 보았다. 먼저 소스 코드는 다음과 같다.
위 코드를 컴파일한 결과를 보면 다음과 같다. 디버그 정보는 모두 삭제하고 레이블도 읽기 쉽게 일부 삭제하고 이름도 바꿨다.
if-else 구문의 경우 지역 변수에 저장하는 명령어(istore 2)가 중복되어 있을 뿐 삼항 연산자 구문의 코드와 거의 같다. 그리고 실제 조건 별로 실행되는 명령을 추적해 보면 실행되는 명령어 수는 같다. 즉 if - else 구문 대신에 삼항 연산자 구문을 쓴다고 해서 성능상 잇점이 있다고 할 수 없는 것이다. 기껏해야 클래스 파일이 조금 작아지는 정도인데 그 정도야 충분히 무시할 수 있는 꺼라 본다. 디버그 정보를 넣어서 컴파일한 것을 그대로 돌리는 경우도 있는 것을 감안하면 별로 작아지는 것도 아니다.
그런데도 그 컨설턴트는 왜 그런 말을 해서 많은 이를 노가다시켰을까? 삼항 연산자를 써서 코드 줄 수를 줄이면 더 최적화된 건가? 눈에 보이는 것만이 다는 아닌데 말이다.
삼항 연산자 구문이 if - else 구문보다 효율적으로 동작한다는 게 그 이유였다. 그 팀원이 예전에 프로젝트 진행 중 장애 진단을 받을 때 그런 말을 들었다고 한다. 삼항 연산자가 if - else 구문보다 효율적으로 동작하니 가능한 구문은 모두 바꾸라고 해서 일일이 소스를 뒤져 바꿨다고 한다. JVM 바이트코드에는 삼항 연산자에 해당하는 명령어가 따로 존재하지 않으므로 삼항 연산자 구문은 if - else 구문과 똑같이 번역될 꺼라 생각했지만 그 '컨설턴트'의 말을 함부로 무시할 수는 없었다.
그래서 같은 내용의 if - else 구문과 삼항 연산자 구문이 각기 어떻게 바이트코드로 컴파일되었는지 살펴 보기로 했다. 바이트코드는 Object Web의 Bytecode Outline plugin for Eclipse로 보았다. 먼저 소스 코드는 다음과 같다.
public int ifclause(String str) {
int ret;
if (null == str) {
ret = 0;
} else {
ret = str.length();
}
return ret;
}
public int inlineconditional(String str) {
int ret = null == str ? 0 : str.length();
return ret;
}
위 코드를 컴파일한 결과를 보면 다음과 같다. 디버그 정보는 모두 삭제하고 레이블도 읽기 쉽게 일부 삭제하고 이름도 바꿨다.
public ifclause(Ljava/lang/String;)I
ALOAD 1
IFNONNULL FIRST
ICONST_0
ISTORE 2
GOTO END
FIRST:
ALOAD 1
INVOKEVIRTUAL java/lang/String.length()I
ISTORE 2
END:
ILOAD 2
IRETURN
public inlineconditional(Ljava/lang/String;)I
ALOAD 1
IFNONNULL FIRST
ICONST_0
GOTO END
FIRST:
ALOAD 1
INVOKEVIRTUAL java/lang/String.length()I
END:
ISTORE 2
ILOAD 2
IRETURN
if-else 구문의 경우 지역 변수에 저장하는 명령어(istore 2)가 중복되어 있을 뿐 삼항 연산자 구문의 코드와 거의 같다. 그리고 실제 조건 별로 실행되는 명령을 추적해 보면 실행되는 명령어 수는 같다. 즉 if - else 구문 대신에 삼항 연산자 구문을 쓴다고 해서 성능상 잇점이 있다고 할 수 없는 것이다. 기껏해야 클래스 파일이 조금 작아지는 정도인데 그 정도야 충분히 무시할 수 있는 꺼라 본다. 디버그 정보를 넣어서 컴파일한 것을 그대로 돌리는 경우도 있는 것을 감안하면 별로 작아지는 것도 아니다.
그런데도 그 컨설턴트는 왜 그런 말을 해서 많은 이를 노가다시켰을까? 삼항 연산자를 써서 코드 줄 수를 줄이면 더 최적화된 건가? 눈에 보이는 것만이 다는 아닌데 말이다.
# by | 2007/09/13 15:08 | 트랙백 | 덧글(1)





















☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
다만, 예제와 같은 단일 삼항 연산자라면 if 보다는 가독성이 더 좋은것 같습니다.
AvoidInlineConditionals 룰이 이런 것도 구분할 수 있으면 좋을 것 같네요..