예외

고재석·2021년 5월 20일
0

Java는 기본!

목록 보기
6/12
post-thumbnail
post-custom-banner

예외란?

예외(Exception)란 무엇일까? 사용자의 잘못된 조작이나 개발자의 잘못된 코딩으로 발생하는 프로그램 오류를 말한다. 예외가 발생하면 프로그램은 바로 종료된다. 하지만 예외 처리를 해줌으로써 프로그램이 종료되지 않고 다른 동작을 하게끔 할 수 있다.

Exception의 종류

checked exception

공식문서에 따르면 Exception과 그 하위 클래스들은 Throwable의 하위 클래스이며, 합리적인 애플리케이션이라면 catch하고 싶어하는 조건들을 명시한다고 한다.
즉, 예외적인 상황이 발생해서 프로그램 오류가 발생하는 경우 Exception이 발생하게끔 특정 조건들이 명시되어있다는 뜻이다.

그리고 RuntimeException을 제외한 모든 하위 클래스와 Exception 클래스는 checked exceptions로 표현한다. 만약 메소드나 생성자의 실행으로 checked exception이 throw 될 수 있거나 그 범위 밖으로 전달될 수 있는 경우에, checked exception은 메소드나 생성자의 throws 절에 선언되어야한다고 한다.
즉, 예외가 발생되는 경우 throw 절에 exception class를 명시해서 예외를 날려주어야한다는 뜻이다.

unchecked exception

RuntimeException은 JVM의 실행 도중에 발생될 수 있다고 한다.

그리고 RuntimeException과 그 하위 클래스들을 unchecked exceptions로 표현한다. checked exception과 반대로 예외가 발생되는 경우 예외를 날려주지 않아도 된다고 한다.


자주 발생하는 unchecked exception의 종류

NullPointerException

인스턴스의 참조 값에 null이 들어가는 경우 .를 사용한 경우에 발생한다.

IndexOutOfBoundsException

배열에서 인덱스 범위를 초과하여 사용한 경우에 발생한다.

NumberFormatException

문자열을 숫자도 변환하는 과정에서 숫자로 변환이 안되는 문자열이 포함된 경우에 발생한다.

ClassCastException

상속/구현 관계의 클래스가 아닌 클래스끼리 타입을 변환하고자하는 경우에 발생한다.


예외 처리 코드

이와 같이 예외가 발생한 경우에 어떤 식으로 처리해주어야 할까? 보통은 try-catch-finally 블록을 이용한다.위의 그림과 같이 catch문 안에 예외가 발생할 경우 실행할 코드를 입력하면 된다.

try {
     StringBuilder sb = null;
     System.out.println(sb.toString());
}

catch(NullPointerException e){
     System.out.println("NullPointerException 발생!!");
}

finally{
     System.out.println("---end---");
}

따라서 위와 같은 코드를 작성하면

NullPointerException 발생!!
---end---

이와 같은 결과 값이 출력될 것이다.


catch문 활용

try-catch-finally 블록에서는 catch문을 여러 개 선언하여 다양한 예외에 대해 각각 알맞은 처리를 명시할 수 있다. 하지만 여기서 주의해야할 부분이 있다.

catch문은 위에서부터 순서대로 실행된다. 상위 클래스의 Exception이 제일 위에 있다면 하위 클래스의 Exception이 발생했을 때에도 위에 있는 catch문에 걸려 아래의 catch문까지 도달하지 못한다. 따라서 아래의 코드와 같이 Exception의 순서를 하위 -> 상위 순으로 나열해야한다.

또한 하나의 catch문 안에 여러 개의 예외를 처리할 수도 있다. 처리할 예외들을 | 로 묶어서 명시하면 된다.

try {
     StringBuilder sb = null;
     System.out.println(sb.toString());
}

catch(NullPointerException | IndexOutOfBoundsException e){
     System.out.println("NullPointerException or IndexOutOfBoundsException 발생!!");
}

catch(Exception e){
     System.out.println("Exception 발생!!");
}

finally{
     System.out.println("---end---");
}

자동 리소스 닫기

try-with-resources를 사용하면 사용했던 resource 객체를 자동으로 닫아준다.

이게 무슨 말이냐면 기존의 try-catch-fianlly 문법에서 try 블록에서 사용하던 리소스 객체(스트림, 소켓 등)를 finally 블록에서 close() 해주어 리소스 관리를 하게끔 했었다. 이 때 close 메소드도 예외처리가 되어야 하기 때문에 finally 블록 안에 다시 try-cath-finally 문이 같이 입력되곤 했었다.

하지만 try-with-resources는 이와 같이 번거롭고 코드가 지저분해지는 작업을 줄여준다.

try(FileInputStream fis = new FileInputStream("file.txt")) {
...
}

catch(IOException e){
...
}

이와 같이 오히려 finally 블록을 없애버릴 수도 있다. try 블록이 실행이 완료되거나 예외가 발생하면 자동으로 close 메소드가 호출되고 그 이후에 catch나 finally블록이 실행된다.


throw 절 활용

throw는 예외를 떠넘기기 위한 문법이다. try-catch-finally처럼 예외를 직접 처리해주는 것이 아니라 메소드나 생성자를 호출한 곳에서 처리하게끔 하는 것이다.

예를 들어 main 메소드가 A 메소드를 호출해서 예외가 발생했다. 이 때 A 메소드는 이 예외를 throw했다. 그렇다면 이 예외는 main 메소드에서 처리해주어야 하는 것이다. 그렇다면 main 메소드에서 throw하면 어떻게 될까? 그렇다면 결국 JVM이 예외를 처리해주어 콘솔에 예외 정보를 찍어준다.


public static void main(String[] args) throws ClassNotFoundException {
	findClass();
}

public static void findClass() throws ClassNotFoundException {
	Class cls = Class.forName("java.lang.String2");
}
profile
명확하게 말하고, 꼼꼼하게 개발하자
post-custom-banner

0개의 댓글