▸JAVA/기본 문법

예외(Exception) 처리하기_'try-catch-finally'문 [2/5]

코데방 2019. 12. 12.
728x90

[ try-catch-finally ]

  • 예외 처리를 위한 가장 기본적인 문법
  • try : 실제 내용을 실행
  • catch : 예외 시 어떻게 처리할 것인지 결정
  • finally : 실제 내용에서 마무리해야할 내용이 있다면 마지막에 처리

 

[ try-catch 구문 ]

기본 문법은 간단합니다. 먼저 미확인 예외에 대한 예외 처리를 간단하게 샘플로 들어보겠습니다. 사실 코드를 잘 짰다면 배열의 인덱스를 검색하는 과정에서 예외가 발생하지 않겠지만 예외라는 이름 그대로 생각지도 못하게 발생할 수 있습니다. 아래는 배열의 크기를 넘어서는 인덱스를 사용해 예외가 발생할 경우에 대한 예외 처리입니다.

 

try에 수행할 코드를 작성한 후, catch부분에서 예외처리를 해줍니다. catch( )의 괄호안에는 JVM에서 예외처리 시 생성하는 예외처리 객체를 담아줄 예외처리클래스의 타입과 변수를 지정해줍니다. 메소드의 매개변수와 같은 개념입니다. JVM에서 생성한 예외처리 객체와 catch 매개변수의 타입이 다를 경우 예외 처리를 할 수 없어 프로그램이 종료됩니다. 따라서 catch 구문은 여러 개를 사용할 수 있고 발생 가능한 모든 예외에 대해 처리해줄 수 있어야 합니다.

 

그냥 예외 발생 시 예외 처리만 하면 되는 것을 굳이 이렇게 복잡하게 만들어둔 이유는 예외 발생 종류에 따라 다른 catch문의 내용을 실행하도록 하기 위함입니다. 어떤 예외가 발생하던지 같은 로직으로 처리하고 싶다면 매개변수 타입을 가장 상위의 상속 클래스인 Exception 타입으로 지정해주면 됩니다. 아래쪽에서 한번 더 다루겠습니다.

 

 

package study.first;

public class Main {
	public static void main(String[] args) {

		int[] arr = { 1, 2, 3, 4, 5 };

		try {
			
			System.out.println(arr[5]);

		} catch (ArrayIndexOutOfBoundsException indexO) {

			System.out.println("인덱스를 벗어났습니다.");
		
		} catch (NullPointerException nullp) {
			
			System.out.println("널 포인트 예외가 발생했습니다. ");
		}
	}
}

 


위에서 언급한 바와 같이 발생한 예외를 종류별로 달리 처리하지 않고 한번에 처리하고 싶다면, 아래와 같이 Exception클래스 타입으로 예외를 받아주면 됩니다. 가장 상위의 부모 클래스이기 때문에 모든 예외 클래스가 오버라이딩이 가능합니다.

 

주의할 점은 catch문의 매개변수로 Exception 타입을 사용할 때 가장 마지막에 위치해야 한다는 것입니다. 가장 윗쪽에 Exception타입의 catch문이 존재할 경우 아랫쪽에 다른 catch문이 있어도 도달할 수 없기 때문에 컴파일 단계에서 에러가 납니다. 하지만 위에 다른 타입들의 catch문이 있고 마지막에 Exception타입의 catch문이 오게 된다면, 위에서부터 검색해서 맞는 타입을 찾을 수 없을 경우에만 마지막 catch문에 도달하여 처리하게 됩니다. 어떤 예외가 발생할지에 대해 확신이 없다면 마지막은 Exception 타입의 매개변수를 가진 catch문을 붙여두는 것도 좋은 방법입니다.

 

package study.first;

public class Main {
	public static void main(String[] args) {

		int[] arr = { 1, 2, 3, 4, 5 };

		try {
			System.out.println("예외처리 발생전..!");
			System.out.println(arr[5]);

		} catch (NullPointerException nullp) {

			System.out.println("널포인터 예외처리!");

		} catch (Exception indexO) {

			System.out.println("Exception 타입의 catch문에 도달!");

		} finally {

			System.out.println("파이널리!!");
		}
	}
}

 


 

[ try-catch-finally 구문 ]

try구문을 수행하다 예외가 발생해서 catch문에서 예외 처리 후 종료된 경우, 예외 발생에 관계 없이 try문과 한 쌍으로 수행될 수 있도록 해주는 것이 finally문입니다. 굳이 finally를 사용하지 않고 아랫쪽에 코드를 작성해서 무방하지만 가독성을 위해 한 쌍으로 작성할 수 있도록 해줍니다. try에서 열어둔 자원(파일 등)을 해제해주는 코드를 넣을 때 많이 사용됩니다.

 

주의할 점은, try-catch-finally문은 각각 대괄호로 묶여 있기 때문에 서로 다른 스택 프레임을 가지게 됩니다. 즉, 지역 변수의 공유가 되지 않습니다. 따라서 서로 변수 공유를 하기 위해서는 구문 바깥쪽에 변수를 생성해줘야 합니다. 이런 문제점을 해결하기 위한 문법이 다음글에서 다룰 "try-with-resources"문 입니다.

 

그리고 파일 클래스와 같이 "확인된 예외"처리가 필수인 경우, finally 구문 안에서도 try-catch문을 통해 예외처리를 해줘야 컴파일 에러가 나지 않습니다. 파일 입출력 편에서 자세히 다루도록 하겠습니다.

package study.first;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class Main {
	public static void main(String[] args) {

		FileInputStream fi = null;

		try {

			fi = new FileInputStream("a.txt");
			System.out.println(fi); // 무언가 파일을 처리함

			int[] arr = { 1, 2, 3, 4, 5 };
			System.out.println(arr[5]); // 예외 발생 지점

		} catch (IndexOutOfBoundsException i) {

			System.out.println("인덱스를 벗어났습니당");

		} catch (FileNotFoundException f) {

			System.out.println("파일을 열 수 없습니당");

		} finally {

			if (fi != null) {
				try {
					fi.close();
				} catch (IOException io) {

					System.out.println("파일이 닫히질 않습니다...!");
				}
			}
		}
	}
}

 


 

finally 사용을 통한 자원의 해제가 번거롭다면, "try-with-resources"문을 사용해도 됩니다.

2019/12/12 - [JAVA/기본 문법] - 예외(Exception) 처리하기_'try-with-resources'문 [3/5]

728x90

댓글

💲 추천 글