[Java] Error와 Exception 차이

Jeini·2022년 11월 12일
2

☕️  Java

목록 보기
27/70

📌 Error와 Exception란

✔️ 오류(Error)
오류(Error)는 시스템이 종료되어야 할 수준의 상황과 같이 수습할 수 없는 심각한 문제를 의미한다. 개발자가 미리 예측하여 방지할 수 밖에 없다.

✔️ 예외(Exception)
예외(Exception)는 개발자가 구현한 로직에서 발생한 실수나 사용자의 영향에 의해 발생한다. 오류와 달리 개발자가 미리 예측하여 방지할 수 있기에 상황에 맞는 예외처리(Exception Handle)를 해야 한다.

예외가 발생하면 프로그램이 종료가 된다는것은 에러와 동일하지만 예외는 예외처리(Exception Handling)을 통해 프로그램을 종료 되지 않고 정상적으로 작동되게 만들어줄 수 있다.

자바에서 예외처리는 Try Catch문을 통해 해줄 수 있다.


💡 Throwable

✅ 자바에서 예외 처리 계층의 루트 클래스

  • throw 키워드로 발생시킬 수 있는 건 전부 Throwable 의 자식이어야 함
  • 주요 메서드:
    getMessage() → 예외 메시지 확인
    printStackTrace() → 예외 발생 경로 출력
    toString() → 예외 클래스명 + 메시지 출력

💡 오류(Error)

  • 시스템 레벨 문제 (cpu, memory, JVM 기인 문제 등)
  • 프로그램이 제어할 수 없는 심각한 문제 → 보통 개발자가 처리할 수 없음
  • 예시:
    OutOfMemoryError (메모리 부족)
    StackOverflowError (재귀 너무 깊음)
    ➡️ 이런 건 보통 프로그램이 그냥 종료됨 ❌

👉 오류는 "잡아서 처리하려고 하지 말고, 근본적으로 코드/환경을 고쳐야 하는 문제"

✔️ StackOverflowError
: 응용 프로그램이 너무 많이 반복되어 StackOverflow가 발생할 때 던져지는 오류이다.

✔️ OutOfMemoryError
: JVM이 할당된 메모리의 부족으로 더 이상 객체를 할당할 수 없을 때 던져지는 오류이다.

  • Garbage Collector에 의해 추가적인 메모리가 확보되지 못하는 상황일 때
  • heap 사이즈 부족
  • 너무 많은 class를 로드할 때
  • 가용가능한 swap이 없을 때
  • 큰 메모리의 native메서드가 호출될 때
    이를 해결하기 위해, dump파일분석, jvm 옵션 수정 등이 있다.

앞서 말했듯 개발자가 미리 오류를 대처하기는 힘들다.
다만 StackOverflowError 를 피하기 위해서 재귀를 사용할 때에 조심하거나 가시적인 loop를 사용하는 간접적인 예방이 가능하다.

또한 OutOfMemoryError 를 피하기 위해 새는 메모리를 차단하거나 heap의 크기를 늘려주는 방법을 사용할 수도 있다.


💡 예외(Exception)

  • 개발자가 처리할 수 있는 문제
  • 프로그램 실행 중 "예상은 못했지만 충분히 대비할 수 있는 상황"
  • 예시:
    NullPointerException (null 접근)
    IOException (파일 못 찾음)
    ArithmeticException (0으로 나눔)

👉 예외는 try-catch로 잡아서 프로그램이 죽지 않게 처리할 수 있음 ✅


✏️ Exception의 2가지 종류

1. Checked Exception

  • 예외처리가 필수이며, 처리하지 않으면 컴파일되지 않는다.
    try-catch로 감싸거나 throw로 던져서 예외처리.
  • 컴파일 단계에서 명확하게 Exception체크가 가능하다.
  • JVM 외부와 통신(네트워크, 파일시스템 등)할 때 주로 쓰인다.

2. UncheckedException

  • 명시적인 예외처리를 하지 않아도 된다.
  • RuntimeException 하위의 모든 예외
  • NullPointerException , IndexOutOfBoundException 등등
  • 실행과정 중 어떠한 특정 논리에 의해 발견되는 Exception
  • 예외 발생시 트랜잭션을 roll-back한다.

❗️ Checked Exception과 UncheckedException의 가장 명확한 구분 기준
: '꼭 처리를 해야 하는가'


✏️ 여러가지 예외들

✔️ ArithmeticException
: 정수를 0으로 나눌경우 발생

✔️⭐️ ArrayIndexOutOfBoundsException
: 배열의 범위를 벗어난 index를 접근할 시 발생

ex) 길이가 3인 int[]arr = new int[3] 배열을 선언했다면,
0 ~ 2까지의 index만 사용할 수 있다. 하지만 이 배열의 index가 -1이나 3을 참조하는 순간 이 예외가 발생한다.

✔️⭐️⭐️ ClassCastException
: 변화할 수 없는 타입으로 객체를 반환 시 발생

타입 변환은 상위클래스와 하위클래스간에 발생하고 구현 클래스와 인터페이스간에도 발생한다. 이런 관계가 아니면 클래스는 다른 클래스로 타입을 변환할 수 없다. 하지만 이 규칙을 무시하고 억지로 타입을 변환시킬 경우 발생하는 예외이다.

✔️⭐️⭐️⭐️ NullPointException
: 존재하지 않는 레퍼런스를 참조할 때 발생

Java 프로그램에서 가장 빈번하게 발생하는 익셉션으로, 객체 참조가 없는 상태, 즉 null값을 갖는 참조변수로 객체 접근 연산자인 토드(.)를 사용했을 때 발생한다.
객체가 없는 상태에서 객체를 사용하려 했으니 예외가 발생하는 것.

✔️ IllegalArgumentException
: 잘못된 인자를 전달할 때 발생

✔️ IllegalStateException
: 객체의 상태가 메서드 호출에는 부적절한 경우에 발생

✔️ IOException
: 입출력 동작 실패 또는 인터럽트 시 발생

✔️ OutOfMemoryException
: 메모리가 부족한 경우 발생

✔️⭐️⭐️ NumberFormatException
: 문자열이 나타내는 숫자와 일치하지 않는 타입의 숫자로 변환시 발생

개발을 하다보면 문자열로 되어있는 데이터를 숫자타입으로 변경하는 경우가 자주 발생하는데 숫자타입으로 변경할 수 없는 문자를 치환시키려고 하면 발생하는 예외이다.

✔️ CurrentModificationException
: 금지된 곳에서 객체를 동시에 수정하는 것이 감지될 경우 발생

✔️ UnsupportedOperationException
: 객체가 메서드를 지원하지 않는 경우 발생


📝 오류 vs 예외 비교

구분ErrorException
의미시스템 레벨 문제프로그램 레벨 문제
복구불가능가능 (try-catch)
예시OutOfMemoryErrorNullPointerException
처리코드로 못 잡음코드로 처리 가능

📌 Exception Handling

Java에서 모든 예외가 발생하면 (XXX)Exception 객체를 생성한다.
즉, 자바의 예외 처리는 발생시키기(throw), 던지기(throws), 잡아서 처리하기(try-catch-finally), 직접 정의하기(Custom Exception) 이 네 가지 흐름으로 정리할 수 있다 🚀

1️⃣ 발생시키기 (throw)

👉 코드 안에서 강제로 예외 객체를 만들어 발생시킴

public class ThrowExample {
    public static void main(String[] args) {
        int age = 15;

        if (age < 18) {
            throw new IllegalArgumentException("18세 미만은 접근 불가!");
        }

        System.out.println("접근 허용");
    }
}

✔️ throw 뒤에는 반드시 Throwable 을 상속받은 객체가 와야 함

2️⃣ 던지기 (throws)

👉 메서드 선언부에 "이 메서드는 이런 예외를 던질 수 있다"고 선언하는 것
👉 호출한 쪽에서 예외를 처리해야 함

import java.io.FileReader;
import java.io.IOException;

public class ThrowsExample {
    public static void main(String[] args) {
        try {
            readFile();
        } catch (IOException e) {
            System.out.println("파일을 읽는 중 오류 발생: " + e.getMessage());
        }
    }

    public static void readFile() throws IOException {
        FileReader fr = new FileReader("없는파일.txt"); // 예외 발생
    }
}

✔️ throws예외를 던지는 선언, 실제 발생은 throw로 함

3️⃣ 잡아서 처리하기 (try-catch-finally)

👉 예외가 발생할 수 있는 코드 블록을 감싸고, 예외 발생 시 처리
👉 finally는 무조건 실행됨 (자원 해제용)

public class TryCatchFinallyExample {
    public static void main(String[] args) {
        try {
            int[] arr = {1, 2};
            System.out.println(arr[5]); // 예외 발생
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("배열 인덱스 범위 초과!");
        } finally {
            System.out.println("항상 실행됨 (자원 해제 용도)");
        }
    }
}

✔️ try-catch 만 쓸 수도 있고, try-finally 만 쓸 수도 있음

4️⃣ 직접 정의하기 (Custom Exception)

👉 Exception (Checked) 또는 RuntimeException (Unchecked)을 상속받아 내가 원하는 예외를 만들 수 있음

// 나만의 예외 정의
class MyCheckedException extends Exception {
    public MyCheckedException(String message) {
        super(message);
    }
}

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

    static void checkAge(int age) throws MyCheckedException {
        if (age < 18) {
            throw new MyCheckedException("18세 미만은 접근 불가!");
        }
    }
}

✔️ Checked Exception → 반드시 throws 로 선언하고 try-catch 로 처리해야 함
✔️ Unchecked ExceptionRuntimeException 상속, 선언 안 해도 됨

profile
Fill in my own colorful colors🎨

0개의 댓글