본문 바로가기
개발/Java

자바 기본 - 예외

by 컴쏘 2024. 11. 6.

개발을 하다보면 .. 반드시 마주하는 것이 예외이다. 예외에 대해서 알아보자. 

 

Error vs Exception

자바에서는 실행 시(runtime) 발생할 수 있는 오류에러와 예외 2가지로 구분한다. 

  • 에러(error) : 프로그램 코드에 의해서 수습될 수 없는 심각한 오류 
    • 메모리 부족(OutofMemoryError)이나 스택 오버 플로우(StackOverflowError)처럼 발생하면 복구할 수 없는 심각한 오류이고 예측 불가능하다. 
    • JVM 실행에 문제가 생긴 것

 

논리 에러, 컴파일 에러, 런타임 에러
논리 에러 : 논리적 에러는 버그라고 생각하면 된다. 프로그램의 실행에는 문제가 없지만, 결과가 예상과 달라 사용자가 의도한 작업을 수행하지 못해 서비스 이용에 문제가 될 수 있다. (ex. 수량에 음수가 나오는 경우, ...)

컴파일 에러 : 컴파일 단계에서 오류가 발견되면 컴파일러가 에러 메시지를 출력해주는 것이다. 대표적인 원인으로는 문법 구문 오류(syntax error)이다. 컴파일이 되지 않기 때문에 프로그램이 만들어지지 않아 프로그램 실행 자체가 불가능하다.

런타임 에러 : 컴파일에는 문제가 없더라도, 프로그램 실행 중에 에러가 발생해서 잘못된 결과를 얻거나, 프로그램이 종료될 수 있다. 개발자가 역추적해서 원인을 파악해야 한다.

 

  • 예외(exception) : 프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류 
    • 개발자가 구현한 로직에서 발생한 실수사용자의 영향에 의해 발생한다. 
    • 문제가 발생하더라도 이에 대한 대응 코드를 미리 작성해 놓음으로써 어느 정도 프로그램의 비정상적인 종료 혹은 동작을 막을 수 있다. (이 대응 코드가 try - catch 자바 예외 처리 문법)
    • 예외 처리(exception handling)을 통해 언제나 예외 상황을 처리하여 프로그램이 종료되는 일이 없도록 코드의 흐름을 바꿀 필요가 있다.
Exception Handling
예외 처리는 프로그램 실행 시 발생할 수 있는 예기치 못한 예외의 발생에 대비한 코드 작성 행위이다. 예외 처리의 목적은 예외의 발생으로 인한 실행 중인 프로그램의 갑작스런 비정상 종료를 막고, 정상적인 실행 상태를 유지하는 것이다.

 

Exception 클래스

계층 구조 ❘ 파란색 - 컴파일 에러, 빨간색 - 런타임 에러

 

JVM은 프로그램을 실행하는 도중에 예외가 발생하면 해당 예외 클래스로 객체를 생성하고서 예외 처리 코드에서 예외 객체를 이용할 수 있도록 해준다. 

  • 자바에서 다루는 모든 예외 오류는 Exception 클래스에서 처리한다. 
  • Exception 및 하위 클래스 (파란색 부분) : 사용자의 실수와 같은 외적인 요인에 의해 발생하는 컴파일 시 발생하는 예외 
    • 존재하지 않는 파일의 이름을 입력 (FileNotFoundException)
    • 실수로 클래스의 이름을 잘못 기재 (ClassNotFoundException)
    • 입력한 데이터 형식이 잘못된 경우 (DataFormatException)
    • I/O와 관해서 발생할 수 있는 예외 (IOException)
  • RuntimeException 클래스 (빨간색 부분) : 개발자의 실수로 발생하는 예외 
    • 배열의 범위를 벗어남 (IndexOutOfBoundsException
    • 값이 null인 참조 변수의 멤버를 호출 (NullPointerException)
    • 클래스 간의 형 변환을 잘못함 (ClassCastException)
    • 정수를 0으로 나누는 산술 오류 (ArithmeticException)
    • 메소드의 전달 인자값이 잘못될 경우 발생 (IllegalStateException)
    • 정수를 0으로 나눌 때 발생하는 에러 (ArithmeticException)
    • 의도치 않는 입력 오류 시 발생하는 예외 (InputMismatchException)
    • ... 등등

 

+) 더 알아보기 : Checked Exception과 Unchecked Exception

더보기

Checked Exception과 Unchecked Exception이 있다. 이는 코드적 관점에서 예외 처리 동작을 필수 지정 유무에 따라 나뉘기 때문이다. 

 

Checked Exception은 컴파일 예외 클래스들을 가리킨다. (반드시 예외 처리 - 컴파일 자체가 안되기 때문)

Unchecked Exception은 런타임 예외 클래스들을 가리킨다. (명시적인 처리를 안해도 됨 - 필요하다고 생각될 때 예외 처리) 

 

Java에서는 예외 상황이 발생했을 때 프로그램의 흐름을 중단하고 해당 예외를 호출한 쪽으로 전달하기 위해 예외 던지기를 한다. 예외가 발생한 메서드는 예외를 던지며, 상위 호출 스택에서 이를 받아 처리할 수 있다.  이때, 상위 호출 스택에서 처리하도록 전달하는 역할에는 throw와 throws 2가지가 있다. 

throw 

throw 키워드를 사용하면 강제로 예외를 발생시킬 수 있다. 

  • 프로그램적으로 에러가 아니더라도 로직상 개발자가 일부러 에러를 내서 로그에 기록하고 싶은 상황이 올 수 있다.
  • new 생성자로 예외 클래스를 초기화하여 던지진다. 

 

throws

throws 예시

 

예외가 발생할 수 있는 코드를 작성할 때 try - catch 블록으로 처리하는 것이 기본이지만, 경우에 따라서는 다른 곳에서 예외를 처리하도록 호출한 곳으로 예외를 떠넘길 수도 있도록 한다. 

  • 메소드 선언부 끝에 작성되어 메소드에서 예외를 직접 처리(catch)하지 않은 예외를 호출한 곳으로 떠넘기는 역할 
  • 예외를 메서드에 선언하는 역할이다. 

 

try - catch - .. 그리고 finally .. ? 

try - catch는 예외 처리를 위한 기본적인 구조이다. 

  • try 블록에는 예외 발생 가능 코드를 작성하고,
  • 만약, 예외가 발생하면 예외 클래스에 맞는 catch 문으로 가서 catch 블록의 코드를 실행한다. 
    • 이때, catch 문을 보면 e가 선언되어 있는 경우가 있다. 
    • 그리고, e.getMessage()와 같이 사용되는 것을 볼 수 있다. 이는 Throwable 클래스를 상속 받기 때문에 가능한 예외 메시지를 처리하는 것이다. 

 

+) 더 알아보기 : Throwable

더보기
상속 관계

 

Throwable 클래스는 오류나 예외에 대한 메시지를 담는다. 

  • 대표적으로 getMessage()와 printStackTrace() 메서드가 바로 이 클래스에 속해 있다. 
  • Error와 Exception 클래스가 Throwable을 상속 받기 때문에 사용 가능하다. 

 

그런데, try - catch 문에 finally가 붙는 경우도 있다. 왜 그럴까? 

 

finally는 어떤 예외가 발생하더라도 반드시 실행되어야 하는 부분이 있다면 필요하다. 

 

참고 1
참고 2
참고 3