본문 바로가기
☕️ JAVA/🦋 Effective Java

지역 변수의 범위를 줄여 쉬운 코드 작성하기 (feat. while 보다는 for)

by kukim 2022. 1. 18.

이 글은 책 이펙티브 자바 3판 Item57을 참고했습니다. 잘못된 내용이 있다면 편하게 말씀해주세요 🙏🏻

 

주제

일반 프로그래밍 원칙

 

결론

지역 변수가 많거나 범위가 넓으면 오류 발생이 크다.

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


지역 변수의 범위와 오류를 줄이는 방법 5가지를 알아보자

✅ 1. 가장 처음 쓰일 때 선언하기

C언어 개발자들은 지역 변수를 코드 블록 첫머리에 선언하는 경우가 많았다. 하지만 코드가 길어지면 정작 사용할 때 이해가 어렵다.

자바에서는 어디서든 선언 가능하니 사용하기 직전에 선언하자

public class Car {
	public static void main(String[] args) {
		String name = "BMW"
		// ...
		
		// 중간 코드 50줄

		// ...
		// name이 뭐였지?
        
		String type = "auto"; // 단편적인 예
		if (type.equals("auto") {
        }
	}
}

✅ 2. 모든 지역변수는 선언과 동시에 초기화하기

선언과 동시에 초기화하지 않고 사용하면 default 초기값이 들어가 로직에 문제가 생길 수 있거나, 중간에 재할당하면 맥락 파악이 어렵다.

public class Car {
	public static void main(String[] args) {
		String name; // 초기화 선언 X

		// ...
		
		if (name.equals("SONATA") {  
		// 선언과 동시에 초기화 하지 않으면 초기화를 까먹어 문제가 될 수 있다.
		}

	}
}

단, 예외가 있다면 try-catch 문에서 변수 초기화 과정에서 Exception 가능성이 있다면 try 블록 안에서 초기화하는 경우를 제외

public class Car {
	public static void main(String[] args) {
	  
		int power;
		try {
			power = Engin.getPower(); //  Engin.getPower() 메서드 자체가 Exception 가능성이 있는 경우
		} catch (IOException e) {
			throw new RunTimeException();
		}
	}
}

✅ 3. while 대신 for 사용하기

for의 장점

- while문 작성시 오류를 방지할 수 있다.

// while문 - 오류 발생 가능성 Up
public class Name {
  public static void main(String[] args) {

    List<String> lastName = Arrays.asList("김", "이", "박");
    Iterator<String> i = like.iterator();
    while(i.hasNext()) {
      System.out.print(i.next());
    }

    List<String> fisrtName = Arrays.asList("구","지은", "명수");
    Iterator<String> i2 = hate.iterator();
    while(i.hasNext()) { // i2.hasNext()가 아닌 i.hasNext()로 실수! (컴파일, 런타임 에러 체크 X)
      System.out.println(i2.next());
    }
  }
}
// for의 장점 : 로컬 변수, 컴파일 오류로 체크 가능
public class Name {
  public static void main(String[] args) {

	List<String> lastName = Arrays.asList("김", "이", "박");    
	for (Iterator<String> i = like.iterator(); i.hasNext();) {
		System.out.print(i.next());
    	} // for문 종료 후 i는 for문에 대한 지역변수로 사라짐


	// 아래 for에서는 i.hasNext() 접근이 불가하여 컴파일에서 체크 O
	List<String> fisrtName = Arrays.asList("구","지은", "명수");
	for (Iterator<String> i2 = hate.iterator(); i.hasNext();) {
		System.out.print(i2.next());
    }
  }
}

- 코드가 짧다. 

// for
for (int i = 0, n = average(nums); i < n; i++) {

}

// while
int i = 0;
int n = average(nums);
while (i < n) {

}

위 코드에서 for가 while 보다 짧아 가독성이 좋은 것을 볼 수 있다.

*tip) average(nums)에 대한 계산 결과를 미리 n = average(nums)으로 선언해주었다. for (int i = 0, n = average(nums); i < n; i++) 만약 이를 for (int i = 0, ; i < average(nums); i++)으로 해주었다면 매번 반복할 때마다 average() 연산을 하기 때문에 성능이 안 좋다. 따라서 for문에 대한 조건문 결과는 for 문 첫 번째 에서 계산하는 것이 좋다.

 

✅ 4. 컬렉션이나 배열 반복 시

컬렉션이나 배열을 순회만 하는 경우에는 for-each 문이 좋다.

for (Element e : c) {
	// 컬렉션 c를 순회하여 e로 무언가 하는 경우
}

이터레이터를 필요할 때 반복 (e.g. remove 메서드를 사용할 때)

for (Iterator<Element> itr = c.iterator(); itr.hasNext();) {
	Element e = itr.next();
	
	// 만약 이터레이터를 사용해 특정 e를 지운다면
	if (e.tostring() == "김") {
		itr.remove();
	}
}

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

단순히 메서드를 기능별로 잘게 쪼개면 지역 변수가 최소화될 것이다.

댓글