티스토리 뷰
이번 아이템은 기본적으로 "클래스와 멤버의 접근 권한을 최소화하라"고 한 아이템 15와 취지가 비슷합니다.
지역변수의 유효 범위를 최소로 줄이면 코드 가독성과 유지보수성이 높아지고 오류 가능성은 낮아집니다.
C와 같이 역사가 깊은 프로그래밍 언어 중에는 지역변수를 코드 블록의 첫머리에 선언하는 경우가 많고, 이 방식을 여전히 습관처럼 따르는 프로그래머도 있습니다.
하지만 자바에서는 문장을 선언할 수 있는 곳이면 어디서든 변수를 선언할 수 있습니다.
지역변수의 범위를 줄이는 가장 강력한 기법은 '가장 처음 쓰일 때 선언하기'입니다.
사용하려면 멀었는데, 미리 선언부터 해두면 코드가 어수선해져 가독성이 떨어집니다.
변수를 실제로 사용하는 시점엔 타입과 초깃값이 기억나지 않을 수도 있습니다.
지역변수를 생각없이 선언하다 보면 변수가 쓰이는 범위보다 너무 앞서 선언하거나, 다 쓴 뒤에도 여전히 살아 있게 되기 쉽습니다.
지역변수의 범위는 선언된 지점부터 그 지점을 포함한 블록이 끝날 때까지이므로, 실제 사용하는 블록 바깥에 선언된 변수는 그 블록이 끝난 뒤까지 살아 있게 됩니다.
그래서 실수로 의도한 범위 앞 혹은 뒤에서 그 변수를 사용하면 끔찍한 결과로 이어질 수 있습니다.
또한 거의 모든 지역변수는 선언과 동시에 초기화해야 합니다.
초기화에 필요한 정보가 충분하지 않다면 충분해질 때까지 선언을 미뤄야 합니다.
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로 작업을 진행
}
다음의 두 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();
}
// 다음 코드는 "i를 찾을 수 없다"는 컴파일 오류를 낸다.
for (Iterator<Element> i2 = c2.iterator(); i.hasNext(); ) {
Element e2 = i2.next();
}
for 문이 복사해 붙여넣기 오류를 줄여주는 이유는 또 있습니다.
변수 유효 범위가 for 문 범위와 일치하여 똑같은 이름의 변수를 여러 반복문에서 써도 서로 아무런 영향을 주지 않습니다.
마지막으로 for문이 while문보다 짧아서 가독성이 좋다는 장점도 있습니다.
다음은 지역변수의 범위를 최소화하는 또 다른 반복문 관용구입니다.
for (int i = 0, n = expensiveComputation(); i < n; i++) {
// i로 작업
}
이 관용구에서 주목할 부분은 범위가 정확히 일치하는 두 변수 i와 n입니다.
반복 여부를 결정짓는 변수 i의 한계값을 변수 n에 저장하여, 반복 때마다 다시 계산해야 하는 비용을 없앴습니다.
같은 값을 반환하는 메서드를 매번 호출한다면 이 관용구를 사용하면 좋습니다.
지역변수 범위를 최소화하는 마지막 방법은 메서드를 작게 유지하고 한 가지 기능에 집중하는 것입니다.
한 메서드에서 여러 가지 기능을 처리한다면 그중 한 기능과만 관련된 지역변수라도 다른 기능을 수행하는 코드에서 접근할 수 있을 것입니다.
'JAVA > 이펙티브 자바' 카테고리의 다른 글
아이템[59]. 라이브러리를 익히고 사용하라 (0) | 2022.05.08 |
---|---|
아이템[58]. 전통적인 for 문보다는 for-each 문을 사용하라 (0) | 2022.05.08 |
아이템[56]. 공개된 API 요소에는 항상 문서화 주석을 작성하라 (0) | 2022.05.07 |
아이템[55]. 옵셔널 반환은 신중히 하라 (0) | 2022.05.07 |
아이템[54]. null이 아닌, 빈 컬렉션이나 배열을 반환하라 (0) | 2022.05.07 |
- Total
- Today
- Yesterday
- 백준
- kkoon9
- BOJ
- 테라폼
- 코테
- kotest
- 클린 코드
- Kotlin
- 프로그래머스
- Spring
- Olympiad
- 클린 아키텍처
- MSA
- AWS
- BAEKJOON
- 객체지향
- JPA
- 디자인패턴
- programmers
- 정규표현식
- 디자인 패턴
- Effective Java
- 이펙티브 자바
- Spring Boot
- Java
- 알고리즘
- C++
- node.js
- 이팩티브 자바
- Algorithm
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |