예외 처리

이기영·2024년 6월 14일

Java 기초학습

목록 보기
9/14
post-thumbnail

목표

자바의 예외 처리에 대해 학습

목차

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


1. 자바에서 예외 처리 방법

Java에서 예외 처리는 프로그램 실행 중 발생하는 예외 상황을 적절히 처리하여 프로그램이 갑작스럽게 종료되는 것을 방지하고, 사용자에게 유의미한 에러 메시지를 제공하며, 프로그램의 정상적인 흐름을 유지하기 위해 사용됩니다.

Java에서는 예외 처리를 위해 try, catch, finally, throw, throws 키워드를 사용합니다.

1-1 예외의 종류

  • Checked Exception
    컴파일러가 예외 처리를 강제하는 예외입니다. 주로 외부 자원(파일, 네트워크 등)을 다룰 때 발생합니다.
    Ex) IOException, SQLException

  • Unchecked Exception
    컴파일러가 예외 처리를 강제하지 않는 예외입니다. 주로 프로그래머의 실수로 발생합니다.
    Ex) NullPointerException, ArrayIndexOutOfBoundsException

  • Error
    시스템 수준에서 발생하는 심각한 오류로, 보통 애플리케이션에서 처리하지 않습니다.
    Ex) OutOfMemoryError

아래에서 좀 더 자세하게 설명하겠습니다.


1-2 예외 처리 키워드

try-catch

  예외가 발생할 수 있는 코드를 try 블록에 넣고, 예외가 발생했을 떄의 처리를 catch블록에 넣습니다.

try {
    // 예외가 발생할 수 있는 코드
} catch (예외타입 변수이름) {
    // 예외 처리 코드
}

예제

public class ExceptionExample {
    public static void main(String[] args) {
        try {
            int result = 10 / 0; 
            // 여기서 ArithmeticException 발생
        } catch (ArithmeticException e) {
            System.out.println("예외 발생: " + e.getMessage());
        }
    }
}

  위 예제에서 10 / 0 연산으로 ArithmeticException이 발생하며, catch 블록에서 이를 처리합니다.



finally

  try 블록에서 예외가 발생하든 발생하지 않든 항상 실행되는 블록입니다. 주로 자원해제에 사용됩니다.

try {
    // 예외가 발생할 수 있는 코드
} catch (예외타입 변수이름) {
    // 예외 처리 코드
} finally {
    // 항상 실행되는 코드
}

예제

public class FinallyExample {
    public static void main(String[] args) {
        try {
            int result = 10 / 0;
        } catch (ArithmeticException e) {
            System.out.println("예외 발생: " + e.getMessage());
        } finally {
            System.out.println("finally 블록 실행");
        }
    }
}

  앞서 설명한것과 같이 finally는 예외 발생 여부와 관계없이 항상 실행됩니다.



throw

  프로그램의 특정 시점에서 예외를 직접 발생시킬 때 사용합니다.

public class ThrowExample {
    public static void main(String[] args) {
        try {
            validateAge(15);
        } catch (IllegalArgumentException e) {
            System.out.println("예외 발생: " + e.getMessage());
        }
    }

    public static void validateAge(int age) {
        if (age < 18) {
            throw new IllegalArgumentException("나이는 18 이상이어야 합니다.");
        }
    }
}

  위 예제에서 validateAge 메서드는 나이가 18 미만일 경우 IllegalArgumentException을 발생시킵니다.



throws

  메서드 선언부에 사용하여 해당 메서드가 특정 예외를 던질 수 있음을 선언합니다. 주로 CheckedException에 사용됩니다.

  throws를 통해 컴파일러가 예외 처리 여부를 검증할 수 있게 합니다.

public class ThrowsExample {
    public static void main(String[] args) {
        try {
            checkFile();
        } catch (IOException e) {
            System.out.println("예외 발생: " + e.getMessage());
        }
    }

    public static void checkFile() throws IOException {
        FileReader file = new FileReader("nonexistentfile.txt");
    }
}

  위 예제에서 checkFile 메서드는 FileReader 객체를 생성할때 IOException을 던질 수 있음을 throws 키워드를 통해 선언합니다.


✨ throws와 throw의 차이

  • throws : 메서드 선언부에 사용되며, 해당 메서드가 어떤 예외를 던질 수 있는지 선언합니다.
  • throw : 메서드 본문 내에서 사용되며, 실제로 예외를 던질 때 사용됩니다.

✨ throws의 예외 전파

  메서드가 예외를 처리하지 않고 호출한 메서드로 예외를 전파할 수 있습니다. 호출한 메서드에서 예외를 처리해야 합니다!

import java.io.IOException;

public class ExceptionPropagationExample {
    public static void main(String[] args) {
        try {
            method1();
        } catch (IOException e) {
            System.out.println("예외 발생: " + e.getMessage());
        }
    }

    public static void method1() throws IOException {
        method2();
    }

    public static void method2() throws IOException {
        throw new IOException("파일을 읽을 수 없습니다.");
    }
}

  method2IOException을 던지고, method1은 이를 처리하지 않고 throws IOException을 통해 예외를 전파합니다. main메서드에서 최종적으로 예외를 처리합니다.


  이와 같이 throws 키워드를 사용하면 메서드가 던질 수 있는 예외를 명시적으로 선언할 수 있으며, 호출한 메서드에서 예외를 처리하거나, 다시 전파할 수 있습니다.



사용자 정의 예외

  기본 제공 예외 클래스 외에 사용자가 정의한 예외를 만들 수 있습니다. 사용자 정의 예외는 Exception 클래스를 상속하여 생성합니다.

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

public class CustomExceptionExample {
    public static void main(String[] args) {
        try {
            validateAge(15);
        } catch (CustomException e) {
            System.out.println("예외 발생: " + e.getMessage());
        }
    }

    public static void validateAge(int age) throws CustomException {
        if (age < 18) {
            throw new CustomException("나이는 18 이상이어야 합니다.");
        }
    }
}

  CustomException은 사용자 정의 예외로, 나이가 18 미만일 경우, validateAge 메서드에서 CustomException을 던집니다.


2. 자바가 제공하는 예외 계층 구조

Java에서 제공하는 예외 계층 구조는 예외를 체계적으로 관리하고 처리하기 위해 설계되었습니다. 예외 계층 구조는 크게 Throwable 클래스를 기반으로 두 가지 분류인 ErrorExceprion 클래스로 나뉩니다.

java.lang.Object
   └── java.lang.Throwable
         ├── java.lang.Error
         └── java.lang.Exception
              ├── java.lang.RuntimeException
              └── 기타 예외 클래스

  Throwable 클래스는 Java의 모든 예외와 오류의 최상위 클래스입니다. 이 클래스는 예외나 오류가 발생했을 때 잡히거나 던질 수 있는 객체를 나타냅니다.


3. Exception과 Error의 차이

  ExceptionError는 모두 Throwable클래스를 기반으로 하지만, 명확한 차이가 있습니다.

3-1 Error

  Error 클래스는 애플리케이션에서 복구할 수 없는 심각한 문제를 나타냅니다. 이러한 오류는 보통 애플리케이션 수준에서 처리하지 않으며, 주로 JVM에서 발생합니다.

Ex) OutOfMemoryError, StackOverflowError, VirtualMachineError


3-2 Exception

Exception 클래스는 애플리케이션에서 발생할 수 있는 예외 상황을 나타냅니다. Exception은 다시 Checked ExceptionUnchecked Exception으로 나뉩니다.

Checked Exception

  Checked Exception은 컴파일러가 예외 처리를 강제하는 예외입니다. 즉, 이 예외를 처리하거나 메서드 선언부에 throws 키워드를 사용하여 선언해야 합니다.

Ex) IOException, SQLException, ClassNotFoundException


Unchecked Exception

  Unchecked Exception는 컴파일러가 예외 처리를 강제하지 않는 예외입니다. 이러한 예외는 주로 프로그래머의 실수로 인해 발생합니다. 모든 Unchecked Exception은RuntimeException클래스를 상속합니다.


  RuntimeException 클래스는 Unchecked Exception중 최상위 클래스입니다. 일반적으로 프로그래밍 오류에 발생합니다. 이 예외는 명시적으로 선언하지 않아도 되며, 런타임에 발생할 수 있습니다.


4. RuntimeException과 RE가 아닌 것의 차이

  위에서도 여러번 설명드렸지만, 한번더 정리해보겠습니다.

  RuntimeExceptionRuntimeException이 아닌 예외의 주요 차이는 컴파일러가 예외 처리를 강제하는지 여부예외가 발생하는 상황에 있습니다.

  이 차이는 Checked ExceptionUnchecked Exception의 차이로 이해할 수 있습니다.


4-1 RuntimeException (Unchecked Exception)

  RuntimeException 클래스는 Unchecked Exception의 최상위 클래스입니다.

  Unchecked Exception은 컴파일러가 예외 처리를 강제하지 않는 예외로, 주로 프로그래머의 실수로 인해 발생하는 예외들입니다. 이 예외들은 프로그램의 논리적 오류를 나타내며, 런타임에만 발견될 수 있습니다.


특징

  • 컴파일 시 예외 처리를 강제하지 않습니다.
    (throws 키워드를 사용하지 않아도 됩니다.)
  • 런타임에서만 예외 발생 여부를 알 수 있습니다.
  • 주로 프로그래머의 실수로 발생합니다.
    (Ex : 잘못된 타입 캐스팅, 잘못된 인덱스 접근 등)

예시

  • NullPointerException
  • ArrayIndexOutOfBoundsException
  • ArithmeticException
  • ClasscastException

예제

public class RuntimeExceptionExample {
    public static void main(String[] args) {
        String str = null;
        System.out.println(str.length());  // NullPointerException 발생
    }
}



4-2 Checked Exception

  Checked ExceptionException 클래스의 서브클래스로, RuntimeException을 상속하지 않는 예외들입니다.

  이 예외들은 컴파일러가 예외 처리를 강제하며, 일반적으로 외부 환경과의 상호작용에서 발생하는 예외들입니다.

  이러한 예외는 반드시 예외 처리(try-catch)를 하거나 메서드 선언부에 throws 키워드를 사용하여 선언해야합니다.


특징

  • 컴파일 시 예외 처리를 강제합니다.
    (throws키워드를 사용하여 선언하거나, try-catch로 처리해야함)
  • 주로 외부 자원(파일, 네트워크, 데이터베이스 등)과의 상호작용에서 발생합니다.
  • 예외 처리를 통해 복구 가능한 상황을 나타냄

예시

  • IOException
  • SQLException
  • ClassNotFoundException
  • FileNotFoundException

예제

import java.io.*;

public class CheckedExceptionExample {
    public static void main(String[] args) {
        try {
            readFile("nonexistentfile.txt");
        } catch (IOException e) {
            System.out.println("예외 발생: " + e.getMessage());
        }
    }

    public static void readFile(String filename) throws IOException {
        FileReader file = new FileReader(filename);  
        // FileNotFoundException 발생 가능
        file.read();
        file.close();
    }
}

주요 차이점 요약

특징RuntimeException (Unchecked Exception)Checked Exception
예외 처리 강제 여부컴파일러가 예외 처리를 강제하지 않음컴파일러가 예외 처리를 강제
발생 시점주로 런타임에서 발생컴파일 시 예외 처리 요구
발생 원인주로 프로그래머의 실수외부 자원과의 상호작용 (I/O, DB 등)
예제NullPointerException, ArrayIndexOutOfBoundsExceptionIOException, SQLException



5. 커스텀한 예외 만드는 방법

Checked ExceptionUnchecked Exception을 커스텀하게 만들 수 있습니다. Exception클래스나 RuntimeException 클래스를 상속받도록 하면 됩니다.


5-1 Checked Exception

  Checked Exception을 만들기 위해서는 Exception 클래스를 상속받아야 합니다. 이는 컴파일러가 예외 처리를 강제하는 예외입니다.


예제

// CustomCheckedException.java
public class CustomCheckedException extends Exception {
    public CustomCheckedException() {
        super();
    }

    public CustomCheckedException(String message) {
        super(message);
    }

    public CustomCheckedException(String message, Throwable cause) {
        super(message, cause);
    }

    public CustomCheckedException(Throwable cause) {
        super(cause);
    }
}

사용 예제

public class CustomCheckedExceptionExample {
    public static void main(String[] args) {
        try {
            methodThatThrowsCustomException();
        } catch (CustomCheckedException e) {
            System.out.println("Custom checked exception caught: " + e.getMessage());
        }
    }

    public static void methodThatThrowsCustomException() throws CustomCheckedException {
        throw new CustomCheckedException("This is a custom checked exception");
    }
}

5-2 Unchecked Exception

  Unchecked Exception을 만들기 위해서는 RuntimeException 클래스를 상속받아야 합니다. 이는 컴파일러가 예외 처리를 강제하지 않는 예외 입니다.


예제

// CustomUncheckedException.java
public class CustomUncheckedException extends RuntimeException {
    public CustomUncheckedException() {
        super();
    }

    public CustomUncheckedException(String message) {
        super(message);
    }

    public CustomUncheckedException(String message, Throwable cause) {
        super(message, cause);
    }

    public CustomUncheckedException(Throwable cause) {
        super(cause);
    }
}

사용 예제

public class CustomUncheckedExceptionExample {
    public static void main(String[] args) {
        try {
            methodThatThrowsCustomException();
        } catch (CustomUncheckedException e) {
            System.out.println("Custom unchecked exception caught: " + e.getMessage());
        }
    }

    public static void methodThatThrowsCustomException() {
        throw new CustomUncheckedException("This is a custom unchecked exception");
    }
}

요약

  • Checked Exception 만들기
    Exception 클래스를 상속받아 정의합니다. 컴파일러가 예외 처리를 강제하게 됩니다.

  • Unchecked Exception 만들기
    RuntimeException 클래스를 상속받아 정의합니다. 컴파일러가 예외 처리를 강제하지 않습니다.




profile
안녕나를소개하지이름은HaBu직업은Programer취미는tai chi meditation

2개의 댓글

comment-user-thumbnail
2024년 6월 14일

예외 처리 할 때 커스텀한 예외를 사용한다면 에러 발생시 더욱 명확한 원인을 알 수 있겠네요😊

1개의 답글