[Java] 예외처리(exception handling)-1

wnajsldkf·2022년 5월 22일
0

Java

목록 보기
1/19
post-thumbnail

1. 프로그램 오류

프로그램이 실행 중 어떤 원인에 의해서 오작동 하거나 비정상적으로 종료되는 경우, 결과를 초래하는 원인을 프로그램 에러 또는 오류라고 한다.

  • 컴파일 에러: 컴파일 시에 발생하는 에러
  • 런타임 에러: 실행 시에 발생하는 에러
  • 논리적 에러: 실행은 되지만, 의도와 다르게 동작하는 것(ex. 개수가 음수가 나올 때)

컴파일이 성공적으로 마쳤다고 해서 프로그램의 실행 시에도 에러가 발생하지 않은 것은 아니다. 프로그램이 실행 중 동작을 멈추거나, 종료되는 경우처럼 런타임 에러가 발생할 수 있다.

런타임 에러를 방지하기 위해서는 프로그램 실행도중 발생할 수 있는 경우의 수를 고려하여 대비를 하는 것이 필요하고, 자바에서는 실행 시(runtime) 발생할 수 있는 프로그램 오류를 '에러(error)'와 '예외(exception)'으로 구분한다.

  • 에러(error): 프로그램 코드에 의해서 수습될 수 없는 심각한 오류
    ex: 메모리 부족(OutOfMemoryError), 스택오버플로우(StackOverflowError)
  • 에외(exception): 프로그램 코드에 의해서 수습될 수 있는 다소 미양한 오류

2. 예외 클래스의 계층 구조

출처: TCP 스쿨

모든 클래스의 조상은 Object 클래스이므로 Exception과 Error 클래스도 Object 클래스의 자손이다.
예외 클래스는 두 그룹으로 나눌 수 있다.

  1. Exception 클래스와 그 자손들
  2. RuntimeException 클래스와 그 자손들
  1. Exception 클래스
    외부의 영향으로 발생할 수 있는 것들로 프로그램의 사용자들의 동작에 의해서 발생하는 경우가 많다.
    • FileNotFoundException: 존재하지 않는 파일의 이름을 입력한 경우
    • ClassNotFoundException: 실수로 클래스의 이름을 잘못 적은 경우
    • DataFormatException: 입력한 데이터 형식이 잘못된 경우
  1. RuntimeException 클래스
    프로그래머의 실수에 의해서 발생될 수 있는 예외들을 말한다.
    • ArrayIndexOutOfBoundsException: 배열의 범위를 벗어난 경우
    • NullPointerException: 값이 null인 참조변수의 멤버를 호출하는 경우
    • ClassCastException: 클래스간의 형변환을 잘못한 경우
    • ArithmeticException: 정수를 0으로 나누는 경우

3. 예외처리하기: try-catch문

예외처리란?

  • 정의: 프로그램 실행 시 발생할 수 있는 예외에 대비한 코드를 작성하는 것
  • 목적: 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것

발생한 예외를 처리하지 못하면, 프로그램은 비정상적으로 종료된다. 처리되지 못한 예외(uncaught exception)는 JVM의 '예외처리기(UncaughtExceptionHandler)'가 받아서 예외의 원인을 화면에 출력한다.

try-catch 문 구조

try{
	예외가 발생할 가능성이 있는 문장
} catch (Exception1 e1){
	// Exception1이 발생했을 경우, 처리하기 위한 문장 작성
} catch (Exception2 e1){
	// Exception2가 발생했을 경우, 처리하기 위한 문장 작성
}

4. try-catch문의 흐름

try-catch문에서, 예외가 발생한 경우와 발생하지 않았을 때의 흐름(문장의 실행순서)이 달라진다.

try 블럭 내에서 예외가 발생한 경우
1. 발생한 예외와 일치하는 catch 블럭이 있는지 확인한다.
2. 일치하는 catch 블럭을 찾으면, 블럭 내의 문장들을 수행하고 전체 try-catch문을 빠져나가서 그 다음 문장을 계속해서 수행한다. 일치하는 catch 블럭을 찾지 못하면, 예외는 처리되지 못한다.

try 블럭 내에서 예외가 발생하지 않은 경우
1. catch 블럭을 거치지 않고 전체 try-catch문을 빠져나가서 수행을 계속한다.

class Exception{
	public static void main(String args[]){
    	System.out.println(1);
        System.out.println(2);
        try{
        	System.out.println(3);
            System.out.println(0/0);	// 0으로 나눠서 고의로 ArithmeticException을 발생시킨다.
            System.out.println(4);		// 실행되지 않는다.
        } catch(ArithmeticException ae){
        	System.out.println(5);
        }	// try-catch 끝!
        System.out.println(6);
     }	// main 메서드 끝!
}
실행 결과
1
2
3
5
6

5. 예외의 발생과 catch블럭

예외가 발생하면, 발생한 예외에 해당하는 클래스의 인스턴스가 생성된다.

class Exception{
	public static void main(String args[]){
    	System.out.println(1);
        System.out.println(2);
        try{
        	System.out.println(3);
            System.out.println(0/0);	// 0으로 나눠서 ArithmeticException 발생
            System.out.println(4);		// 실행되지 않음
        }catch(ArithmeticException ae){
        	if(ae instanceof ArithmeticException){
            	System.out.println("true")
            System.out.println("ArithmeticException");
        }catch(Exception e){			// ArithmeticException을 제외한 모든 예외가 처리됨
        	System.out.println("Exceptin");
        }	// try-catch의 끝
        System.out.println(6);
	}	// main 메서드의 끝
}
실행 결과
1
2
3
true
ArithmeticException
6

첫 번째 검사에서 일치하는 catch 블럭을 찾았기 때문에 두 번째 catch 블럭은 검사하지 않는다. 만일 ArithmeticException이 아닌 다른 종류의 예러가 발생했다면 두 번째 catch 블럭에서 처리되었을 것이다.

printStackTrace()와 getMessage()

예외가 발생했을 때 생성되는 예외 클래스와 인스턴스에는 예외에 대한 정보가 담겨있고, 위 명령어를 통해 정보들을 얻을 수 있다.

  • printStackTrace(): 예외발생 당시의 호출스택(Call Stack)에 있었던 메서드의 정보와 예외 메시지를 화면에 출력한다.
  • getMessage(): 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.

멀티 catch 블럭

여러 catch 블럭을 | 기호를 이용해서, 하나의 catch 블럭으로 합칠 수 있다.

여러 catch 블럭을 사용하는 경우
중복된 코드가 발생한다.

try{
	...
} catch(ExceptionA e1){
	e1.printStackTrace();
} catch(ExceptionB e2){
	e2.printStackTrace();
}

멀티 catch 블럭
중복된 코드를 줄일 수 있다.

try{
	...
} catch (ExceptionA | ExceptionB e){
	e.printStackTrace();
}

만일 멀티 catch 블럭의 | 기호로 연결된 예외 클래스가 조상과 자손의 관계에 있다면 컴파일 에러가 발생한다. 조상 클래스가 자손 클래스를 포함하기 때문에 불필요한 코드는 제거하라는 의미이다. 다음과 같이 부모 클래스만 써주면 된다.

try{
	...
}catch(ParentException e){
	e.printStackTrace();
}

멀티 catch는 하나의 catch블럭으로 여러 예외를 처리하므로, 발생한 예외를 멀티 catch 블럭으로 처리했을 때 실제로 어떤 예외가 발생한 것인지 알 수 없다. 따라서 예외 클래스들의 공통 분모인 조상 예외 클래스에 선언된 멤버만 사용할 수 있다. 필요하다면 instanceof로 어떤 예외가 발생한 것인지 확인하고 처리할 수 있다.

try{
	...
}catch(ExceptionA | ExceptionB e){
	e.methodA();		// 에러. ExceptionA에 선언된 methodA() 호출 불가
    
    if(e instanceof ExceptionA){
    	ExceptionA e1 = (ExceptionA)e;
        e1.methodA();	// OK. ExceptionA에 선언된 메서드 호출 가능
    }else{	// if(e instanceof ExceptionB)
    	...
    }
    e.printStackTrace();
}    

6. 예외 발생시키기

throw 키워드를 사용해서 프로그래머가 고의로 예외를 발생시킬 수 있다.

  1. 키워드 new를 이용해서 발생시키려는 예외 클래스의 겍채를 만든다.
    Exception e = new Exception("고의로 발생시켰음");
  2. 키워드 throw를 이용해서 예외를 발생시킨다.
    throw e;
Reference
profile
https://mywnajsldkf.tistory.com -> 이사 중

0개의 댓글