본문 바로가기

개발지/Today I learn

[0809] 자바 컬렉션 3 (예외 처리)

#예외 처리

: 프로그램의 비정상적인 종료를 방지, 정상적인 실행 상태를 유지하기 위한 코드.

-에러 발생 원인 

(1) 내부적 요인

: 코드 작성 오류... 등

(2) 외부적 요인

: 메모리 공간 부족 ... 등

 

#컴파일 에러와 런타임 에러

(1) 컴파일 에러

- 컴파일 할 때 발생하는 에러

- 자바 컴파일러가 오류를 감지하여 사전에 사용자에게 알려준다.

- 상대적으로 발견하기 쉽고, 해결 가능

 

(2) 런타임 에러

- 런타임 시 발생하는 에러

- 컴퓨터가 수행할 수 없는 특정한 작업을 요청할 때 발생

 

#예외 클래스의 상속 계층도

(1) 일반 예외 클래스(Exception)

- 실행 예외 클래스를 제외한 모든 Exception 클래스와 그 하위 클래스.

- checked 예외라고 부르기도 함. (컴파일러가 코드 실행 전에 예외 처리 코드 여부 검사)

- 주로 잘못된 클래스명과 데이터 형식 등의 사용자의 실수로 발생한다.

 

(2) 실행 예외 클래스(Runtime Exception)

- 런타임 시 발생하는 RuntimeException 클래스와 그 하위 클래스.

- unchecked 예외 (컴파일러가 예외 처리 코드 여부를 검사하지 않음)

- 클래스 간 형변환 오류(ClassCastException), 벗어난 배열 범위 지정(ArrayIndexOutOfBoundsException) 등의 자바 문법 요소와 관련이 있다.

 

#예외를 처리하는 방법

1. try - catch문

- 정상 실행을 유지하기 위해 작성하는 코드

- 기본 구조는 아래와 같다.

try {
	// 예외가 발생할 가능성이 있는 코드 삽입
}
catch (ExceptionType1 e1) {
	// ExceptionType1 유형의 예외 발생 시 실행할 코드
}
catch (ExceptionType2 e2 {
	// ExceptionType2 유형의 예외 발생 시 실행할 코드
}
finally {
	// finally 블록은 옵셔널
	// 예외 발생 여부와 상관없이 항상 실행
}

- try 블록 안에는 예외 발생 가능성이 있는 코드 입력

- catch 블록은 예외 발생 시 실행되는 코드. 여러 종류의 예외 처리 가능

*예외 처리 try-catch 문 예제

public class RuntimeExceptionTest {
	public static void main(String[] args) {
    
		try {
			System.out.println("[대문자 알파벳을 소문자로 출력하는 프로그램]");
			printMyName(null); // (1) 예외 발생
			printMyName("ABC"); // (1)에서 이미 catch문으로 이동해 실행되지 않음
		}
		catch (ArithmeticException e) {
			System.out.println("ArithmeticExcpetion 발생!"); // (2) 첫 번째 catch문은 해당 X
		}
		catch (NullPointerException e) { // (3) 두 번째 catch문
			System.out.println("NullPointerException 발생!");
			System.out.println("e.getMessage: " + e.getMessage()); // (4) 예외 정보 1
			System.out.println("e.toString: " + e.toString()); // (4) 예외 정보 2
			e.printStackTrace(); // (4) 예외 정보 3
		}
		finally {
			System.out.println("[프로그램 종료]");
		}
	}
    
    static void printMyName(String str) {
		String lowerCaseAlphabet = str.toLowerCase();
		System.outprintln(lowerCaseAlphabet);
	}
}

// 출력값
NullPointerException 발생!
e.getMessage: null
e.toString: java.lang.NullPointerException
[프로그램 종료]
java.lang.NullPointerException
	at RuntimeExceptionTest.printMyName(RuntimeExceptionTest.java:20)
	at RuntimeExceptionTest.main(RuntimeExceptionTest.java:7)

- 코드 안 (1)에서 발생한 예외는 첫 번째 catch문을 지나 두 번째 catch문의 조건에 일치하므로 (3)의 코드가 실행된다.

- (3)에서 에러에 대한 정보를 얻는 방법은 3가지가 존재한다.

 

2. 예외 전가 

- try-catch문과 다르게 예외를 호출한 곳으로 다시 떠넘기는 방법.

- 메서드의 선언부 끝에 throws 키워드와 발생할 수 있는 예외들을 나열한다.

반환타입 메서드명(매개변수, ...) throws 예외클래스1, 예외클래스2, ... {
	...
}

void ExampleMethod() throws Excetpion {
}

- Exception 클래스는 모든 예외 클래스의 상위 클래스이므로 그 하위 클래스 타입의 예외 클래스를 모두 포함한다.

public class ThrowExceptionTest {
    public static void main(String[] arges) {
        try {
            throwException();
        } catch (ClassNotFoundException e) {
            System.out.println(e.getMessage());
        }
    }
    
    static void throwException() throws ClassNotFoundException, NullPointException {
        Class.forName("Java.lang.StringX");
    }
}
//출력값
java.lang.StringX

- throws 키워드를 사용해 예외를 발생한 해당 메서드내가 아닌 메서드가 호출한 곳으로 다시 떠넘기고 있음.

- 예외 처리의 책임이 throwException 메서드가 아닌 main 메서드가 지게 되었다.

 

#예외를 의도적으로 발생시키기

-throw 키워드를 사용하면 의도적으로 예외를 발생시킬 수 있다.

public calss ExceptionTest {
    public static void main(String[] args) {
        try {
            Exception intendedException = new Exception("의도된 예외 만들기");
            throw intendedException;
        } catch (Exception e) {
            System.out.println("고의로 예외 발생시키기 성공!");
        }
    }
}

//출력값
고의로 예외 발생시키기 성공