• 자바에서는 실행 시 발생할 수 있는 오류(Exception과 Error)를 클래스로 정의하였다.
  • 모든 클래스의 조상은 Object클래스 이므로, Exception, Error 클래스 역시 Object 클래스의 자손들이다.

오류

  • 시스템에 비정상적인 상황이 생겼을 때 발생
  • 시스템 레벨에서 발생하기 때문에 심각한 수준의 오류이다.
  • 개발자가 미리 예측할 수 없기 때문에, 애플리케이션에서 오류에 대한 처리를 신경쓰지 않아도 된다.
  • 프로그램 코드로 수습할 수 없는 심각한 오류
    • 메모리 부족(OutofMemoryError)
    • 스택 오버플로우(StackOverflowError)
    • 비정상적인 종료 발생

예외

  • 개발자가 구현한 로직에서 발생한다.
  • 발생할 상황을 미리 예측하여 처리할 수 있다.
  • 개발자가 처리할 수 있기 때문에 예외를 구분하고 그에 따른 처리 방법을 명확히 알고 적용해야한다.
  • 모든 예외의 최고 조상은 Exception 클래스이다.

컴파일 에러

  • Checked 예외
  • 컴파일 시점에 발생하는 에러
  • 반드시 예외를 처리해야 한다.
  • 런타임 에러를 제외한 모든 예외
  • FileNotFoundException : 존재하지 않는 파일의 이름을 입력
  • ClassNotFoundException : 존재하지 않는 클래스 이름 입력
  • DataFormatException : 데이터 형식이 잘못된 경우

런타임 에러

  • Unchecked 예외
  • 실행 도중에 발생하는 에러
  • 명시적인 처리를 강제하지 않는다.(대비안하면 경고한다.)
  • ArithmeticException : 예외적인 산술 조건(0으로 나누기)
  • ClassCastException : 하위 유형이 아닌 유형에 대한 참조를 캐스팅 하려함
  • NullPointerException : 값이 null인 참조 변수의 멤버를 호출
  • IndexOutOfBoundsException : 배열의 범위를 벗어남

논리적 에러

  • 컴파일, 실행에 문제가 없지만 개발자가 의도한 것과 다르게 동작하는 에러를 말한다.

예외 처리

  • 예외 상황을 미리 예측하고 처리할 수 있는데, 이렇게 하는 것을 예외 처리라고 한다.
  • 예외 처리 방법
    1. 예외 복구 : 다른 작업 흐름으로 유도
    2. 예외처리 회피 : 처리하지 않고 호출한 쪽으로 throw
    3. 예외 전환 : 명확한 의미의 예외로 전환 후 throw

try

  • 오류가 발생할 예상 부분을 try로 감싸고, 발생할 오류와 관련된 Exceptioncatch에서 잡아 처리한다.
  • try 블록에서 여러 종류의 Exception이 발생한다면 catch라는 블록을 여러개 둘 수 있다.

catch

  • 예외가 발생했을 때 생성되는 예외클래스의 인스턴스에는 발생한 예외에 대한 정보가 담겨져 있으며, getMessage()printStackTrace()를 통해서 이 정보들을 얻을 수 있다.
  • catch 블럭의 괄호()에 선언된 참조 변수를 통해 이 인스턴스에 접근할 수 있다.
  • 이 참조 변수는 선언된 catch블럭 내에서만 사용 가능하며, 주로 사용되는 메서드는 다음과 같다.
    • printStackTrace()
      • 예외발생 당시의 호출스택(Call Stack)에 있었던 메서드의 정보와 예외 메시지를 화면에 출력한다.
      • stack을 보면 어디서 죽었는지(예외가 발생했는지)를 알 수 있다.
      • printStackTrace(PrintStream s) 또는 pirntStackTrace(PrintWriter s)를 사용하여 발생한 예외에 대한 정보를 파일에 저장할 수 있다.
    • getMessage()
      • 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.
  • Exception처리하지 않았을때는 프로그램이 강제 종료되었는데 catch라는 블록으로 Exception을 처리하니 강제종료되지 않고 잘 실행되는 것을 알 수 있다.
  • Exception 클래스들은 모두 Exception 클래스를 상속받으므로, 예외클래스에 Exception을 두면 어떤 오류가 발생하든지 간에 하나의 catch블록에서 모든 오류를 처리할 수 있다.

finally

  • 예외가 발생한 경우 흐름 : try → catch → finally
  • 예외가 발생하지 않은 경우 흐름 : try → finally
  • 프로그램 설치를 위한 준비 → 파일 복사 → 설치 완료되면 사용된 임시파일들을 삭제하는 흐름이 있을 때
    • finally에 임시파일들을 삭제하는 로직을 둬서 반복을 줄일 수 있다.
  • return문을 만나도 finally 블럭의 모든 문장들은 수행된다.
  • 오류가 발생했든 안했든 무조건 실행되는 finally 블록을 가질 수 있다.
    • finally는 생략 가능하다.

throws

  • 메서드의 선언부에 키워드 throws를 선언해서 메서드 내에서 발생할 수 있는 예외를 적는다.
    • 예외가 여러개인 경우에는 쉼표로 구분한다.
  • 메서드를 사용하려는 사람이 메서드의 선언부를 보았을 때, 이 메서드를 사용하기 위해서는 어떠한 예외들이 처리되어져야 하는지 쉽게 알 수 있다.
    • 해당 메서드를 사용하는 쪽에서는 이에 대한 처리를 하도록 강요하므로, 보다 견교한 프로그램 코드를 작성할 수 있다.
    • 예외를 전달받은 메서드가 또다시 자신을 호출한 메서드에게 전달할 수 있으며, 이런식으로 계속 호출스택에 있는 메서드들을 따라 전달되다가 제일 마지막에 있는 main 메서드에서도 예외가 처리되지 않으면, main 메서드 마저 종료되어 프로그래이 전체가 종료된다.
  • Object.wait()

    • Java API의 Object 클래스의 wait 메서드는 IllegalMonitorStateException, InterruptedExceptionthrows 한다.
    • 하지만 ==메서드 선언부에는 InterruptedException만 처리하면 된다==고 적혀져 있다.
      • InterruptedExceptionException 클래스의 자손이므로 반드시 처리해줘야 하는 예외이다.
      • IllegalMonitorStateExceptionRuntimeException클래스의 자손이므로 처리하지 않아도 된다.
  • 메서드에 예외를 선언할 때 일반적으로 RuntimeException클래스들은 적지 않는다.
    • 이들을 메서드 선언부의 throws에 선언해도 문제가 되지는 않지만 ==보통 반드시 처리해주어야 하는 예외들(RuntimeException 제외 클래스)만 throws한다.==

예외 되던지기

  • 한 메서드에서 발생할 수 있는 예외가 여럿인 경우, 몇개는 try-catch문을 통해서 메서드 내에서 자체적으로 처리하고, 그 나머지는 선언부에 지정하여 호출한 메서드에서 처리하도록 함으로써, 양쪽에서 나눠서 처리되도록 할 수 있다.
public static void main(String[] args) { 
	try { 
	method1(); 
	} catch (Exception e) { 
		System.out.println("main메서드에서 예외가 처리되었습니다."); 
	} 
} // main메서드의 끝 
 
static void method1() throws Exception { 
	try { 
		throw new Exception(); 
	} catch (Exception e) { 
	System.out.println("method1메서드에서 예외가 처리되었습니다."); 
	throw e; // 다시 예외를 발생시킨다. 
	} 
} // method1메서드의 끝
 
// 실행결과
// method1메서드에서 예외가 처리되었습니다.
// main메서드에서 예외가 처리되었습니다.
  • 예외가 발생할 가능성이 있는 메서드에서 try-catch문을 사용해서 예외를 처리해주고 catch문에서 필요한 작업을 행한 후, throw문을 통해 다시 예외를 발생시킨다.
  • 다시 발생한 예외는 이 메서드를 호출한 메서드에게 전달되고, 호출한 메서드의 try-catch문에서 예외를 또다시 처리한다.
    • 여러가지 예외를 하나의 큰 분류의 예외로 묶어서 다루기 위해 사용한다.
    • checked 예외를 unchecked 예외로 바꾸기 위해 사용한다.
      • unchecked예외가 되면 예외처리가 선택적이게 되므로 억지로 예외처리를 하지 않아도 된다.
  • unchecked & checked 예외 예시

static void startInstall() throws SpaceException, MemoryException { 
	if(!enoughSpace()) // 충분한 설치공간이 없다면! 
		throw new SpaceException("설치할 공간이 부족합니다");
	if(!enoughMemory()) // 충분한 메모리가 없다면! 
		throw new MemoryException("t메모리가 부족합니다"); 
}
  • unchecked 예외로 되던진 예시

static void startInstall() throws SpaceException {
	if(!enoughSpace()) // 충분한 설치공간이 없다면!
    	throw new SpaceException("설치할 공간이 부족합니다") 
        
	if(!enoughMemory()) // 충분한 메모리가 없다면!
    	throw new RuntimeException(new MemoryException("메모리가 부족합니다"));
} // 메모리 익셉션이 런타임익셉션의 원인 예외가 된것!

숭실대학교 양승민 교수님 프로그래밍 언어 수업 인파 (2022.11) 자바 에러(Error) 와 예외 클래스(Exception) 💯 이해하기 rlaehddnd0422 (2023.04) [JAVA] 예외(Exception)처리에 대해 프로그래밍 스티치 (2022.02) 예외 되던지기(exception re-throwing) 넥스트리소프트 (2021.01) Java 예외(Exception) 처리에 대한 작은 생각