[JAVA] 예외 처리

AI 개발자 웅이·2022년 7월 17일
0

Java

목록 보기
11/11

오류(error)는 컴파일 오류와 실행 오류로 나뉜다.

컴파일 오류(compile error): 프로그램 코드 작성 중 발생하는 문법적 오류
실행 오류(runtime error): 실행 중인 프로그램이 의도하지 않은 동작을 하거나(bug) 프로그램이 중지되는 오류

실행 오류 발생 시 비정상 종료는 서비스 운영에 치명적이므로, 오류가 발생할 수 있는 경우에 로그(log, 기록)를 남겨 추후 이를 분석하여 원인을 찾아야 한다. 자바는 예외 처리를 통하여 프로그램의 비정상 종료를 막고 로그를 남길 수 있다.

오류와 예외 클래스

시스템 오류(error): 가상 머신에서 발생하며 프로그래머가 처리할 수 없는 오류
ex) 동적 메모리가 없는 경우, 스택 오버 플로우 등
예외(Exception): 프로그램에서 제어할 수 있는 오류
ex) 읽어 들이려는 파일이 존재하지 않는 경우, 네트워크 연결이 끊어진 경우

예외 클래스의 종류

모든 예외 클래스의 최상위 클래스는 Exception이다. 아래와 같이 다양한 예외 클래스가 제공된다. (아래 이미지에서는 예외 클래스 중 일부만을 보여준다.)

또한, JDK에서 제공되는 예외 클래스 외에 사용자가 필요에 의해 예외 클래스를 정의하여 사용할 수 있다. 기존 JDK 예외 클래스 중 가장 유사한 클래스에서 상속하는 형태로 정의할 수 있는데, 기본적으로 Exception에서 상속해도 된다.

사용자 정의 예외 클래스

public class IDFormatException extends Exception {
	public IDFormatException(String message) {
		super(message);
	}
}

사용자 정의 예외 클래스 활용 예제

public class IDFormatTest {

	private String userID;
	public String getUserID() {
		return userID;
	}

	public void setUserID(String userID) throws IDFormatException {

		if (userID == null) {
			throw new IDFormatException("아이디는 null일 수 없습니다.");
		} else if (userID.length() < 8 || userID.length() > 20) {
			throw new IDFormatException("아이디는 8자 이상 20자 이하로 쓰세요.");
		}
		this.userID = userID;

	}

	public static void main(String[] args) {

		IDFormatTest idFormatTest = new IDFormatTest();
		String userID = null;

		try {
			idFormatTest.setUserID(userID);
		} catch (IDFormatException e) {
			System.out.println(e);
		}
		
		userID = "abcdefg";
		try {
			idFormatTest.setUserID(userID);
		} catch (IDFormatException e) {
			System.out.println(e.getMessage());
		}
		
	}

}

출력 결과

메서드 'setUserID'에서 throw 명령어로 예외를 발생시키고, 해당 메서드에서는IDFormatException이 발생하지 않도록 throws 명령어를 통해 예외 발생을 지연시켰다. try-catch문에 대한 내용은 아래 활용 예제를 통해 알아보자.

예외 처리 활용 예제

try-catch-finally

try-catch문은 기본적으로 try{} 블록이 실행될 때 (catch에서 parameter로 받은 것과 같은) 에러가 나면 catch{} 블록이 실행되며 코드 실행이 중단되지 않도록 만드는 역할을 한다. 또한 뒤에 finally 명령어를 붙여주면 try{} 블록 -> finally{} 블록 -> (try{} 블록에서 에러가 난다면) catch{} 블록 순으로 실행된다.

아래는 파일을 불러올 때 try-catch-finally를 활용하여 예외 처리한 예제이다.

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

public class FileInputStreamTest {

	public static void main(String[] args) {
    
		FileInputStream fileInputStream = null;

		try {
			fileInputStream = new FileInputStream("c.txt");
		} catch (FileNotFoundException e) {
			System.out.println(e);
		} finally {
			try {
				fileInputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			System.out.println("finally");
		}
		System.out.println("end");
	}
}

try-with-resources

try-with-resources문은 리소스(file)를 자동 해제하도록 제공해주는 구문이다. 예를 들어 위 예제에서 close()를 명시적으로 호출하지 않아도 try{}블록에서 열린 리소스가 정상인 경우와 예외가 발생한 경우 모두 자동 해제된다. 이 구문을 사용하기 위해서는 해당 리소스에 AutoCloseable가 구현되어(implements) 있어야 한다. 예를 들어 FileInputStream 자바 내장 리소스 입력 클래스의 경우 AutoCloseable을 구현하고 있다.

아래는 파일을 불러올 때 try-with-resources문을 활용하여 예외 처리한 예제이다.

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

public class AutoClosableTest {

	public static void main(String[] args) {

		try (FileInputStream fileInputStream = new FileInputStream("a.txt")) {

		} catch (IOException e) {
			System.out.println(e);
		}
		System.out.println("end");
	}
}

또한, AutoClosable을 구현한 클래스를 직접 정의하여, 예외 처리 시 try-with-resources문에서 활용한 예제이다.

public class AutoCloseObj implements AutoCloseable {

	@Override
	public void close() throws Exception {
		System.out.println("close()");
	}
}
public class AutoCloseTest {

	public static void main(String[] args) {

		AutoCloseObj obj = new AutoCloseObj();

		try (obj) {
			throw new Exception();
		} catch (Exception e) {
			System.out.println(e);
		}
	}
}

출력 결과

try{} 블록에서 에러가 나도, close()가 먼저 실행되는 모습이다.

throws

앞서 언급했듯이 throws를 활용하여 특정 method에서 특정 에러 발생을 지연시킬 수 있다.

아래는 throws를 활용하여 메서드에서 에러를 지연시키고, 실행 코드에서 한번에 예외처리를 하는 방식으로 코드를 작성한 예제이다.

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

public class ThrowsException {

	public Class loadClass(String fileName, String className) throws FileNotFoundException, ClassNotFoundException {
		FileInputStream fls = new FileInputStream(fileName);
		Class c = Class.forName(className);
		return c;
	}

	public static void main(String[] args) {

		ThrowsException exception = new ThrowsException();
		try {
			exception.loadClass("b.txt", "java.lang.string");
		} catch (FileNotFoundException e) {
			System.out.println(e);
		} catch (ClassNotFoundException e) {
			System.out.println(e);
		} catch (Exception e) {
			System.out.println(e);
		}
		System.out.println("end");
	}
}
profile
저는 AI 개발자 '웅'입니다. AI 연구 및 개발 관련 잡다한 내용을 다룹니다 :)

0개의 댓글