예비 개발자(학원)

자바[11] 예외처리

Im늘품 2024. 4. 5. 11:33

1. 예외 처리

프로그램에서 예외가 발생할 경우 프로그램의 갑작스러운 종료를 막고, 정상 실행을 유지할 수 있도록 예외 처리를 한다.

 

오류(error) vs 예외(exception)
오류(error)의 종류:

  1. 시스템 에러: (예) 메모리 부족(OOM: Out-Of-Memory) -> 수정 매우 힘듦, 불가능.
  2. 컴파일 에러: 문법 오류 -> 반드시 수정!
  3. 논리적 오류: 프로그램이 정상적으로 컴파일되고 실행/종료가 되지만, 원하는 결과가 나오지 않는 경우 -> 반드시 수정. 수정 힘듦.
  4. 예외(exception): 프로그램 실행 중에 발생할 수 있는 비정상적인 상황 -> 반드시 수정.
    (1) if-else 문장
    (2) try-catch 문장

<ExceptionMain01.java>

import java.util.Scanner;

public class ExceptionMain01 {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);

		System.out.print("정수 x 입력> ");
		int x = Integer.parseInt(sc.nextLine());

		System.out.print("정수 y 입력> ");
		int y = Integer.parseInt(sc.nextLine());

		if (y != 0) {
			System.out.println("나눈 몫 = " + (x / y));
		} else {
			System.out.println("0으로는 나눌 수 없습니다.");
		}
	}
}

 

 

 try-catch 문장을 사용한 예외 처리:
 
try {
정상적인 상황에서 실행할 코드들; // (1)
} catch (Exception 타입의 변수 선언) {
예외 상황이 발생했을 때 처리할 코드들; // (2)
} finally {

예외 상황 발생 여부와 상관 없이 반드시 실행할 코드들; // (3)
}
  
예외가 발생하지 않을 경우: (1) -> (3)
예외가 발생한 경우: (1) -- 예외 발생 --> (2) -> (3)
  
try-catch 문장에서 catch 블록은 반드시 1개 이상 있어야 함.
catch 블록은 처리하려는 예외의 종류에 따라서 여러개를 작성할 수 있음.
finally 블록은  선택 사항.

<ExceptionMain02.java>

package com.itwill.exception02;

import java.util.Scanner;


public class ExceptionMain02 {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		try {
			System.out.print("x = ");
			int x = Integer.parseInt(sc.nextLine());
			
			System.out.print("y = ");
			int y = Integer.parseInt(sc.nextLine());
			
			System.out.println("x / y = " + (x / y));
		} catch (ArithmeticException e) {
			System.out.println("y는 0이 될 수 없음.");
			System.out.println(e.getMessage());
		} catch (NumberFormatException e) {
			System.out.println("x, y는 정수로 입력하세요.");
			System.out.println(e.getMessage());
		} finally {
			System.out.println();
		}
	}
}

 

<ExceptionMain03.java>

import java.util.Scanner;

public class ExceptionMain03 {

	private final Scanner sc = new Scanner(System.in);

	public static void main(String[] args) {
		ExceptionMain03 app = new ExceptionMain03();

		int x = app.inputInteger2(); //app.inputInteger();
		System.out.println("x = " + x);
	}

	public int inputInteger2() {
		try {
			System.out.println("정수 입력> ");
			return Integer.parseInt(sc.nextLine());
		} catch (NumberFormatException e) {
			System.out.println("정수로 입력하세요...");
			return inputInteger2();
		}
	}

	public int inputInteger() {
		int result = 0;

		while (true) {
			try {
				System.out.print("정수 입력> ");
				result = Integer.parseInt(sc.nextLine());
				break;
			} catch (NumberFormatException e) {
				System.out.println("입력한 내용은 정수가 아닙니다.");
			}
		}
		return result;
	}
}

 


multi-catch 블록
하나의 catch 구문에서 여러개의 Exception 타입 객체를 처리하는 방법.

 try {
} catch (ExceptionType1 | ExceptionType | ... e) {
}

(주의) 상속 관계가 있는 예외 클래스들은 multi-catch 블록에서 사용할 수 없음.
가능한 예: catch (ArithmeticException | NumberFormatException e)
컴파일 에러: catch (ArithmeticException | Exception e)

 

<ExceptionMain05.java>

import java.util.Scanner;

public class ExceptionMain05 {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		try {
			System.out.print("x = ");
			int x = Integer.parseInt(sc.nextLine());
			
			System.out.print("y = ");
			int y = Integer.parseInt(sc.nextLine());
			
			System.out.print("x / y = " + (x / y));
			
//			int[] array = new int[0]; // 오류를 못잡음.
//			array[0] = 100;
//			System.out.println(array[0]);
			
		} catch (NumberFormatException | ArithmeticException e) {
			System.out.println(e.getMessage());
		}
	}

}

 

 

<ExceptionMain06.java>

public class ExceptionMain06 {

	public static void main(String[] args) {
		// Calculator 타입 객체 생성
		Calculator calc = new Calculator();
		// throws 선언문이 있는 메스드들 중에서,
		// RuntimeException을 상속하는 예외 타입들은 try-catch를 사용하지 않아도 컴파일 에러가 없음.
		// RuntimeException이 아닌 예외 타입들은 반드시
		// (1) try-catch 문장을 사용하거나
		// (2) throws 선언문을 추가해야 함.
		
		// Integer.parseInt(""); //-> 반드시 try-catch를 사용할 필요는 없음.
		
		try {
			int result = calc.divide(100, 0);
			System.out.println(result);
			
		} catch (Exception e) {
			e.printStackTrace();
		}

		System.out.println("main 정상 종료");
	}
}

 

<Calculator.java>

package com.itwill.exception06;

public class Calculator {

	public int divide(int x, int y) throws Exception {
		if (y != 0) {
			return x / y;
		} 	
		throw new Exception("y는 0이 될 수 없음.");
	}
}

 

2. 예외 클래스

JVM은 프로그램을 실행하는 도중에 예외가 발생하면 해당 예외 클래스로 객체를 생성하고 예외 처리 코드에서 객체를 이용할 수 있도록 해준다.

 

<ExceptionMain03.java>

/*
 * 예외 클래스들의 상속 관계:
 * Object
 * |__ Throwable
 * 	   |__ Exception
 * 		   |__ RuntimeException
 *             |__ ArithmeticException, NumberFormatException,NullPointerException, ...
 * catch 블록이 여러개인 경우, 하위 타입의 예외를 먼저 catch하고,
 * 상위 타입의 예외를 나중에 catch 해야 함.
 */

public class ExceptionMain04 {

	public static void main(String[] args) {
		
		try {
		} catch (ArithmeticException e) {
		} catch (Exception e) {
			// 다형성: SuperType car = new SubType();
			// Exception 클래스를 상속하는 모든 종류의 예외를 잡을 수 있음.
		}
		
		// finally: 예외 상황 발생 여부와 상관 없이 항상 실행되는 블록.
		// try 또는 catch 블록에 return 문장이 있어도,
		// finally 블록이 실행된 후에 return 문장이 실행됨.
		
		try {
			int x = 100;
			int y = 0;
			System.out.println("몫 = " + (x / y));
			System.out.println("end try");
		} catch (Exception e) {
			System.out.println(e.getMessage());
			System.out.println("end catch");
			return; // main 메서드 종료
		} finally {
			System.out.println("언제 출력될까요?");
		}
		System.out.println("end main");
	}
}