[JAVA]

[처음부터 다시 하는 JAVA] 스코프

북방바다코끼리표범 2024. 1. 12. 17:49

처음부터 다시 하는 자바 공부는 인프런의 김영한 강사님의 강의를 참고해서 공부했다.

 

스코프1 - 지역 변수와 스코프

변수는 선언한 위치에 따라 지역 변수, 멤버 변수(클래스 변수, 인스턴스 변수)와 같이 분류된다.
우리가 지금까지 학습한 변수들은 모두 영어로 로컬 변수(Local Variable) 한글로 지역 변수라 한다. 

나머지 변수들은 뒤에서 학습한다 지금은 지역 변수만 기억하자.
지역 변수는 이름 그대로 특정 지역에서만 사용할 수 있는 변수라는 뜻이다. 그 특정 지역을 벗어나면 사용할 수 없다. 
여기서 말하는 지역이 바로 변수가 선언된 코드 블록( {} )이다. 지역 변수는 자신이 선언된 코드 블록( {} ) 안에서만 생 
존하고, 자신이 선언된 코드 블록을 벗어나면 제거된다. 따라서 이후에는 접근할 수 없다.

 

package scope; 

public class Scope1 {
	public static void main(String[] args) { 
        int m = 10; //m 생존 시작
        if (true) {
            int x = 20; //x 생존 시작
            System.out.println("if m = " + m); //블록 내부에서 블록 외부는 접근 가능 
            System.out.println("if x = " + x);
        } //x 생존 종료
        
        //System.out.println("main x = " + x); //오류, 변수 x에 접근 불가 
		System.out.println("main m = " + m);
    } //m 생존 종료
 }
  • int m
    • int m 은 main{} 의 코드 블록안에서 선언되었다. 따라서 변수를 선언한 시점부터 main{} 의 코드 블록이 종료될 때 까지 생존한다.
    • if{} 블록 내부에서도 외부 블록에서 선언된 m 에 접근할 수 있다. 쉽게 이야기해서 생존 범위만 맞으면 다 접근할 수 있다.
  • int x
    • int x 는 if{} 블록안에서 선언되었다. 따라서 변수를 선언한 시점부터 if{} 의 코드 블록이 종료될 때 까지 생존한다.
    • if{} 내부에서는 자신의 범위에서 선언한 x 에 당연히 접근할 수 있다.
    • if{} 코드 블록이 끝나버리면 x 는 제거된다. 따라서 더는 x 에 접근할 수 없다. 따라서 이후에 접근하면 
      cannot find symbol 이라는 변수 이름을 찾을 수 없다는 컴파일 오류가 발생한다.

정리하면 지역 변수는 본인의 코드 블록 안에서만 생존한다. 그리고 자신의 코드 블록 안에서는 얼마든지 접근할 수 있 
다. 하지만 자신의 코드 블록을 벗어나면 제거되기 때문에 접근할 수 없다.

 

이렇게 변수의 접근 가능한 범위를 스코프(Scope)라 한다. 참고로 Scope를 번역하면 범위라는 뜻이다.
int m 은 main{} 전체에서 접근할 수 있기 때문에 스코프가 넓고, int x 는 if{} 코드 블록 안에서만 접근할 수 
있기 때문에 스코프가 좁다.

 

이번에는 if{} 대신에 for{} 를 사용하는 예제를 보자

package scope; 

public class Scope2 {
	public static void main(String[] args) { 
        int m = 10;
        for (int i = 0; i < 2; i++) { //블록 내부, for문 내
            System.out.println("for m = " + m); //블록 내부에서 외부는 접근 가능 
            System.out.println("for i = " + i);
        } //i 생존 종료

		//System.out.println("main i = " + i); //오류, i에 접근 불가 
		System.out.println("main m = " + m);
    } 
}

for 문으로 바뀐 것을 제외하면 앞의 예제와 비슷한 예제이다.
for 문의 경우 for(int i=0;..) 과 같이 for 문 안에서 초기식에 직접 변수를 선언할 수 있다. 그리고 이렇게 선언한 변수는 for 문 코드 블록 안에서만 사용할 수 있다.

 

스코프2 - 스코프 존재 이유

변수를 선언한 시점부터 변수를 계속 사용할 수 있게 해도 되지 않을까? 왜 복잡하게 접근 범위(스코프)라는 개념을 만 
들었을까?
이해를 위해 다음 코드를 보자

package scope;

public class Scope3_1 {
	public static void main(String[] args) { 
		int m = 10;
		int temp = 0;
		if (m > 0) {
            temp = m * 2;
			System.out.println("temp = " + temp);
        }
		System.out.println("m = " + m);
    } 
}

조건이 맞으면 변수 m 의 값을 2배 증가해서 출력하는 코드이다. 여기서 2배 증가한 값을 저장해두기 위해 임시 변수 
temp 를 사용했다. 그런데 이 코드는 좋은 코드라고 보기는 어렵다. 왜냐하면 임시 변수 temp 는 if 조건이 만족할 
때 임시로 잠깐 사용하는 변수이다. 그런데 임시 변수 temp main() 코드 블록에 선언되어 있다. 이렇게 되면 다음과 
같은 문제가 발생한다.

  • 비효율적인 메모리 사용: temp 는 if 코드 블록에서만 필요하지만, main() 코드 블록이 종료될 때 까지 메모리 
    에 유지된다. 따라서 불필요한 메모리가 낭비된다. 만약 if 코드 블록 안에 temp 를 선언했다면 자바를 구현하 
    는 곳에서 if 코드 블록의 종료 시점에 이 변수를 메모리에서 제거해서 더 효율적으로 메모리를 사용할 수 있다. 
  • 코드 복잡성 증가: 좋은 코드는 군더더기 없는 단순한 코드이다. temp 는 if 코드 블록에서만 필요하고, 여기서 
    만 사용하면 된다. 만약 if 코드 블록 안에 temp 를 선언했다면 if 가 끝나고 나면 temp 를 전혀 생각하지 않 
    아도 된다. 머리속에서 생각할 변수를 하나 줄일 수 있다. 그런데 지금 작성한 코드는 if 코드 블록이 끝나도 
    main() 어디서나 temp 를 여전히 접근할 수 있다. 누군가 이 코드를 유지보수 할 때 m 은 물론이고 temp 까지 
    계속 신경써야 한다. 스코프가 불필요하게 넓은 것이다. 지금은 코드가 매우 단순해서 이해하는데 어려움이 없겠 
    지만 실무에서는 코드가 매우 복잡한 경우가 많다.

temp 의 스코프를 꼭 필요한 곳으로 한정해보자

package scope;

public class Scope3_2 {
	public static void main(String[] args) { 
        int m = 10;
        if (m > 0) {
			int temp = m * 2;
			System.out.println("temp = " + temp);
        }
		System.out.println("m = " + m);
    } 
}

temp 를 if 코드 블록 안에서 선언했다. 이제 temp 는 if 코드 블록 안으로 스코프가 줄어든다.

덕분에 temp 메모리를 빨리 제거해서 메모리를 효율적으로 사용하고, temp 변수를 생각해야 하는 범위를 줄여서 더 유지보수 하기 좋은 코드를 만들었다.

 

 

while문 vs for문 - 스코프 관점

이제 스코프 관점에서 while 문과 for 문을 비교해보자 
다음 코드들은 기존에 반복문에서 학습했던 코드이다.

package loop;

public class While2_3 {
	public static void main(String[] args) {
        int sum = 0;
        int i = 1;
        int endNum = 3;

		while (i <= endNum) {
            sum = sum + i;
			System.out.println("i=" + i + " sum=" + sum);
             i++; 
        }
		//... 아래에 더 많은 코드들이 있다고 가정
    } 
}
package loop; 

public class For2 {
	public static void main(String[] args) { 
        int sum = 0;
        int endNum = 3;
        for (int i = 1; i <= endNum; i++) {
            sum = sum + i;
			System.out.println("i=" + i + " sum=" + sum);
        }
		//... 아래에 더 많은 코드들이 있다고 가정
    } 
}

변수의 스코프 관점에서 카운터 변수 i 를 비교해보자.

  • while 문의 경우 변수i 의 스코프가 main() 메서드 전체가 된다. 반면에 for 문의 경우 변수 i 의 스코프가 for문 안으로 한정된다.
  • 따라서 변수 i 와 같이 for 문 안에서만 사용되는 카운터 변수가 있다면 while 문 보다는 for 문을 사용해서 스코프의 범위를 제한하는 것이 메모리 사용과 유지보수 관점에서 더 좋다.

정리

  • 변수는 꼭 필요한 범위로 한정해서 사용하는 것이 좋다. 변수의 스코프는 꼭 필요한 곳으로 한정해서 사용하자. 메 
    모리를 효율적으로 사용하고 더 유지보수하기 좋은 코드를 만들 수 있다.
  • 좋은 프로그램은 무한한 자유가 있는 프로그램이 아니라 적절한 제약이 있는 프로그램이다.