JAVA 웹개발 과정 국비 6일차 정리

6일차

※ 배우는 과정이므로 정확하지 않을 수 있습니다.
잘못된 점은 알려주시면 수정하도록 하겠습니다!


1. 변수의 종류

  1. 지역변수
    • 중괄호 안에 있는 변수
    • 같은 지역 내에서 같은 변수 이름 2개 불가능
    • Life cycle = 지역
  2. 매개변수
  3. 멤버변수
  4. 정적변수

2, 3, 4의 변수는 뒤에서 배우니 패스.

1) if문과 break문은 관련이 없다.

ATM 시뮬레이터 예제 문제를 풀 때, 헷갈리는 것이 있었다.

class Quiz_01 {
	public static void main(String[] args) {
		
		// 1번 : 무한 루프 안에 if문 안에 break - 무한루프 탈출 가능
		while(true){
			if(){
				break;
			}
		}
		
		// 2번 : 무한 루프 안에 switch문 안에 break - 무한루프 탈출 불가능
		while(true){
			switch(){
			case:
				break;
			}
		}
		
	}
}

1번과 2번 모두 동일하게 동작할 줄 알았는데, 1번은 무한루프가 종료되는 반면 2번은 무한루프가 종료되지 않았다.
반복문 - if문 일때는 반복문을 탈출하지만,
반복문 - 선택문 - if문 일때는 선택문만 탈출한다. 따라서 2번이 무한루프가 되는 것이다.
break문은 쉬운 개념이라고 생각했는데 생각보다 헷갈려서 다시 정리해놓는다.

2. 예외처리 : try - catch 문 사용

1) 예외처리를 하는 이유

  • 에러가 나는 코드 라인 이후 코드는 아예 실행이 되지 않는다.
  • 프로그램이 에러가 나서 종료되는 것을 방지하기 위함.
  • try - catch문 사용.
import java.util.Scanner;

public class Quiz_02 {
	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);
		
		while(true) {
			System.out.println("=== 계산기 프로그램 ===");
			System.out.print("연산자 입력 (+, -, *, /) : ");
			String oper = sc.nextLine();

(중략)
			
			System.out.print("첫 번째 숫자 입력 : ");
			int num1 = Integer.parseInt(sc.nextLine());

			System.out.print("두 번째 숫자 입력 : ");
			int num2 = Integer.parseInt(sc.nextLine());

			System.out.println("====== 결 과 ======");
(후략)

위 코드는 계산기 프로그램 실습 코드 중 일부만 따온 것이다.
이 상태로 실행을 한다면 첫 번째 숫자 입력하는 부분에서 알파벳(문자열)이 입력된다면 에러가 나고 프로그램이 정지할 것이다.
parseInt 함수가 문자열을 처리할 수 없기 때문이다.

예외 처리를 하는 방법을 정리해보자.

2) 예외 발생 예상 지점을 찾는다.

예외 발생 예상 지점을 찾는다.

(전략)
			System.out.print("첫 번째 숫자 입력 : ");
			int num1 = Integer.parseInt(sc.nextLine());

			System.out.print("두 번째 숫자 입력 : ");
			int num2 = Integer.parseInt(sc.nextLine());
(후략)

3) try - catch 문을 사용한다.

  • try 문 : 예외가 발생할 것 같은 구문을 감싸준다.
  • catch문 : 예외 발생 시 어떻게 처리할 것인지 써준다.

try - catch 문을 사용함으로써 에러가 발생하지 않으면 catch문을 실행하지 않고 넘어가고, 에러가 발생하면 catch문을 실행한다.
발생하는 에러는 여러가지가 있고, 그에 따른 처리를 각각 해줘야하지만 (멀티캐치문) 현재는 에러는 모두 뭉뚱그려서 (Exception e)로 배우고 넘어갔다.

(전략)
			try {
				System.out.print("첫 번째 숫자 입력 : ");
				int num1 = Integer.parseInt(sc.nextLine());
			}catch(Exception e) {
				System.out.println("숫자를 입력해주세요.");
				}
			
			try {
				System.out.print("두 번째 숫자 입력 : ");
				int num2 = Integer.parseInt(sc.nextLine());
			}catch(Exception e) {
				System.out.println("숫자를 입력해주세요.");
				}
				
			System.out.println("====== 결 과 ======");
(후략)

4) 실행할 수 없다.

위 코드처럼 try - catch문을 만들어주고 실행해본다면, 오류가 날 것이다.
바로 지역변수 num1 과 num2 때문이다.
num1과 num2가 try문 안에서 선언되었기 때문에, 아래 코드들은 try문 밖에 있어서 컴퓨터가 읽을 수 없다.
따라서 변수 선언한 코드를 try문으로 옮겼다면 꼭 try문 밖에서 변수를 선언하도록 바꿔주자.

(전략)
			int num1 = 0; // 변수 선언 밖으로 빼주기
			int num2 = 0; // 변수 선언 밖으로 빼주기

			try {
				System.out.print("첫 번째 숫자 입력 : ");
				num1 = Integer.parseInt(sc.nextLine()); // 변수 선언 삭제
			}catch(Exception e) {
				System.out.println("숫자를 입력해주세요.");
				}
			
			try {
				System.out.print("두 번째 숫자 입력 : ");
				num2 = Integer.parseInt(sc.nextLine()); // 변수 선언 삭제
			}catch(Exception e) {
				System.out.println("숫자를 입력해주세요.");
				}
				
			System.out.println("====== 결 과 ======");
(후략)

5) 사용자입장에서 생각하기

사용자가 되어 계산기 프로그램을 써본다고 가정해보자.
연산자도 잘 적고, 첫 번째 숫자도 잘 적었는데, 두 번째 숫자를 알파벳을 입력해버렸다.
그런데 위 코드대로라면 ‘숫자를 입력해주세요.’ 라는 안내문구가 나오고 바로 잘못된 결과값도 출력이 되어버린다. 이상한 프로그램이 되는 것이다.

6) continue 사용

그래서 catch문 맨 마지막에 continue를 넣어서 결과값이 출력되지 않고 맨 위(while문 시작)로 다시 돌아가게 만들었다.
기껏 연산자와 첫 번째 숫자를 잘 입력했는데, 두 번째 숫자를 잘못 입력했다고 연산자부터 다시 입력하게 만드는 것이다.
사용자 입장에서는 굉장히 짜증나는 일이 아닐 수 없다.

7) while문으로 감싸주기

두 번째 숫자를 잘못 입력했으면 두 번째 숫자부터 다시 입력하게 만들어야 한다.
while 문으로 try - catch 문을 감싸서 각각의 처음으로 다시 돌려보낸다.
각각 while문을 감싸준 것도 그 이유 때문이다. 한번에 while문 안에 넣어버리면 아까와 똑같이 두 번째 숫자만 잘못 입력해도 첫 번째 숫자부터 입력해야하는 번거로움이 있기 때문이다.
아래와 같이 코드를 수정해주면 잘못 입력한 숫자만 다시 받는 코드가 만들어진다.

그리고 에러가 발생하지 않으면 반복문을 탈출하는 break를 try문 아래에 써준다.
써주지 않으면 무한루프가 발생하는 오류가 생긴다.

(전략)
			while(true) {
				try {
					System.out.print("첫 번째 숫자 입력 : ");
					num1 = Integer.parseInt(sc.nextLine());
					break; // 반복문 탈출
				}catch(Exception e) {
					System.out.println("숫자를 입력해주세요.");
				}
			}

			while(true) {
				try {
					System.out.print("두 번째 숫자 입력 : ");
					num2 = Integer.parseInt(sc.nextLine());
					break; // 반복문 탈출
				}catch(Exception e) {
					System.out.println("숫자를 입력해주세요.");
				}
			}
(후략)

이렇게 하면 예외 처리가 끝난다.
단순히 try - catch문만 쓰는 것이 아니라 while문, break를 적절히 써주어야 완벽한 예외처리를 해줄 수 있다.
생각보다 쉽지 않은 작업이었다.

3. try - catch 문에서의 sc.nextInt(); 사용

위의 코드를 보면 입력을 모두 Integer.parseInt(sc.nextLine());로 받고 있는 것을 볼 수 있다.
sc.nextInt();를 사용하는 것은 까다롭기 때문이다.

(전략)
			while(true) {
				try {
					System.out.print("첫 번째 숫자 입력 : ");
					num1 = sc.nextInt(); // 1번 : Integer.parseInt(sc.nextLine()); 사용
					break;
				}catch(Exception e) {
					System.out.println("숫자를 입력해주세요.");
					// 2번 : sc.nextLine(); 사용
				}
			}
(후략)

위와 같은 코드가 있다고 해보자.
첫 번째 숫자로 ABC\r\n(엔터) 를 입력했다고 가정했을 때, buffer에도 똑같이 ABC\r\n이 들어있을 것이다.
여기서의 에러는 parseInt가 문자열을 받지 못하는 것과는 다른 에러인 InputMismatchException이 생긴다.
‘가져올 숫자가 없다’는 말이다.
어쨌든 에러가 발생하면 catch 문이 실행될 것이고, ‘숫자를 입력해주세요.’ 문구가 출력된다.
그리고 while 무한 반복문으로 인해 또 첫 번째 숫자를 입력받을 것이다.
그러나 buffer에는 여전히 ABC\r\n이 들어있으므로 또다시 catch문이 실행되고 또 문구가 출력되고… 이렇게 반복되어 결국 ‘숫자를 입력해주세요.’ 문구만 무한히 반복되는 무한루프가 생긴다.

1) 해결하는 방법은?

해결할 수 있는 방법은 총 2가지가 있다.

  1. sc.nextInt();대신 Integer.parseInt(sc.nextLine()); 사용
  2. sc.nextLine();을 catch문 아래에 써서 buffer를 비운다.

그냥 nextInt()는 되도록 안쓰는 걸로…

4. break label

위에서도 말했듯이 break문은 가장 가까운 반복문을 종료시키고 바깥쪽 반복문은 종료시키지 못한다.
중첩된 반복문을 탈출하기 위해서는 break label을 사용하면 된다.

public class Quiz_test {
	public static void main(String[] args) {
		
		while(true) {
			while(true) {
				System.out.println("무한루프 반복 중");
				break;
			}
		}
		
	}
}

위의 코드는 break를 썼음에도 불구하고 무한루프로 반복된다.
break문은 안쪽 while문만 탈출하기 때문이다.
이 때, break label을 아래와 같이 써주면 무한루프는 종료된다.

public class Quiz_test {
	public static void main(String[] args) {
		
		wh: while(true) { // 라벨명: 반복문
			while(true) {
				System.out.println("무한루프반복중");
				break wh; // break 라벨명;
			}
		}
		
	}
}

댓글남기기