고래씌

[JAVA] 12-1. 예외처리(UncheckedException, CheckedException) 본문

JAVA/JAVA 기초

[JAVA] 12-1. 예외처리(UncheckedException, CheckedException)

고래씌 2023. 10. 20. 11:43

1. 예외처리

▶ 에러(오류) 종류
- 시스템 에러 : 컴퓨터의 오작동으로 인해 발생하는 에러 => 소스코드로 해결이 불가능(심각한 에러)
- 컴파일 에러 : 소스코드상의 문법적인 문제로 발생하는 에러 => 소스코드의 수정으로 해결가능(빨간밑줄로 알려줌)
- 런타임 에러 : 소스코드상으로는 문제가 없는데, 프로그램을 실행 중 발생하는 에러 
                         => 사용자가 잘못 입력한 경우일수도, 개발자가 예측가능한 경우를 제대로 처리해놓지 않은 걸수도 있다.
- 논리에러     : 소스코드상의 문법적인 문제도 없고, 실행했을때도 에러가 발생하지 않지만, 프로그램의 의도상의 기능과 맞지 않는 경우
 
▶ 시스템 에러를 제외한 컴파일 에러, 런타임 에러, 논리 에러와 같은 비교적 덜 심각한 것들을 가지고 작업할 예정.
이러한 에러들을 "예외"라고 정의함(Exception)
 
▶ 예외처리를 해야하는 이유 : 예외 발생시 프로그램이 비정상적으로 종료되는 것을 막고자하기 위함.
 
▶ 예외처리 방법
① try ~ catch 문을 이용
② throws를 이용(떠넘기기)
 
 

2. UncheckedException  (반드시 예외처리를 안해도 되는 예외들)

: 프로그램 실행시 발생되는 예외들
 
RuntimeException의 자식클래스들
- ArrayIndexOutOfBoundsException  :  배열의 부적절한 인덱스로 접근할 때 발생하는 예외
 
- NegativeArraySizeException   :  배열의 크기를 음수로 지정할 경우 발생하는 예외
 
- ClassCastException   :  허용할 수 없는 형변환이 진행될 경우 발생하는 예외
   ex)  Object ob = new String("d");   →   ((Integer)ob) 형변환 불가.
 
- NullPointerException :  참조변수가 null 값을 저장함에도 불구하고, 특정 필드 및 메소드에 접근하려고
                                                              할 때 발생한다.(null값 저장은 아무 문제 없다)
 
- ArithmeticException :  나누기 연산시 0으로 나눌때 발생하는 예외
- ....
 
☞ 이러한 RuntimeException과 관련한 예외들은 예외상황이 충분히 예측 가능한 상황이기 때문에 예외자체가 발생하지 안되게끔 조건문으로 해결 가능하긴함. 굳이 예외처리를 할 필요가 없다.
 
 

1) ArithmeticException  

: 나누기 연산시 0으로 나누고자할 때 발생하는 예외
 
■ 사용자에게 두개의 정수값을 입력받아 나눗셈 연산 결과 출력

package com.kh.exception.controller;

import java.util.Scanner;

public class A_UncheckedException {

	private Scanner sc = new Scanner(System.in);
	
	public void method1() {
		
		// ArithmeticExcepton : 나누기 연산시 0으로 나누고자할 때 발생하는 예외
		
		// 사용자에게 두개의 정수값을 입력받아 나눗셈 연산 결과 출력
		
		System.out.print("첫번째 정수 : ");
		int num1 = sc.nextInt();
		
		System.out.print("두번째 정수(0 제외) : ");
		int num2 = sc.nextInt();
		sc.nextLine();
	}

 
 
■ 해결방법 1.
조건문으로 처리(애초에 예외 자체가 발생되지 않게끔 if문으로 조건검사 후 계산 진행)

package com.kh.exception.controller;

import java.util.Scanner;

public class A_UncheckedException {

	private Scanner sc = new Scanner(System.in);
	
	public void method1() {
		
		// ArithmeticExcepton : 나누기 연산시 0으로 나누고자할 때 발생하는 예외
		
		// 사용자에게 두개의 정수값을 입력받아 나눗셈 연산 결과 출력
		
		System.out.print("첫번째 정수 : ");
		int num1 = sc.nextInt();
		
		System.out.print("두번째 정수(0 제외) : ");
		int num2 = sc.nextInt();
		sc.nextLine();
		
		// 해결방법 1. 조건문으로 처리(애초에 예외 자체가 발생되지 않게끔 if문으로 조건검사 후 계산 진행)
		if(num2 == 0) {
			System.out.println("0으로 나눌 수 없습니다.");
		}else {
			System.out.println("나눗셈 연산 결과 : " + (num1 / num2));
		}
		System.out.println("프로그램 종료");
	}
}

 
 
■ 해결방법 2.
예외처리 구문으로 해결(예외가 발생했을 경우를 대비해서 실행할 내용을 정의해두는 것)
 
try ~ catch문
[표현법]
try {
     예외가 발생될수도 있는 소스코드가 존재하는 구문
} catch (발생될 예외클래스 변수명){
     e.printStackTrace(); // 오류를 추적할 수 있음. 현재 예외가 발생한 정보를 볼 수 있다.
     해당 예외가 발생할 경우 실행할 구문
}

package com.kh.exception.controller;

import java.util.Scanner;

public class A_UncheckedException {

	private Scanner sc = new Scanner(System.in);
	
	public void method1() {
		
		// ArithmeticExcepton : 나누기 연산시 0으로 나누고자할 때 발생하는 예외
		
		// 사용자에게 두개의 정수값을 입력받아 나눗셈 연산 결과 출력
		
		System.out.print("첫번째 정수 : ");
		int num1 = sc.nextInt();
		
		System.out.print("두번째 정수(0 제외) : ");
		int num2 = sc.nextInt();
		sc.nextLine();

		
		// 해결방법 2. 예외처리 구문으로 해결(예외가 발생했을 경우를 대비해서 실행할 내용을 정의해두는 것)
		/*
		 * try ~ catch문
		 * [표현법]
		 * try {
		 *    예외가 발생될수도 있는 소스코드가 존재하는 구문
		 * } catch (발생될 예외클래스 변수명){
		 *    해당 예외가 발생할 경우 실행할 구문
		 * }
		 */
		
		try {
			System.out.println("나눗셈 연산 결과 : " + (num1 / num2));
		}catch(ArithmeticException e) {
			e.printStackTrace(); // 오류를 추적할 수 있음. 현재 예외가 발생한 정보를 볼 수 있다.
			System.out.println("0으로 나눌 수 없습니다.");
		}
		System.out.println("프로그램을 종료합니다.");
	}
}

 
 

2) cath블럭이 여러개 있는 경우

■ try ~ catch 문을 사용하는데 catch블럭이 여러개 있는 경우

	public void method2() {
		
		System.out.print("정수입력(0 제외 ) : ");
		
		try {
			int num = sc.nextInt(); // InputMismatchException
			
			System.out.println("나눗셈 연산 결과 : " + (10/num));  // AritmeticException 발생가능한 코드
		}catch(ArithmeticException e) {
			System.out.println("0으로 나눌 수 없습니다.");
		}catch(InputMismatchException e) {
			System.out.println("정수값을 입력해주세요.");
		}// 다중 catch블럭. : 예외가 여러개 발생할 가능성이 있을 경우 사용
		
		System.out.println("프로그램 종료");

	}

 
 

3) 범위가 작은 자식타입의 예외를 먼저 기술!

 
▶ RuntimeException 관련된 예외는 대부분
- 조건문으로 해결 가능   =>  예외 자체가 발생 안되게끔 개발자가 소스코드로 핸들링 하는 것(예외처리x)
- 예외 처리 구문으로 해결 가능  =>  예외가 발생했을 때를 대비해서 그때 실행할 내용을 정의해두는 것
 
 
- 예측이 가능한 상황 → 조건문으로 해결가능(권장)
- 예측이 불가능한 상황 → 예외처리 구문으로 해결
 
▶ RuntimException 계열은 충분히 예측 가능한 상황이기 때문에 조건문으로 해결하는 것을 권장
필수는 아니다 => UncheckedException
 
 
- RuntimeException 은 부모타입의 예외 클래스!
- ArrayIndexOutOfBoundsException은 자식타입의 예외 클래스
★ 범위가 작은 자식타입의 예외를 먼저 기술해야한다!! ★
 

	public void method3() {
		
		// ArrayIndexOutOfBoundsException :
		// NegativeArraySizeException :
		
		System.out.print("배열의 크기 : ");
		try {
			int size = sc.nextInt();

			if(size < 0) {
				System.out.println("음수로 제시할 수 없습니다.");
				return;
			}

			int[] arr = new int[size];
			if(arr.length > 100)
				System.out.println("100번째 인덱스 값 : " + arr[100]);

		
		}catch(ArrayIndexOutOfBoundsException e) { // 범위가 작은 자식타입의 예외를 먼저 기술해야한다.
			System.out.println("부적절한 인덱스로 접근했다.");
		
			// 다중 catch블럭과 비교했을 때 코드블럭이 줄어들긴 했지만 정확히 어떤 예외가 발생했는지 알 수 없음
		}catch(RuntimeException e) {  // 다형성을 적용하여 부모타입의 예외클래스 하나만 작성
			System.out.println("에러가 발생하긴 했는데, 입력값이 잘못 입력되었을 수도 있고, "
					+ "배열의 크기를 음수로 입력했을 수도 있고,"
					+ "부적절한 인덱스로 접근했을수도 있다.");
		}
		
//		catch(ArrayIndexOutOfBoundsException e) {
//			System.out.println("부적절한 인덱스로 접근했습니다.");
//		}catch(NegativeArraySizeException e) {
//			System.out.println("배열의 크기를 음수로 제시할 수 없습니다.");
//		}

	}

 
 
 

3. CheckedException  (반드시 예외처리를 해줘야 하는 예외들)

 (즉, 예측이 불가능한 곳에서 예외가 발생하기 때문에 미리 예외처리구문을 작성해야함)
 => 주로 외부매체외 입출력시 발생
 
 
 
① try ~ catch 문으로 예외처리하기

package com.kh.exception.controller;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class B_CheckedException {
	
	/*
	 * CheckedException 은 반드시 예외처리를 해줘야하는 예외들
	 * (즉, 예측이 불가능한 곳에서 예외가 발생하기 때문에 미리 예외처리구문을 작성해야함)
	 * => 주로 외부매체외 입출력시 발생
	 */
	
	public void method2() {
		
		// Scanner와 같이 키보드로 값을 입력받을 수 있는 객체
		 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		System.out.print("아무 문자열이나 입력해주세요. ");
		
		// 1. try ~ catch으로 예외 처리하기
        
		try {
			// 이 메소드 호출시 IOException가 발생할 수도 있음을 컴파일 에러로 알려준다.
			String str = br.readLine();  // 문자열값 얻어오는 메소드
		}catch (IOException e) {
			e.printStackTrace();
		}
		

	}

}

 
 
② throws 이용해서 예외처리하기  - 별로 추천하지 않는 방법
: 지금 현재 메소드에서 예외를 처리하지 않고, 현재 메소드를 호출한 곳으로 떠넘기는 방법
 

package com.kh.exception.run;

import java.io.IOException;
import java.util.Calendar;

import com.kh.exception.controller.A_UncheckedException;
import com.kh.exception.controller.B_CheckedException;

public class Run {

	public static void main(String[] args) throws IOException {
		
		B_CheckedException bce = new B_CheckedException();
		bce.method1();

	}
}
package com.kh.exception.controller;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class B_CheckedException {

	
	public void method1() throws IOException {
		
		method2();
	}
	

	
	public void method2() throws IOException {
		
		// Scanner와 같이 키보드로 값을 입력받을 수 있는 객체
		 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		System.out.print("아무 문자열이나 입력해주세요. ");
		
		
		// 2. throws : 지금 현재 메소드에서 예외를 처리하지 않고, 현재 메소드를 호출한 곳으로 떠넘기는 방법
		String str = br.readLine();
		
		System.out.println("문자열의 길이 : " + str.length());
	}

}

 
※ 정리

  예외 발생 시점 예외 처리
RuntimeException 프로그램 실행하는 도중 에러 발생 필수 X => UncheckedException
IOException  그 외  컴파일 에러 필수 => CheckedException