[이펙티브 자바] 아이템 57
## 지역번수의 범위를 최소화하라
### 지역변수의 유효 범위를 최소로 줄이면 코드 가독성과 유지보수성이 높아지고 오류 가능성은 낮아진다.
### 지역변수의 범위를 줄이는 기법
- 가장 처음 쓰일 때 선언하기
: 미리 선언부터 해두면 코드가 어수선해져 가독성이 떨어짐. 변수를 실제로 사용하는 시점엔 타입과 초깃값이 기억나지 않을 수도 있다.
: 변수가 쓰이는 범위보다 너무 앞서 선언하거나,다 쓴 뒤에도 여전히 살아 있게 되기 쉽다. 그래서 실수로 의도한 범위 앞 혹은 뒤에서 그 변수를 사용하면 끔찍한 결과로 이어질 수 있다.
- 거의 모든 지역변수는 선언과 동시에 초기화해야 한다.
: 초기화에 필요한 정보가 충분하지 않다면 충분해질 때까지 선언을 미뤄야 한다.
: try-catch 문은 이 규칙에서 예외다. 변수 초기화 표현식에서 검사 예외를 던질 가능성이 있다면 try 블록 안에서 초기화해야한다. 변수 값을 try 블록 바깥에서도 사용해야한다면 try 블록 앞에서 선언해야 한다.
Constructor<? extends Set<String>> cons = null;
try {
cons = cl.getDeclaredConstructor();
} catch (NoSuchMethodException e) {
fatalError("매개변수 없는 생성자를 찾을 수 없습니다.");
}
### 반복문 (while문 대신 for문 사용하기)
- 반복문에서는 반복 변수의 범위가 반복문의 몸체, 그리고 for 키워드와 몸체 사이의 괄호 안으로 제한됨.
따라서 반복변수의 값을 반복문이 종료된 뒤에도 써야 하는 상황이 아니라면 while문보다 for문을 쓰는 편이 낫다.
- 컬렉션이나 배열을 순회하는 권장 관용구
for (Element e : c) {
... // e로 무언가를 한다.
}
반복자가 필요할 때의 관용구
- 반복자를 사용해야 하는 상황이면 for-each문 대신 전통적인 for문을 쓰는 것이 낫다
for (Iterator<Element> i = c.iterator(); i.hasNext();) {
Element e = i.next();
... // e와 i로 무언가를 한다.
}
- 원소와 반복자의 유효 범위가 반복문 종료와 함께 끝난다
- 똑같은 이름의 변수를 여러 반복문에서 반복해서 사용할 수 있다
- while문보다 짧아서 가독성이 좋다
while문 버그
반복자로 while
을 쓰면 아래와 같은 실수를 만들 수 있다.
Iterator<Element> i = c.iterator();
while(i.hasNext()) {
doSomething(i.next());
}
// ...
Iterator<Element> i2 = c2.iterator();
while(i.hasNext()) { // 버그
doSomethingElse(i2.next());
}
- 실수로 새로 초기화한
i2
를 사용하지 않고 그냥i
를 써버렸다.
반복자로 for
을 쓰면 위와 같은 실수를 할 일이 없다.
for (Iterator<Element> i = c.iterator(); i.hasNext(); ) {
Element e = i.next();
// e와 i로 무언가 한다...
}
for (Iterator<Element> i2 = c2.iterator(); i.hasNext(); ) {
Element e2 = i2.next();
// e와 i로 무언가 한다...
}
- 아래의
for
문에서 에러가 뜰 것이다.- 위쪽
for
문의i
는 스코프가 만료되어 더이상 존재하지 않기 때문이다.
- 위쪽
같은 값을 반환하는 메서드를 매번 호출할때 사용할 수 있는 관용구
for (int i = 0, n = expensiveComputation(); i < n; i++) {
... // i로 무언가를 한다.
}
- 반복 여부를 결정짓는 변수 i의 한곗값을 변수 n에 저장하여, 반복 때마다 다시 계산해야 하는 비용을 없앴다.
### 메서드를 작게 유지하고 한 가지 기능에 집중
한 메서드에서 여러 가지 기능을 처리한다면 그중 한 기능과만 관련된 지 역변수라도 다른 기능을 수행하는 코드에서 접근할 수 있을 것이다.
해결책은 단순히 메서드를 기능별로 쪼개면 된다.