티스토리 뷰
Item69에서 예외는 진짜 예외 상황에서만 사용하라 말한다.
너무나 당연한 얘기를 왜 한 장에 할당해 설명했을까?
바로 다음과 같은 해괴한 방식으로 작성하는 녀석들이 있기 때문이다
try {
int i = 0 ;
while (true) {
System.out.println(array[i++]);
}
} catch (ArrayIndexOutOfBoundsException e) {
// doSomething...
}
위 코드의 의도는 array로 선언한 배열의 인덱스를 하나씩 늘려가며 출력하는 것인데
배열의 마지막 요소까지 출력하기 위해 범위를 넘어갈 때 (즉 ArrayIndexOutOfBoundsException이 발생할 때)
catch 블록에서 잡아서 별도의 처리를 하거나 하지 않거나 하는 방식으로 작성한 것이다
for-each loop, for-loop으로 작성하면 아주 간단한데 원래의 의도와 벗어나게 예외를 활용해 흐름을 제어하는 방식이다
올바른 방법을 벗어났기에 나는 사파의 방법이라 부른다
사파의 방식을 쓸 것이라면 정파의 방식보다 나은 게 있어야 쓸까 말까 고민이라도 할 텐데
아래 3가지의 이유로 속도도 느리고 이해할 수 없는 코드가 탄생한다
1. 예외 자체가 다양한 상황에서 사용될 것을 산정하고 만들어진게 아님
2. try-catch block 안에서는 최적화 여지가 줄어듬
3. 많은 JVM 구현체들이 이미 인덱스 마지막 값 처리를 최적화해둠
위 코드 블록에서 한술 더 뜨는 위험은 i로 선언한 인덱스를 직접 다룰 때 발생한다
아래처럼 돌려버리면 i는 놀랍게 50도 아니고 51이 나온다
int array = new int[50];
int i = 0 ;
try {
while (true) {
System.out.println(array[i++]);
}
} catch (ArrayIndexOutOfBoundsException e) {
log.info("i = {}", i);
}
인덱스에 대해서는 거의 다 알겠지만 한번 더 짚고 넘어가자, 인덱스는 0부터 시작하니 마지막 인덱스는 49가 된다
i++로 후위 증감 연산을 때려버리니 정상 접근 가능한 마지막 인덱스 49에서부터 살펴보면 된다
i = 49일 때 i++은 50이다, 다시 while 반복 안에서 출력하려 하니 i = 50인 상황이고
ArrayIndexOutOfBoundsException이 터지지만 i++은 이미 처리된 상황이다
이에 관련된 보안 취약점 글이 있었는데 까먹었다, 나중에 찾으면 첨부해야겠다
그 글의 요지는 예외가 터지더라도 메모리 상에서 이미 연산이 수행된 데이터를 조작하는 것이었다
즉, 예외 터트리면 끝이 아니라 그 뒤에 변수에 할당된 값을 이전 값으로 돌려놓거나 or 메모리에서 날려버리는 과정이 필요하다
애초에 for-loop, for-each loop은 사용자에게 인덱스 조작을 허용하지 않기에 고민하지 않아도 되는 문제다
다만 이런 문제들에도 불구하고 한 가지 생각해 볼만한 점은 있는 것 같다
무지성 개발만 한다면 for-each 쓰면 되지 하고 끝낼 수 있는데
애플리케이션에서 요구되는 상황을 boundary register의 경계 값 확인으로도 해결할 수 있구나 하는 인사이트를 얻을 수 있다
문제를 푸는 다양한 방법이 있다지만 산업 스파이가 아니라면 예외 기반 반복은 생각지도 말자
특히나 여러 사람이 협업하는 경우에는 더더욱. 정도의 길을 걷고 자바의 도를 깨우치러 가보자
'Java > Effective Java' 카테고리의 다른 글
[Item71] Checked Exception 즐겨보기 (0) | 2023.01.30 |
---|---|
[Item70] Checked Exception 금지 (0) | 2022.11.01 |
[Item68] 컨벤션 따르기 (1) | 2022.09.11 |
[Item67] 최적화는 나중에 (0) | 2022.08.28 |
[Item66] 자바 네이티브 인터페이스 (0) | 2022.08.03 |