지역변수의 범위를 최소화하라 - Effective Java[57]
🔗 지역변수의 범위를 줄이는 가장 강력한 기법은 ‘가장 처음 쓰일때 선언하기’다
-
사용하려면 멀었는데, 미리 선언부터 해두면 코드가 어수선해져 가독성이 떨어지다.
-
변수를 실제로 사용하는 시점엔 타입과 초깃값이 기억나지 않을 수도 있다.
-
지역변수를 생각 없이 선언하다 보면 쓰이는 범위보다 너무 앞서 선언하거나, 다 쓴 뒤에도 여전히 살아있게 되기 쉽다.
-
지역변수의 범위는 선언된 지점부터 그 지점을 포함한 블록이 끝날 때까지이므로, 실제 사용하는 블록 바깥에 선언된 변수는 그 블록이 끝난 뒤까지 살아 있게 된다.
-
그래서 실수로 의도한 범위 앞 혹은 뒤에서 그 변수를 사용하면 끔찍한 결과로 이어질 수 있다.
-
💎 거의 모든 지역변수는 선언과 동시에 초기화해야 한다.
-
초기화에 필요한 정보가 충분하지 않다면 충분해질 때까지 선언을 미뤄야 한다.
-
try-catch 문은 이 규칙에서 예외다.
-
변수를 초기화하는 표현식에서 검사 예외를 던질 가능성이 있다면 try 블록 안에서 초기화 해야 한다.
-
그렇지 않으면 예외가 블록을 넘어 메서드에까지 전파된다.
-
-
한편, 변수 값을 try 블록 바깥에서도 사용해야한다면 (비록 정확히 초기화하진 못하더라도) try 블록 앞에서 선언해야 한다.
💎 반복문은 독특한 방식으로 변수 범위를 최소화해준다.
-
예전의 for형태든 새로운 for-each 형태든, 반복문에서는 반복 변수의 범위가 반복문의 몸체, 그리고 for 키워드와 몸체 사이의 괄호 안으로 제한된다.
-
따라서 반복 변수의 값을 반복문이 종료된 뒤에도 써야 하는 상황이 아니라면 while 문보다는 for 문을 쓰는 편이 낫다.
- 아래는 컬렉션을 순회할 때 권장하는 관용구다.
💎 컬렉션이나 배열을 순회하는 권장 관용구
for (Element e : c) {
... //e로 무언가를 한다.
}
- 반복자를 사용해야 하는 상황이면(반복자의 remove 메서드를 써야 한다든가) for-each 문 대신 전통적인 for 문을 쓰는 것이 낫다.
💎 반복자가 필요할 때의 관용구
for (Iterator<Element> i = c.iterator(); i.hasNext(); ) {
Element e = i.next();
... // e와 i로 무언가를 한다.
}
💎 while 문 보다 for문이 나은 이유
- 다음의 두 while 문을 보면 앞서의 for 문이 더 나은 이유를 알 수 있다.
- 다음 코드에는 버그도 하나 숨어 있다.
Iterator<Element> i = c.iterator();
while (i.hasNext()) {
doSomething(i.next());
}
Iterator<Element> i2 = c2.iterator();
while (i.hasNext()) {
doSomethingElse(i2.next());
}
-
두 번째 while 문에는 복사해 붙여넣기 오류가 있다.
-
새로운 반복 변수 i2를 초기화했지만, 실수로 이전 while 문에서 쓴 i를 다시 쓴 것이다.
-
불행히도 i의 유효 범위는 아직 끝나지 않았으므로, 이 코드는 컴파일도 잘 되고 실행 시 예외도 던지지 않는다.
-
하지만 두 번째 while 문은 c2를 순회하지 않고 곧장 끝나 버려 c2가 비었다고 착각하게 만든다.
- 프로그램 오류가 겉으로 드러나지 않으니 오랜 기간 발견되지 않을 수도 있다.
-
💎 for-each**를 포함한 **for문을 사용하면 복사해 붙여넣기 오류를 컴파일 타임에 잡아준다.
-
첫 번째 반복문이 사용한 원소와 반복자의 유효 범위가 반복문 종료와 함께 끝나기 때문이다.
-
다음은 전통적인 for문에서의 상황을 보여준다.
for (Iterator<Element> i = c.iterator(); i.hasNext();) {
Element e = i.next();
... //e와 i로 무언가를 한다.
}
// 다음 코드는 "i를 찾을 수 없다"는 컴파일 오류를 낸다.
for (Iterator<Element> i2 = c2.iterator(); i.hasxNext();) {
Element e2 = i2.next();
.. //e와 i2로 무언가를 한다.
}
-
for 문이 복사해 붙여넣기 오류를 줄여주는 이유는 또 있다.
-
변수 유효 범위가 for 문 범위와 일치하여 똑같은 이름의 변수를 여러 반복문에서 써도 서로 아무런 영향을 주지 않는다.
- 사실 이렇게 쓰는 게 더 세련되기까지 하다.
-
-
한가지 더 다른 for문의 장점은 while 문 보다 짧아서 가독성이 좋다는 것이다.
- 다음은 지역변수의 범위를 최소화하는 또 다른 반복문 관용구다.
for (int i = 0, n = expensiveComputation(); i< n; i++) {
... // i로 무언가를 한다.
}
-
위 관용구에서 주목할 부분은 범위가 정확히 일치하는 두 반복 변수 i와 n이다.
-
반복 여부를 결정짓는 변수 i의 한곗값을 변수 n에 저장하여, 반복 때마다 다시 계산해야 하는 비용을 없앴다.
-
같은 값을 반환하는 메서드를 매번 호출한다면 이 관용구를 사용하기 바란다.
-
💎 메서드를 작게 유지하고 한 가지 기능에 집중하는 것이다.
- 지역 변수 범위를 최소화하는 마지막 방법은 한 메서드에서 여러 가지 기능을 처리한다면 그중 한 기능과만 관련된 지역변수라도 다른 기능을 수행하는 코드에서 접근할 수 있을 것이다.
- 해결책은 단순히 메서드를 기능별로 쪼개면 된다.
참조 - 이펙티브 자바 3/E - 조슈아 블로크때
Comments