티스토리 뷰

Programming/Java

[Java]예외(Exception)

heyhyo 2018. 7. 11. 14:51

먼저 프로그램에서 오류라는 것은 무엇일까? 오류라는 것은 프로그램이 비정상적으로 종료되거나 잘못된 행동을 하는 경우가 있는데, 이러한 행동들의 원인프로그램 오류(Program Error)라고 한다.




에러



이러한 에러들은 발생 시점에 따라 컴파일 에러런타임 에러로 나눌 수 있다. 컴파일 에러는 말 그대로 컴파일 시에 발생하는 에러이고, 런타임 에러는 실행중에 나타나는 에러이다. 그리고 덧붙여서 논리적 에러가 있는데, 이는 프로그램의 실행에는 문제가 없으나 의도와 다른 행동을 하는 것을 말한다.


컴파일 에러 - 컴파일 시 발생하는 에러

런타임 에러 - 실행중에 발생하는 에러

논리적 에러 - 실행에는 문제가 없으나 의도와는 다른 행동을 하는 것


우리가 프로그래밍을 할 때, 다양한 IDE를 사용하는데 그것은 컴파일 에러를 잡아주는 데 큰 도움이 된다. IDE에서 빨간줄로 잘못된 부분을 보고 고치는 경우가 많다. 이것들은 문법적인 오류를 잡아주는 것이다.


그리고 우리가 프로그램을 실행시키다가 존재하지 않는 주소를 참조하거나, 메모리가 부족해지는 등의 런타임 에러도 흔히 볼 수 있다. 이러한 에러들은 문법상으로는 전혀 문제가 없지만, 실행중에 발생하게 된다. 또한 아무런 오류가 존재하지 않지만, 이상한 동작을하는 경우가 논리적 에러인데, 이러한 에러를 잡기 위해서 '디버깅(Debugging)'을 하는 것이다.



런타임 에러의 두가지 종류



자바에서는 런타임 에러를 두가지로 구분하는데, 발생하게 되면 치명적이여서 복구할 수 없는것을 '에러'라고 부른다. 그리고 발생하더라도 수습이 가능한 것을 '예외'라고 한다.


에러 - 프로그램 코드로 수습이 불가능한 치명적인 에러

예외 - 프로그램 코드로 수습이 가능한 상대적으로 작은 에러


아래의 오류의 클래스 계층구를 확인하면서 자세히 알아보자.




예외 클래스 계층구조





클래스 구조를 보면 가장 상위에 Object 클래스의 상속을 받은 Throwable 클래스 아래에 크게 두 클래스가 있는데, 예외 클래스에러 클래스이다. 우리가 주목해야할 클래스는 예외가 모여있는 Exception 클래스이다. 우리가 프로그래밍 적으로 해결해야할 부분이 이 클래스에 존재하기 때문이다.


여기서 예외가 두가지로 나뉘어 지는데, Checked ExceptionUnchecked Exception으로 나눠진다.



RuntimeException 클래스(Unchecked Exception)


이 클래스의 자식 클래스들은 프로그래머의 실수로 발생할 수 있는 예외 클래스들이다. 이들은 Unchecked Exception이라고 부른다. 왜나하면 컴파일 시 이 예외를 처리해주지 않아도 컴파일이 잘 되기 때문이다. 이러한 예외는 예상할 수 없어서 실행중에 특정한 조건에서 발동하기에 컴파일 시에 확인이 어렵다. 0으로 나누는 상황이나 null값을 참조하려는 상황 등이 있다. 그래서 컴파일 시 확인을 거치지 않는 예외인 것이다.


ex) ArithmeticException(0나누기), NullPointerException(null값 참조)



Exception 클래스(Checked Exception)


RuntimeException클래스를 제외한 나머지 자식 클래스들은 주로 사용자의 실수에 의해서 발생하는 예외이다. 잘못된 입력값, 파일 경로의 잘못된 설정 등이 이에 속한다. 이들은 예외를 반드시 처리해 줘야하는 것이다. 이런 예외를 Checked Exception이라고 한다. 이들은 예외를 처리하지 않으면 컴파일 단계에서 오류가 난다.


ex) FileNotFoundException(파일을 찾을 수 없음), DataFormatException(입력 데이터 포멧이 잘못됨)




예외처리



그렇다면 이러한 예외를 코드상에서 처리를 해줘야 한다는 것인데, 어떠한 방법으로 처리할 수 있을까?


1. try-catch


아래의 코드를 통해 간단하게 알아보도록 하겠다.


<코드>

public class ExceptionTest {

	public static void main(String[] args) {
		try {
			// 예외 발생 가능성 코드
			double n = 10/0;
		} catch (Exception e) {
			// 예외 발생 처리 코드
			System.out.println(e.toString());
		} finally {
			// 예외 발생과 상관없이 언제나 실행되는 코드
			System.out.println("언제나 실행");
		}
	}

}



<결과>

java.lang.ArithmeticException: / by zero
언제나 실행



일단 구조부터 알아보도록 하자


try


이 안에는 예외가 발생할 가능성이 있는 코드가 들어가게 된다. 이 안에서 예외가 발생하면 예외가 존재하는 catch 문으로 이동하게 된다.


catch


try안의 코드에서 예외가 발생했다면 해당하는 예외를 처리하는 catch 문으로 이동하여 조치를 취하게 된다.


finally


여기는 예외가 발생하던 발생하지 않던 언제나 실행되는 구간이다. 일반적으로 파일 IO 처리를 할 때, 파일이 열려있는 상태로 프로그램이 종료되는 것을 막기 위하여 여기서 파일을 정상적으로 닫아주는 역할로 많이 쓰인다.


위 코드에서 0으로 나누는 시도를 하였다. 이 시도는 try 문 안에서 시행되어 예외가 발생하게 된다. 그리고 그 예외를 처리하기 위해 catch 문으로 이동하게 되고, catch 문에서는 그 예외가 어떤 예외인지 출력하고 종료된다. 그리고 마지막으로 finally 문으로 가서 실행을 마치고 종료된다.


여기서 ArithmaticException이라는 것은 0으로 나누는 시도를 했을 때의 예외이다. 그리고 예외가 발생하지 않았더라도 '언제나 실행'이라는 문자열은 언제나 출력될 것이다.



2. throws


이 역시 코드로 살펴보자.


<코드>

public class ExceptionTest {

	public static void main(String[] args) {
		try {
			// 예외 발생 가능성 코드
			makeException();
		} catch (ArithmeticException e){
			// 예외 발생 처리 코드1
			System.out.println(e.toString());
		} catch (Exception e) {
			// 예외 발생 처리 코드2
			System.out.println(e.toString());
		} finally {
			// 예외 발생과 상관없이 언제나 실행되는 코드
			System.out.println("언제나 실행");
		}
	}
	
	public static void makeException() throws Exception {
		throw new Exception();
	}
}



<결과>

java.lang.Exception
언제나 실행


makeException메소드는 throws를 통해 자신이 호출되었던 부모 메소드에게 예외를 던지는 것을 볼 수 있다. 저렇게 함수에서 예외를 부모에게 던지는 방법이 있다. 이렇게 되면 부모 메소드에게 던져서 부모의 try-catch 문으로 도달하여 던져진 예외를 받아서 처리하는 형식으로 구동될 수 있다.


여기서 하나 참고할 부분은 런타임 에러는 throws를 하지 않아도 자동으로 던져진다는 것이다. 




참고



Java의 정석 - 남궁성

http://history1994.tistory.com/10?category=668240

http://www.nextree.co.kr/p3239/

http://sleepyeyes.tistory.com/

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함