본문 바로가기
Everyday Study

2024.07.22 (월) { 예외처리, try-catch }

by xogns93 2024. 7. 22.

predicate 인터페이스 

if (condition.test(item))

 

Predicate<T>

boolean test(T t);

- T를 인자로 받고, Boolean형을 리턴한다

 

어레이리스트, 링크드리스트 장단점

 

언체크드는 던지기할필요 x


자바 가상 머신(JVM)이 발생시키는 예외

자바 가상 머신(JVM)은 프로그램 실행 중에 다양한 예외를 발생시킬 수 있습니다. 이러한 예외는 주로 런타임 오류로 인해 발생하며, 프로그램의 정상적인 실행을 방해할 수 있습니다. 자바의 예외는 java.lang.Throwable 클래스의 서브클래스로 표현됩니다. Exception Error 두 가지 주요 서브클래스가 있습니다.

 

주요 예외 클래스

  1. Exception: 프로그램의 논리적 오류나 외부 조건으로 인해 발생하는 예외. 주로 복구 가능.
    • RuntimeException: 런타임 시 발생하는 예외로, 프로그래머의 실수로 인해 발생. 예외 처리를 강제하지 않음.
      • NullPointerException: 객체 참조가 null인 상태에서 메서드나 속성에 접근할 때 발생.
      • ArrayIndexOutOfBoundsException: 배열의 잘못된 인덱스에 접근할 때 발생.
      • ArithmeticException: 나누기 0과 같은 잘못된 산술 연산이 수행될 때 발생.
    • IOException: 입출력 작업에서 발생하는 예외. 예외 처리를 강제함.
      • FileNotFoundException: 파일을 찾을 수 없을 때 발생.
      • EOFException: 입력 스트림의 끝에 도달했을 때 발생.
  2. Error: 주로 JVM의 내부 오류나 자원 부족으로 인해 발생하는 심각한 문제. 프로그램에서 복구할 수 없음.
    • OutOfMemoryError: JVM의 힙 메모리가 부족할 때 발생.
    • StackOverflowError: 재귀 호출이 너무 깊어져서 스택 메모리가 초과될 때 발생.
    • VirtualMachineError: JVM의 내부 오류로 인해 발생하는 에러. InternalError, UnknownError 등이 포함됨.

 

자바에서는 try-catch 블록을 사용하여 예외를 처리합니다.

public class ExceptionExample {
    public static void main(String[] args) {
        try {
            int result = divide(10, 0);
            System.out.println("Result: " + result);
        } catch (ArithmeticException e) {
            System.out.println("예외 발생: " + e.getMessage());
        } finally {
            System.out.println("프로그램 종료.");
        }
    }

    public static int divide(int a, int b) {
        return a / b;  // b가 0이면 ArithmeticException 발생
    }
}

위 예시에서, divide 메서드에서 0으로 나누기를 시도하면 ArithmeticException이 발생하고, 이를 catch 블록에서 처리합니다.


체크드 예외(Checked Exception)와 언체크드 예외(Unchecked Exception)

 

 

체크드 예외 (Checked Exception)

  • 정의: 컴파일러가 예외 처리를 강제하는 예외입니다. 메서드에서 체크드 예외가 발생할 수 있으면, 해당 예외를 처리하거나 메서드 서명에 throws 키워드를 사용해 선언해야 합니다.
  • 특징:
    • 컴파일 시점에 예외 처리를 요구합니다.
    • 예외를 처리하지 않으면 컴파일 오류가 발생합니다.
    • 파일 입출력, 네트워크 통신, 데이터베이스 접근 등의 작업에서 자주 발생합니다.

자바에서 체크드 예외(Checked Exception)를 처리할 때는 두 가지 방법 중 하나를 선택해야 합니다:

 

  • 예외 처리: try-catch 블록을 사용하여 예외를 처리합니다.
  • 예외 선언: 메서드 서명에 throws 키워드를 사용하여 예외를 선언하고, 호출한 메서드로 예외를 전달합니다.

 

종류

  • IOException (및 하위 클래스)
    • FileNotFoundException: 파일을 찾을 수 없을 때 발생합니다.
    • EOFException: 입력 스트림의 끝에 도달했을 때 발생합니다.
  • SQLException
    • 데이터베이스 액세스 오류가 발생했을 때 던져집니다.
  • ClassNotFoundException
    • 특정 클래스 파일을 찾을 수 없을 때 발생합니다.
  • InstantiationException
    • 객체 생성에 실패했을 때 발생합니다.
  • IllegalAccessException
    • 클래스에 접근할 수 없을 때 발생합니다.
  • InterruptedException
    • 스레드가 대기, 수면 또는 대기 상태에서 인터럽트되었을 때 발생합니다.
  • NoSuchMethodException
    • 특정 메서드를 찾을 수 없을 때 발생합니다.
  • InvocationTargetException
    • 리플렉션을 통해 메서드를 호출하는 중 예외가 발생했을 때 던져집니다.

 

 

언체크드 예외 (Unchecked Exception)

  • 정의: 컴파일러가 예외 처리를 강제하지 않는 예외입니다. 런타임 시점에 발생하며, RuntimeException 클래스와 그 하위 클래스들입니다.
  • 특징:
    • 컴파일 시점에 예외 처리를 요구하지 않습니다.
    • 예외 처리를 하지 않아도 컴파일이 가능합니다.
    • 논리적 오류, 프로그래밍 실수 등에서 자주 발생합니다.
    • 일반적으로 예외를 처리하지 않고 프로그램을 수정하는 것이 바람직합니다. 

종류

  • RuntimeException (및 하위 클래스)
    • NullPointerException: 객체 참조가 null일 때 발생합니다. 널포인트익셉션은 어차피 처리할방법이없어서 걍 포기하기때문에 try캐치문 안써도됨; 일반적으로 이러한 예외는 코드의 논리적 오류로 인해 발생하며, 예외를 처리하기보다는 발생하지 않도록 코드를 수정하는 것이 더 바람직
    • ArrayIndexOutOfBoundsException: 배열의 잘못된 인덱스에 접근할 때 발생합니다.
    • ArithmeticException: 잘못된 산술 연산이 수행될 때 발생합니다.
    • ClassCastException: 잘못된 형변환이 수행될 때 발생합니다.
    • IllegalArgumentException: 메서드에 부적절한 인수가 전달되었을 때 발생합니다.
    • NumberFormatException: 숫자 형식의 문자열을 파싱할 때 형식이 맞지 않으면 발생합니다.
  • Error (및 하위 클래스)
    • OutOfMemoryError: JVM의 힙 메모리가 부족할 때 발생합니다.
    • StackOverflowError: 재귀 호출이 너무 깊어져서 스택 메모리가 초과될 때 발생합니다.
    • VirtualMachineError: JVM의 내부 오류로 인해 발생합니다.

 

 

요약

  • 체크드 예외 (Checked Exception):
    • 컴파일러가 예외 처리를 강제함.
    • 메서드가 던질 수 있는 예외를 선언하거나, try-catch 블록으로 처리해야 함.
    • 예시: FileNotFoundException, IOException.
  • 언체크드 예외 (Unchecked Exception):
    • 컴파일러가 예외 처리를 강제하지 않음.
    • 예외 처리를 하지 않아도 컴파일이 가능함.
    • 예시: NullPointerException, ArrayIndexOutOfBoundsException, ArithmeticException.

 


try-catch-finally

try-catch-finally 구문은 자바에서 예외를 처리하는 예외 핸들링 메커니즘입니다. 이를 통해 예외가 발생했을 때 프로그램이 비정상적으로 종료되지 않고, 적절하게 예외를 처리할 수 있습니다.

 

try-catch-finally 구문의 구성 요소

  1. try 블록:
    • 예외가 발생할 가능성이 있는 코드를 포함합니다. { } 안에
    • 예외가 발생하면 해당 예외는 즉시 try 블록을 빠져나가고, 적절한 catch 블록이 실행됩니다.
  2. catch 블록:
    • 특정 예외 타입을 처리하는 코드가 포함됩니다.
    • try 블록에서 발생한 예외를 잡아서 처리합니다.
    • 여러 개의 catch 블록을 사용하여 다양한 예외를 처리할 수 있습니다.
  3. finally 블록 (선택 사항):
    • 예외 발생 여부와 상관없이 항상 실행되는 코드를 포함합니다.
    • 주로 리소스를 정리하거나 닫는 작업을 수행합니다.

예외발생 유무와 상관없이 finally{ } 는 무조건 실행된다

try catch 작성할때 꼭 finally도 같이 작성하는 습관 들이면 좋음

 

 


예외 처리 메커니즘

 

예외 던지기 (Throwing an Exception)

  1. 예외 객체 생성: 예외가 발생하면, 해당 예외에 대한 정보가 담긴 예외 객체를 생성합니다.
  2. 예외 던지기: throw 키워드를 사용하여 예외 객체를 던집니다.

예외 잡기 (Catching an Exception)

  1. 예외 핸들러 검색: 런타임 시스템은 예외를 처리할 수 있는 예외 핸들러를 검색합니다.
  2. 예외 처리: 예외 핸들러가 존재하면 예외를 처리하고, 존재하지 않으면 프로그램이 종료됩니다.

 

다음은 Java에서 예외를 던지고 처리하는 예시입니다:

public class ExceptionExample {
    public static void main(String[] args) {
        try {
            int result = divide(10, 0);
            System.out.println("Result: " + result);
        } catch (ArithmeticException e) {
            System.out.println("예외 발생: " + e.getMessage());
        } finally {
            System.out.println("프로그램 종료.");
        }
    }

    public static int divide(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException("0으로 나눌 수 없습니다."); // 예외 던지기
        }
        return a / b;
    }
}

코드 설명

  1. 예외 던지기:
    • divide 메서드에서 b가 0일 경우, ArithmeticException 객체를 생성하고 throw 키워드를 사용하여 예외를 던집니다.
  2. 예외 잡기:
    • main 메서드 내의 try 블록에서 divide 메서드를 호출합니다.
    • 예외가 발생하면 catch 블록이 실행되어 예외 메시지를 출력합니다.
    • finally 블록은 예외 발생 여부와 관계없이 항상 실행됩니다.

예외 처리 흐름

  1. divide(10, 0) 메서드 호출
  2. b가 0이므로 throw new ArithmeticException("0으로 나눌 수 없습니다.") 실행
  3. 예외가 던져지고, 런타임 시스템은 catch 블록에서 ArithmeticException을 처리
  4. 예외 메시지를 출력하고, finally 블록 실행

 

예외가 처리되지 않는 경우

예외가 발생했지만 적절한 예외 핸들러가 없는 경우, 프로그램은 다음과 같이 동작합니다:

public class NoHandlerExample {
    public static void main(String[] args) {
        int result = divide(10, 0); // 예외 발생
        System.out.println("Result: " + result); // 이 줄은 실행되지 않음
    }

    public static int divide(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException("0으로 나눌 수 없습니다.");
        }
        return a / b;
    }
}

위 예시에서 catch 블록이 없으므로 예외가 처리되지 않으며, 프로그램은 비정상 종료되고 스택 추적(Stack Trace)을 출력합니다.

 


throws 키워드

 

throws 키워드는 메서드 선언부에서 사용되어 해당 메서드가 특정 예외를 던질 수 있음을 나타냅니다. 메서드 내에서 예외가 발생하면, 그 예외를 자신을 호출한 메서드에게 전달(던지기)합니다. 예외를 처리하지 않고 던짐으로써, 예외 처리를 호출한 메서드로 위임합니다.

 

예외 던지기:

  • throw new ~~Exception(); 문을 사용하여 예외 객체를 생성하고 던집니다.
  • 예외 객체가 생성되면, 현재 메서드의 실행이 중지됩니다.
  • 예외는 호출 스택을 통해 역순으로 전파됩니다.

 

 

예외전달 :

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

    public static void methodB() throws ArithmeticException {
        methodA();
    }

    public static void methodA() throws ArithmeticException {
        throw new ArithmeticException("0으로 나눌 수 없습니다.");
    }
}

코드 작동 순서

  1. main 메서드 시작:
    • 프로그램이 시작되고 main 메서드가 실행됩니다.
  2. try 블록 진입:
    • main 메서드 내의 try 블록으로 진입합니다.
    • try 블록에서 methodB()를 호출합니다.
  3. methodB 호출:
    • methodB() 메서드가 호출됩니다.
    • methodB()는 ArithmeticException을 던질 수 있음을 선언하고 있습니다.
    • methodB() 내에서 methodA()를 호출합니다.
  4. methodA 호출:
    • methodA() 메서드가 호출됩니다.
    • methodA()는 ArithmeticException을 던질 수 있음을 선언하고 있습니다.
    • methodA() 내에서 예외가 발생합니다. throw new ArithmeticException("0으로 나눌 수 없습니다.");코드가 실행됩니다.
  5. 예외 발생:
    • methodA()에서 ArithmeticException 예외가 발생합니다.
    • methodA()는 예외를 던지고 종료됩니다.
    • 예외는 methodB()로 전달됩니다.
  6. methodB로 예외 전달:
    • methodA()에서 발생한 예외가 methodB()로 전달됩니다.
    • methodB()는 예외를 처리하지 않고 던진다고 선언했으므로, 예외는 methodB()를 호출한 main 메서드로 전달됩니다.
    • methodB()는 예외를 던지고 종료됩니다.
  7. main 메서드로 예외 전달:
    • methodB()에서 발생한 예외가 main 메서드로 전달됩니다.
    • main 메서드의 try 블록 내에서 예외가 발생했으므로, try 블록을 빠져나가고, 해당 예외를 처리하는 catch 블록으로 이동합니다.
  8. catch 블록 실행:
    • catch (ArithmeticException e) 블록이 실행됩니다.
    • 예외 메시지를 출력합니다: 예외 발생: 0으로 나눌 수 없습니다.
  9. 프로그램 종료:
    • catch 블록이 종료된 후 main 메서드가 정상적으로 종료됩니다.
    • 프로그램이 종료됩니다.

 

이렇게 예외는 호출 계층을 따라 전달되며, 적절한 예외 핸들러가 있을 때까지 전달됩니다. 만약 예외가 적절하게 처리되지 않으면 프로그램은 비정상 종료됩니다. 

 


체인드 예외(Chained Exceptions)

 

체인드 예외(Chained Exceptions)는 자바에서 하나의 예외가 다른 예외의 원인(cause)으로 발생했음을 나타내기 위해 사용됩니다. 이 메커니즘은 여러 계층의 예외를 처리할 때, 원래 예외의 발생 원인을 추적하고 디버깅하는 데 유용합니다.

체인드 예외는 한 예외가 다른 예외를 던질 때, 원래 예외를 원인으로 지정할 수 있는 방법을 제공합니다. 이를 통해 여러 예외를 연결(chain)하여 예외의 발생 원인을 명확히 할 수 있습니다.

 

체인드 예외 생성 및 사용

예제 코드

아래 예제는 체인드 예외를 사용하는 방법을 보여줍니다.

public class ChainedExceptionExample {
    public static void main(String[] args) {
        try {
            methodA();
        } catch (Exception e) {
            System.out.println("최종 예외: " + e);
            System.out.println("원인 예외: " + e.getCause());
        }
    }

    public static void methodA() throws Exception {
        try {
            methodB();
        } catch (Exception e) {
            throw new Exception("methodA에서 예외 발생", e);
        }
    }

    public static void methodB() throws Exception {
        throw new Exception("methodB에서 예외 발생");
    }
}

코드 설명

  1. methodB 예외 발생:
    • methodB는 Exception을 던집니다.
    • 예외 메시지: "methodB에서 예외 발생".
  2. methodA 예외 발생 및 체인드 예외 생성:
    • methodA는 methodB를 호출합니다.
    • methodB에서 예외가 발생하여 methodA로 전파됩니다.
    • methodA는 catch 블록에서 원래 예외를 잡고, 새로운 예외를 던질 때 원래 예외를 원인(cause)으로 지정합니다.
    • 새로운 예외 메시지: "methodA에서 예외 발생".
  3. main 메서드에서 최종 예외 처리:
    • main 메서드는 methodA를 호출하고, try-catch 블록에서 예외를 처리합니다.
    • 최종 예외 메시지와 원인 예외 메시지를 출력합니다.

 

체인드 예외의 주요 메서드

  • initCause(Throwable cause): 예외 객체에 원인 예외를 설정합니다.
  • getCause(): 예외 객체의 원인 예외를 반환합니다.

예제 코드:

public class ChainedExceptionExample2 {
    public static void main(String[] args) {
        try {
            throw new Exception("최초 예외");
        } catch (Exception e) {
            Exception chainedException = new Exception("체인드 예외");
            chainedException.initCause(e); // 원인 예외 설정
            try {
                throw chainedException;
            } catch (Exception ex) {
                System.out.println("최종 예외: " + ex);
                System.out.println("원인 예외: " + ex.getCause());
            }
        }
    }
}

코드 설명

  1. 최초 예외 발생:
    • Exception 객체를 생성하여 "최초 예외" 메시지와 함께 던집니다.
  2. 체인드 예외 생성 및 원인 예외 설정:
    • catch 블록에서 새로운 예외 객체 chainedException을 생성하고 "체인드 예외" 메시지를 설정합니다.
    • initCause 메서드를 사용하여 원인 예외를 설정합니다.
  3. 최종 예외 던지기 및 처리:
    • 새로운 예외 chainedException을 던집니다.
    • 외부 catch 블록에서 최종 예외와 원인 예외를 출력합니다.

 

요약

  • 체인드 예외(Chained Exceptions): 하나의 예외가 다른 예외의 원인으로 발생했음을 나타내기 위해 사용됩니다.
  • initCause 메서드: 예외 객체에 원인 예외를 설정합니다.
  • getCause 메서드: 예외 객체의 원인 예외를 반환합니다.
  • 사용 예제: 체인드 예외를 통해 예외 발생의 원인을 명확히 하고, 디버깅을 용이하게 할 수 있습니다.

체인드 예외를 사용하면 예외의 발생 원인을 추적하고, 예외 처리 흐름을 명확히 할 수 있습니다. 이를 통해 디버깅과 유지보수가 더 쉬워집니다.

 


e.getStackTrace()