JAVA

[이펙티브 자바] 아이템 57

수염차 2025. 5. 6. 20:59

## 지역번수의 범위를 최소화하라

 

### 지역변수의 유효 범위를 최소로 줄이면 코드 가독성과 유지보수성이 높아지고 오류 가능성은 낮아진다.

 

### 지역변수의 범위를 줄이는 기법

- 가장 처음 쓰일 때 선언하기

: 미리 선언부터 해두면 코드가 어수선해져 가독성이 떨어짐. 변수를 실제로 사용하는 시점엔 타입과 초깃값이 기억나지 않을 수도 있다.

: 변수가 쓰이는 범위보다 너무 앞서 선언하거나,다 쓴 뒤에도 여전히 살아 있게 되기 쉽다. 그래서 실수로 의도한 범위 앞 혹은 뒤에서 그 변수를 사용하면 끔찍한 결과로 이어질 수 있다.

 

- 거의 모든 지역변수는 선언과 동시에 초기화해야 한다.

: 초기화에 필요한 정보가 충분하지 않다면 충분해질 때까지 선언을 미뤄야 한다.

: 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에 저장하여, 반복 때마다 다시 계산해야 하는 비용을 없앴다. 

 

### 메서드를 작게 유지하고 한 가지 기능에 집중

한 메서드에서 여러 가지 기능을 처리한다면 그중 한 기능과만 관련된 지 역변수라도 다른 기능을 수행하는 코드에서 접근할 수 있을 것이다. 

해결책은 단순히 메서드를 기능별로 쪼개면 된다.