원지의 개발
article thumbnail
728x90

예외

  • 에러에 대한 처리
  • 예외처리 메커니즘 제공
  • 문제가 될 만한 부분을 사전에 예상하고 → 문제가 발생하면 이렇게 처리하라고 프로그래밍 하는 것
    목적: 실행이 멈추지 않게
에러 - 심각한 것 / 예외 - 미약한 것

컴파일러 에러 (Compile-time Error): 문법적으로 틀린 부분, 컴파일 할 때 발생하는 에러
런타임 에러 (& Runtime Exception, 실행 예외): (컴파일 과정에서) 실행 할 때 일어나는 에러 / 프로그램 종료
논리적 에러(Logical Error): 작성 의도와 다르게 동작 / 프로그램 종료 X

주요 실행 예외

  • NullPointException (NPE) - null값을 갖는 참조 변수 / dot(.)을 사용했을 때 발생
  • ArrayIndexOutOfBoundsException - 배열의 인덱스 범위 초과
  • NumberFormatException - 문자열→숫자로 변경하는 경우 발생
  • ClassCastException - 클래스 형변화 에러

예외 처리 방법1: try ~ catch ~ finally 

try {
     모든 프로그램 코드
} catch (Exception e) {
    에러 발생시 처리할 내용
} finally {
   무조건 실행
}

  • catch 블럭{ } 여러개 가능 = 다중  catch
  • try 괄호 생략 불가

다중 catch

  • 둘 이상의 예외 처리
주의! 상위 예외 클래스가 하위 예외 클래스보다 아래쪽에 위치해야 함
        예외 처리 클래스도 상속 관계를 가지는데, 주의하지 않으면 자식 클래스들이 실행 안됨

상속관계 확인: ctrl + t
Exception은 예외 클래스들의 부모클래스

예제

더보기

RunTimeEx - 실행예외 되는 경우 4가지

package day10.exception.trycatch;
import day06.inherit.good.Person;

public class RunTimeEx {

	public static void main(String[] args) {
		
//		실행예외(runtime)
//		String s = null;
//		if(s != null) {
//			s.charAt(0);
//		}
	
//		ArrayIndexOut
//		int[] arr = {1, 2, 3};
//		arr[5] = 10;
		
//		ClassCast
//		Object o = new Object(); 
//		Person p = (Person)o; // Person으로 생성된 객체만 Person으로 캐스팅 가능
		
//		NumberFormat
//		String s = "홍길동";
//		Integer.parseInt(s); // 숫자로 바꿔주는 기능
		
	}
}

TryCatchEx01

package day10.exception.trycatch;
public class TryCatchEx01 {

	public static void main(String[] args) {
		
		int a = 10;
		int b = 0;
		
		System.out.println(a + b);

		try {
			System.out.println(a / b);
			System.out.println("이 문장은 실행이 될까요?"); // 실행 안됨, 위에서 에러 발생시 catch영역으로 바로 넘어감
			
		// catch뒤에는 해당 예외를 처리할 수 있는 예외 종류가 들어갑니다.
		} catch (Exception e) {
			System.out.println("0으로 나눌 수 없습니다");
		}
		
		System.out.println(a - b);
		
	}
}

----------------------출력-------------------
10
0으로 나눌 수 없습니다
10
  • a+b, a-b의 경우는 예외가 없으므로 그대로 출력
  • 에러, 예외가 생길 것 같은 구문에 try-catch로 예외시 나올 문장(0으로 나눌 수 없습니다.) 출력
  • try{}의 경우 에러가 발생하는 순간 아래 부분은 실행이 안되고 바로 catch 영역으로 넘어감

TryCatchEx02

package day10.exception.trycatch;
public class TryCatchEx02 {

	public static void main(String[] args) {
		
		String[] arr = {"홍길동", "이순신", "홍길자"};
		
		int i = 0;
		while(i < 4) {
			try {
				System.out.println(arr[i]);
			} catch (Exception e) {
				System.out.println("범위를 벗어났습니다");
			} finally {
				System.out.println("이 문장은 예외 여부와 상관없이 항상 실행됨");
			}
			i++;
		}
	}
}
---------------------------출력--------------------------
홍길동
이 문장은 예외 여부와 상관없이 항상 실행됨
이순신
이 문장은 예외 여부와 상관없이 항상 실행됨
홍길자
이 문장은 예외 여부와 상관없이 항상 실행됨
범위를 벗어났습니다
이 문장은 예외 여부와 상관없이 항상 실행됨
  • String[] 배열 타입 arr에 초기화 된 값이 있음
  • while 반복문으로 i = 0 ~ 3까지 돌면서 배열값이 출력
  • 에러가 발생하면 catch 영역의 범위를 벗어났다는 문구 출력
  • finally영역은 예외 여부와 상관없이 반복을 돌때마다 출력

MultiCatchEx01 - 복습

package day10.exception.trycatch;
public class MultiCatchEx01 {

	public static void main(String[] args) {
		
//		main의 args 사용방법
//		run -> run configuration -> argments탭에 -> ${string_prompt}
		try {
        
//     		main 메소드의 String[] args는 사용자가 입력한 값(문자열)을 args(파라미터)에 할당하는 것을 의미
			String data1 = args[0];
			String data2 = args[1];
		
			int n1 = Integer.parseInt(data1); // String타입의 숫자를 int타입으로 변환
			int n2 = Integer.parseInt(data2);
			
			System.out.println("두 수의 합: " + (n1 + n2));
			
			String s = null;
			s.charAt(0); // string으로 저장된 문자열 중에서 한글자만 선택해서 char타입으로 변환
			
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println("매개값은 2개 입력하세요");
		} catch (NumberFormatException e) {
			System.out.println("매개값은 숫자로 입력하세요");
		} catch (Exception e) { // 어떤 실행 예외든 처리가 가능 (예외의 부모) (클래스의 상속 관계: ctrl + t)
			System.out.println("기타 예외 입니다");
		}
		
//		System.out.println(args[0]);
//		System.out.println(args[1]);
	}
}

 

실행을 여기서도 가능

TryCatchEx03 - 엔터 개행 제거

package day10.exception.trycatch;
import java.util.Scanner;

public class TryCatchEx03 {

	public static void main(String[] args) {
		
//		입력과 예외처리
//		0을 입력하기 전까지 숫자를 입력
		
		Scanner scan = new Scanner(System.in);
		
		while(true) {
			
			try { // 예외 발생 가능성이 있는 코드
				System.out.print(">");
//			1. int num = Integer.parseInt( scan.nextLine() ); // nextLine은 엔터값을 포함해서 다시 받아줌
				int num = scan.nextInt(); // 정수를 받음 (문자 입력하면 프로그램 멈춤, 예외, 에러 발생)
				
				if(num == 0) break; //
				
			// try 내부의 코드에서 에러 발생시 예외를 받아옴(catch가 실행되는 동안 프로그램 멈추지 않음)
			} catch (Exception e) {
				System.out.println("숫자로 입력하세요");
//			2. scan = new Scanner(System.in); // 내풀이
				scan.nextLine(); // 3. 엔터개행을 제거

			}
			
		}
	}
}
--------------------------출력------------------------
>1
>나
숫자로 입력하세요
>
  • nextint로 정수를 입력받고, 엔터를 치면 개행문자는 제거하지 않은 채 그대로 남겨줌
  • 남은 개행문자가 nextLine으로 입력 처리되어 문자를 받지 못하고 바로 개행
  • 오류를 해결하려면 nextLine전 scan.nextLine을 한번더 작성하여 개행문자 제거

Quiz16 - up/down 게임, 엔터 개행 제거

package quiz16;
import java.util.Scanner;

public class MainClass {

	public static void main(String[] args) {
		
	/*
	 * up down게임
	 * 
	 * 1~100까지의 임의의 숫자를 1번 생성
	 * 반복문 안에서 스캐너를 이용해서 정답을 입력받습니다.
	 * 
	 * 랜덤수가 입력받은 값보다 작으면 "더 큰수를 입력하세요"
	 * 랜덤수가 입력받은 값보다 크면 "더 작은수를 입력하세요"
	 * 
	 * 정답이라면 시도횟수: x회 를 출력하고 종료
	 *
	 * 만약에 숫자가 아닌값이 들어온다면 예외를 처리하고, 다시 입력받으세요
	 */

	Scanner scan = new Scanner(System.in);
	int ran = (int)((Math.random()*100) + 1);
	
	int count = 0; // 시도횟수
	
	while(true) {
		try {
			System.out.println("정답입력>");
			int answer = scan.nextInt();
			count++;
			
			if(answer == ran) {
				System.out.println("정답");
				System.out.println("시도 횟수: " + count);
				break;
			} else if(answer > ran) {
				System.out.println("더 작은수를 입력해라");
			} else 
				System.out.println("더 큰 수를 입력해라");
		} catch (Exception e) {
			System.out.println("숫자로 입력해라");
			scan.nextLine(); // while안 무한루프, catch영역에 들어오면 엔터를 강제로 제거
			count++; // 잘못입력한 값도 시도횟수로 들어가야 하므로
		}
		
	}	
	}
}

예외 처리 방법2: throws (예외 떠넘기기) 

  • throws는 직접 처리하지 않고, 메서드 or 생성자를 호출한 곳으로 예외를  떠넘김
    = 메서드 호출자에게 예외를 던지는 방법
  • 예외가 일어나면 통으로 메서드 종료
  • throws 키워드가 붙은 메서드는 반드시 try 블록 내부에서 호출되어야 함. 
  • main도 throws 사용 가능
throws는 예외가 날 수 있는 프로그램 코드 → try-catch로 묶고 쓰라고 강요!!

예외 강제 발생: throw

  • 예외를 직접 생성하는 방법으로 잘 사용되지는 않음
  • 예외를 강제 발생시키며 메서드를 강제 종료

ThrowsEx01

e.printStackTrace(): 예외 발생 당시의 호출스택(Call stack)에 있던 메소드의 정보와 예외 결과를 화면에 출력

package day10.exception.throws_;

public class ThrowsEx01 {

	public static void main(String[] args) {
		
//		메서드에서 예외처리 - throws
//		throws 구문이 붙어있는 메서드 ar 생성자를 호출할때는 예외를 대신 처리애햐 합니다.
//		즉 메서드안에서 예외처리를 강요할 때 사용합니다.
		try { // 호출문장 안에서 예외처리 해줘야 함
			
			greeting(0);
			greeting(1);
			greeting(2);
			greeting(3);
			greeting(4);

		} catch (Exception e) {
			System.out.println("배열 참조를 벗어났습니다");
		}

	
	System.out.println("------------------");
	
	try {
		calc(0);
	} catch (Exception e) {
		System.out.println("\"0으로 나눌 수 없습니다.");
	}
	
	System.out.println("------------------");
	try {
		greeting(5);
	} catch (Exception e) {
//		예외처리를 하면 예외의 내용을 알수가 없기 때문에,
//		예외의 내용을 확인하기 위해서 catch영역에서는 항상 사용합니다.
		e.printStackTrace();
	}
	
	System.out.println("프로그램 정상 종료");
	
	} // main의 끝
    

//	static
	private static String[] arr = {"안녕하세요", "hello", "니하오", "곤니찌와" };
	
	public static void greeting(int index) throws Exception {
		System.out.println(arr[index]);
	}
	
	public static void calc(int num) throws ArithmeticException {
		System.out.println(10 / num);
	}

}

ThrowsEx02 - 1

package day10.exception.throws_;
public class ThrowsEx02 {

//	생성자
	public ThrowsEx02() throws Exception {
		System.out.println("생성자호출");
		aaa();
		System.out.println("생성자종료");
	}

	public void aaa() throws Exception {
		System.out.println("aaa시작");
		bbb(1);
		System.out.println("aaa종료");
	}
	
	public void bbb(int i) throws Exception{
		System.out.println("bbb시작");
		
//		try {
//			System.out.println(i / 0); // 예외
//		} catch (Exception e) {	}
		
		System.out.println(i / 0); // 예외
		System.out.println("bbb종료");
	}
}

// MainClass
package day10.exception.throws_;
public class MainClass {

	public static void main(String[] args) {
		
		try {
			ThrowsEx02 ex = new ThrowsEx02();
		} catch (Exception e) {
			System.out.println("0으로 나눌 수 없습니다");
		}
	}
}

-------------------------호출---------------------
생성자호출
aaa시작
bbb시작
0으로 나눌 수 없습니다
  • ThrowsEx02 - "생성자호출" - aaa() - "aaa시작" - bbb(1) - "bbb시작" - i/0 예외발생 - main의 "0으로 나눌 수 없습니다"문구 출력 - 종료

ThrowsEx02 - 2

package day10.exception.throws_;

public class ThrowsEx02 {

//	생성자
	public ThrowsEx02() throws Exception {
		System.out.println("생성자호출");
		aaa();
		System.out.println("생성자종료"); // aaa()가 끝나고 실행
	}

	public void aaa() throws Exception {
		System.out.println("aaa시작");
		try {
			bbb(1);
		} catch (Exception e) {
			System.out.println("0으로 나눌 수 없습니다");
		}
		System.out.println("aaa종료"); // bbb()가 끝나고 실행
	}
	
	public void bbb(int i) throws Exception{
		System.out.println("bbb시작");
		
//		try {
//			System.out.println(i / 0); // 예외
//		} catch (Exception e) {	}
		
		System.out.println(i / 0); // 예외
		System.out.println("bbb종료");
	}
	
}

// main은 같음
-------------------------호출---------------------
생성자호출
aaa시작
bbb시작
0으로 나눌 수 없습니다
aaa종료
생성자종료
  • ThrowsEx02 - "생성자호출" - aaa() - "aaa시작" - bbb(1) - "bbb시작"- 예외발생 - main의 "0으로 나눌 수 없습니다"문구 출력 - (bbb는 뒷부분 실행 X) - aaa()안의 bbb(1)실행 후 "aaa종료" - 같은 방식으로 위의 "생성자종료"

quiz16 - calculator

package quiz16;

import java.util.Scanner;

public class Calculator {
	
	public static int input() throws Exception {
		/*
		 * 1. 스캐너 정수 2개를 입력을 받습니다.
		 * 2. 입력된 값이 정수라면 합계를 반환합니다.
		 * 3. 예외가 발생할 수 있는 상황이라면 throw를 이용해서 메서드를 종료하고 예외메시지를 전달해주면 됩니다
		 * 4. scan.close() 는 finally 문장에서 사용하세요
		 * 합계반환, 에러메시지
		 */
		
//		Scanner scan = null; 변수를 밖에 선언, 지역변수는 초기화가 필수
//		try안에 scan = new Scanner(System.in); 아래와 같음
		Scanner scan = new Scanner(System.in);
		
		try {
			System.out.println("정수 입력1> ");
			int a = scan.nextInt();
			System.out.println("정수 입력2> ");
			int b = scan.nextInt();

			int sum = 0;
			sum = a + b;
			System.out.println("정수 합계: " + sum);
			return sum;
			
		} catch (Exception e) {
			throw new Exception("정수로 입력해라"); // 예외생성, throw문제가 생기면서 input()옆에 throws Exception 추가
			
		} finally {
			scan.close();
			System.out.println("입력을 종료");
		}

	}
}
  • Scanner scan = new Scanner(System.in);
                                  ∥
  • Scanner scan = null; (변수를 밖에 선언, 지역변수는 초기화가 필수)
    try안에 scan = new Scanner(System.in);
  • throw new Exception("정수로 입력해라");
    예외생성, throw문제가 생기면서 input()옆에 throws Exception 추가
package quiz16;

public class MainClass2 {

public static void main(String[] args) {
		
		try {
			Calculator.input();
			
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e.getMessage());
		
		} finally { // 여기서는 없어도 됨
			System.out.println("입력을 종료합니다");
		}
		
	}
}
  • main에서 Calculator.input(); 출력
  • 예외구문 System.out.println(e.getMessage()); : throw new Exception에 적은 출력

오늘 하루

더보기

기억에 남는 부분

- main과 method에서 한꺼번에 try~catch 구문 사용 가능

- throws 키워드가 붙은 메서드는 반드시 try 블록 내부에서 호출 필수

 

어려운 부분

- nextInt, nextLine 개행문자 저장되는 부분 살짝 헷갈리지만 알겠음

- ThrowsEx02 부분 throws가 돌아가는 순서 확인

 

문제 해결 부분

- quiz16.Calculator class, main 두 부분에 예외 설정 가능
  e.printStackTrace();, System.out.println(e.getMessage()); 사용

 

728x90
profile

원지의 개발

@원지다

250x250