예외 처리

파이 ఇ·2023년 7월 5일
1
post-thumbnail

💡 목표 : 자바의 예외처리에 대해 학습해보자.

⚡️ 목차

  • 자바에서 예외 처리 방법 (try, catch, throw, throws, finally)
  • 자바가 제공하는 예외 계층 구조
  • Exception과 Error의 차이는?
  • RuntimeException과 RE가 아닌 것의 차이는?
  • 커스텀한 예외 만드는 방법

자바에서 예외를 처리하는 이유?

자바에서 예외를 처리하는 방법을 알아보기 이전에 왜 예외 처리를 하는지에 대해 먼저 알아보자. 간단히 말하면 예외적인 상황을 대비하여 미리 안전장치를 하는 것이다. 자바 프로그램에서는 예외 상황이 발생하면, 예외를 발생시킨다. 특히 uncheckedException 같은 예외는 프로그램 실행중에 발생되는 예외인데, 서비스가 정상적으로 운영중 이어도 예외가 발생하면 프로세스가 강제적으로 종료된다. 때문에 프로그램의 안정적인 운영에 있어서 예외는 필수이다. 이러한 예외적인 상황은 예외처리 ExceptionHandling을 통해 프로세스가 강제적으로 종료되지 않고, 예외 상황이 발생해도 운영이 가능하도록 핸들링을 할 수 있다.

자바에서 예외 처리를 하는 방법 try-catch

try-catch는 예외 처리를 할 때, 일반적으로 사용되는 예외 처리 방법이다. try 구문에는 예외 발생 가능성이 있는 문장을 넣어주고, catch 구문에는 try 구문에서 예외가 발생할 시 어떻게 처리할 것인지를 작성한다.

try {
	예외 발생 가능성이 있는 문장
  } catch (예외의 종류) {
  	예외가 발생하면 처리할 문장
  }

✔️ try 블록

  • 예외 발생 가능성이 있는 문장을 묶어준다.

✔️ catch 블록

  • 예외가 발생하면 처리할 문장.
  • 매개변수로는 예외의 종류를 둘 수 있으며, try 블록에서 발생한 예외 메세지나 객체를 인수로 받아 처리한다.
  • catch 블록에 아무런 내용을 작성해주지 않으면 어디서 오류가 발생했는지 파악하기 어렵기때문에, 특수한 상황이 아니라면 항상 로그를 남기도록 하는게 좋다.

예외를 발생시키는 throw와 예외를 떠넘기는 throws 키워드

throw는 예외를 발생시키는 키워드이다. throw는 예외를 강제적으로 발생시켜 상위 블럭이나 catch문으로 예외를 던진다. throws는 예외를 떠넘기는 방법으로 어떠한 메서드를 호출할 때 그 메서드가 throws 키워드로 정의되어 있으면, 해당 메서드는 메서드를 호출한 곳에서 강제적으로 예외를 처리해주어야 한다. 강제적으로 처리하지 않고 throws로 예외를 다시 떠넘겨도 되나, 해당 방법은 그리 좋지 않은 방법이다. 예외를 계속 떠넘기게 된다면 비정상 종료가 되면서 이 예외는 JVM에게 넘겨지게 된다. JVM은 예외를 받아서 JVM 기본 예외 처리기에 의해 마지막으로 처리를 하게 되지만 JVM의 기본 예외 처리기는 넘어온 예외를 처리할 방법이 없기 때문에 결국 오류를 출력한다. 하여 예외 처리가 될 수 있도록 하려면 try catch문으로 처리를 해야한다.

finally, 반드시 실행되어야 하는 문장

finally는 예외 발생 여부와 관계없이 무조건 실행되어야 하는 문장이다. 예외 처리 다음 문장에 수행할 동작을 넣어주면 되는데 왜 굳이 finally를 사용할까? 만약 예외처리를 수행한 메서드 내에서 리턴 값을 받는다고 가정하면, try와 catch문에서 return을 만나게 되고 프로그램은 무조건 중단된다. try 구문 바깥에서 예외 발생 여부와 관계없이 원하는 코드를 작성한다고 한들, 리턴값을 돌려주게 되면 메서드를 빠져나와 실행될 수 없다. 그래서 try catch 구문 내에 동일한 코드를 반복적으로 작성해주어야 하고, 그럼 코드에 중복이 생긴다. 이 때 사용되는 finally 문장은 중복되는 코드를 줄일 수 있다.

try {
	예외가 발생할 수 있는 문장
  } catch (예외의 종류) {
  	예외를 처리하는 문장
    } finally {
      예외가 발생하든 발생하지 않든 무조건 실행한다.
    }

try finally와 try-with-resources

자바 7부터 나온 try-with-resources는 자원을 닫아주는 역할을 한다. try-with-resources 문법을 사용하면 close()를 호출하지 않아도 예외 발생 여부와 관계없이 finally와 같이 반드시 close 메서드가 호출된다. close는 어떤때에 사용될까? 예를 들자면, 네트워크와 데이터베이스와 관련된 작업을 마치고 MaxConnection을 방지하기 위해 finally블록에서 close()를 하여 Connection을 끊을 수 있고, 데이터베이스뿐만 아니라 파일 개수 등과 같이 시스템에서는 허용되는 자원의 한계가 있어 리소스를 계속 열기만 하고 닫지 않는다면 허용되는 자원의 개수를 초과할 수 있으므로 자원 사용이 끝나면 반드시 close를 해줘야 한다. 또한 자바 라이브러리 중에서는 close 메서드를 호출하여 직접 닫아줘야만 하는 자원이 많다. 직접 닫아줘야 하는 자원으로는 입출력 스트림인 InputStream과 OutputStream 그리고 Connection등이 있다. 자원 닫기는 예측할 수 없는 성능 문제로 이어지기도 하기 때문에 사용이 종료되었으면 반드시 닫아주어야 한다. 이러한 자원을 회수 할 때 try finally 블럭을 이용해서 사용한 자원을 회수할 수 있는데, finally는 해당 절 내에서도 Exception이 발생하는 경우가 있다고 한다. 또한 코드가 복잡해지는 경우가 많아 try-with-resources를 사용하여 코드를 더 짧고, 분명해지도록 구현이 가능하여 회수해야 하는 자원을 다룰때는 try-with-resources을 사용하는 것이 좋다. 더 자세한 내용은 참고자료를 확인해보자.

자바가 제공하는 예외 계층 구조를 알아보자

모든 예외의 조상은 java.lang.Throwable 클래스이다. 가장 먼저, 모든 클래스의 최상위 클래스인 Object 클래스를 확장한 모든 예외의 조상 클래스인 Throwable클래스, 그리고 Throwable 클래스를 확장한 Error 클래스와 Exception클래스로 분류할 수 있다. Error클래스는 자바 프로그램 외에서 발생하는 오류이며, Exception클래스는 자바 프로그램 내에서 발생하는 오류이다.

Exception클래스와 Error클래스의 차이는 무엇일까?

Error는 시스템이 비정상적인 상황에서 발생한다. 컴퓨터 하드웨어의 오동작 또는 고장으로 인해 응용프로그램에 이상이 생겼거나 자바 가상 머신(JVM) 실행에 문제가 생겼을 때 발생하는 것이며, 시스템 레벨에서 발생하는 심각한 수준의 오류이기 때문에 예외와 다르게 개발자가 미리 예측할 수도 없고, 애플리케이션 코드에서 잡아서 처리할 수 도 없다. 에러의 예시로는 OutOfMemoryError, ThreadDeath, StackOverflowError등이 있다. Exception은 사용자의 잘못된 조작 또는 개발자의 잘못된 코딩으로 인해서 발생하는 프로그램 오류이다. 입력값에 대한 처리가 불가능하거나, 프로그램 실행 중 참조된 값이 잘못된 경우 등 정상적인 프로그램의 흐름을 벗어나는 것을 이야기한다. 자바에서 예외는 개발자가 예외처리(Exception Handling)를 통해 직접 처리할 수 있기 때문에 예외 상황을 미리 예측하여 핸들링 할 수 있다.

RuntimeException과 RE가 아닌것의 차이

컴파일러가 예외처리를 체크(checkedException)하느냐, 체크하지 않느냐(uncheckedException)의 차이

CheckedException과 UncheckedException

checkedException은 ComplieException이라고도 하며 Exception을 상속 받는다. 컴파일 시점에 예외를 catch하는지 정적으로 확인하며, 만약 컴파일 시점에 예외에 대한 처리를 하지 않는다면 컴파일 에러가 발생한다. 예외가 발생하는 메서드에서 throws 예약어를 사용하여 예외를 호출한 메서드에 전달하는 방법으로도 처리가 가능하다.(ex.FileNotFoundException, ClassNotFoundException, DataFormatException)
uncheckedExceptionRuntimeException을 상속받는다. checkedException과 반대로 컴파일 시점에서 예외를 catch하는지 여부를 확인하지 않는다. 그렇기 때문에 컴파일 시점에서 예외가 발생했는지 여부를 판단할 수 없다.(ex.IndexOutOfBoundsException, NullPointerException, ClassCastException)

public class Main {
	public static void main(String[]args) {
		//checkedException
		try {
				throw new Exception();
		} catch(Exception e) {
				System.out.println("checked Exception은 반드시 예외 처리가 필요하다.");
		}
		//uncheckedException
		throw new RuntimeException("unchecked Exception은 예외 처리가 선택적이다.");
	}
}

checkedException과 uncheckedException예외, 분류를 하는 이유는 무엇일까

만약에 uncheckedException도 컴파일러가 예외를 처리하게 한다면 어떻게 될까? 예를 들어 모든 참조변수는 NullPointerException이 발생할 가능성이 있다. 마찬가지로 모든 배열도 ArrayIndexOutOfBoundsException이 발생할 가능성이 있다. 모든 배열은 범위를 벗어날 가능성이 있고, 모든 참조변수에는 null값이 대입될 수 있다. 만약 컴파일러가 이러한 것들 모두 예외 처리를 강제적으로 하게 한다면, 모든 배열과 모든 참조변수에 예외 처리를 해야만 한다. 즉, 코드는 대부분 데이터를 다루게 되어 있는데, 거의 모든 코드에 try catch 블럭을 매번 넣어야 한다는 것이다. 때문에 uncheckedException으로 분류해서 선택적으로 예외를 처리하게 하는데 이러한 부분들은 프로그래머가 잘 파악하고 예외처리를 해주어야 한다.

커스텀한 예외를 만드는 방법

Custom Exception을 만들 때에는 해당 예외의 특징을 고려하여 extend를 통해 Exception이나 RuntimeException을 상속받아 작성한다. 개인적으로 해당 Exception에 대해 좀 더 명확한 정보 전달을 위해 유사한 표준 에러를 상속받아 좀 더 구체적인 Custom Exception들을 작성하는 것을 추천한다.

public class CustomException extends RuntimeException {
		//1. 매개변수가 없는 기본 생성자
		public CustomException() {}

		//2. 예외 발생 원인(예외 메세지)을 전달하기 위해 String 타입의 매개변수를 갖는 생성자.
		public CustomException(String message) {
				super(message); //RuntimeException 클래스의 생성자를 호출한다.
		}
}
public class Main {
	public static void main(String[]args) {
		
			try {
					test();
			} catch (CustomException e) {
					System.out.println("커스텀 예외 테스트");
					System.out.println(e.getMessage()); // 예외 메세지 가져오기
					e.printStackTrace(); 
					/** printStackTrace() ?
					예외 발생 코드를 추적해서 모두 콘솔에 출력. 어떤 예외가 어디서 터졌는지 상세하게 출력해주기 때문에 
					프로그램 테스트하면서 오류를 찾을때 활용한다. */
			}
	}

	public static void test() throws CustomException {
			throw new CustomException("예외 테스트 입니다.");
	}
}

끝 !


첨 해보는 팀프로젝트때문에 한주 밀렸지만 어쨋든 해낸 나^^..~~
✨🌸💕💛~! ! !긍~살~ ! ! !💘🩵🎶🍑✨🌻

[참조]
https://wildeveloperetrain.tistory.com/107
https://mangkyu.tistory.com/217
https://velog.io/@pearl0725/자바에서-예외를-처리하는-방법#try-finally-와-try-with-resources
https://veneas.tistory.com/entry/Java-커스텀-예외-만들기Custom-Exception

profile
⋆。゚★⋆⁺₊⋆ ゚☾ ゚。⋆ ☁︎。₊⋆

0개의 댓글