backend
  • README
  • DOCS
    • Java Docs
    • Servlet Docs
    • JSP Docs
    • DB & SQL Docs
    • Spring Boot Docs
    • Spring Security Docs
    • AWS Docs
  • 설치하기
    • Intellij 설정
  • 자바
    • 01 Java란?
    • 02 자바 시작하기
    • 03 자료형과 연산자
    • 04 제어문
    • 05 메소드
    • 06 클래스 기초
      • Static 보충자료
      • 패키지 보충자료
    • 07 객체지향 프로그래밍
    • 08 클래스 더 알아보기
      • 열거형 ENUM 보충자료
    • 09 클래스와 자료형
      • 다형성 보충자료
      • 제네릭 보충자료
    • 10 컬렉션 프레임워크
      • 컬렉션 프레임워크 보충자료
    • 11 람다식과 함수형 프로그래밍
      • 람다식 보충자료
    • 12 오류 대비하기
      • 오류 보충자료
    • 13 멀티태스킹
      • 멀티태스킹 보충자료
    • 교재보충
      • java.lang
  • 스프링
    • 서블릿, JSP
      • 05 Servlet(서블릿)
        • 서블릿 보충자료
        • 서블릿 추가코드
        • XML, YAML, JSON
      • 06 JSP(자바 서버 페이지)
        • JSP 보충자료
      • 07 JSTL(JSP 스탠다드 태그 라이브러리)
        • JSTL 보충자료
      • 08 Cookie(쿠키), Session(세션)
      • 09 서블릿,필터,리스너
        • 서블릿,필터,리스너 보충자료
      • 11 도서관리 프로젝트 실습
    • Spring Boot
      • 01 스프링 등장 배경, 객체지향
        • 스프링 등장 배경, 객체지향 보충자료
      • 02 IOC(제어의 역전), DI(의존성 주입)
        • IOC 보충자료
        • DI 보충자료
      • 03 스프링 구조
        • 스프링 구조 보충설명
      • 04 테스트코드 실습
      • 05 스프링 빈 설정
        • 스프링 빈 설정 보충자료
      • 06 싱글톤
        • 싱글톤 보충 자료
      • 07 스프링 빈 자동설정
        • 스프링 빈 자동설정 보충자료
      • 08 빈 생명주기
        • 빈 생명주기 보충자료
      • 09 빈 스코프
        • 빈 스코프 보충자료
      • 10 스프링 MVC
        • 스프링 MVC 보충자료
        • 데이터베이스 연동에 필요한 부분
      • 11 Validation(검증)
        • Validation(검증) 보충자료
      • 12 Bean Validation(빈검증)
        • Bean Validation(빈검증) 보충자료
      • 13 예외처리
        • 예외처리 보충자료
      • 14 타입변환
      • 15 JDBC(Java Database Connectivity)
      • 16 커넥션풀
      • 17 트랜잭션
        • 트랜잭션 보충자료
      • 18 JDBC 템플릿 활용
      • 19 MyBatis
      • 20 JPA(Java Persistence API)
      • 22 게시판 프로젝트 실습
    • Spring Security
      • 보안(Security)
      • Spring Security
      • 2. Spring Security 알아보기
        • 보안 위협 실제 사례와 방어 전략
      • 3. Spring Security 기본 동작 흐름
      • 4. Spring Security로 인증 권한 추가하기
        • Spring Security의 인증 및 인가
      • 5. Spring Security에서 세션 관리하기
        • 세션(Session)과 쿠키(Cookie) 비교, 토큰(Token)과의 관계
        • 해싱 및 해싱알고리즘
        • base64
      • 6. Spring Security 악용 보호
        • SameSite
      • 7. Spring Security로 인가 권한 추가하기
      • 8. Bcrypt(비크립트) 암호화
      • OAuth2 적용하기
  • 네트워크
    • HTTP
    • OSI 7계층
  • DB&SQL
    • 01 Database(데이터베이스)와 SQL 개요
    • 02 관계형 모델
    • 03 집합
    • 04 JOIN 연산
    • 05 MySQL
      • 세이브포인트
      • DBeaver, Mysql 오토커밋 설정 관련
    • 06 SQL 기초
      • 예시데이터 쿼리문
    • 07 SQL 실습
      • 실습 스키마
    • 08 Join 활용
      • 실습스키마
    • 09 SQL 활용
      • 실습스키마
    • 10 정규화
      • 실습 스키마
    • 데이터타입
    • 예시 프로젝트 스키마 구성
  • AWS
    • SSL 연결하기
    • 보충설명
Powered by GitBook
On this page
  • 오류와 에러
  • 1. 컴파일 오류 (Compile-time Error)
  • 예시: 컴파일 오류
  • 2. 런타임 오류 (Runtime Error)
  • 런타임 오류의 종류: Error와 Exception
  • 1. Error
  • Error 예시
  • 2. Exception
  • Exception 예시 (체크 예외)
  • Exception 예시 (언체크 예외)
  • 3. Error와 Exception의 차이
  • 4. 예외 처리 방법
  • 예외 처리 예시
  • 5. 정리
  • 예외 정의하고 발생시키기
  • 예외 떠넘기기 (Throwing an Exception)
  • 예시: 예외 떠넘기기
  • 코드 설명
  • 출력 결과
  • 예외 되던지기 (Rethrowing an Exception)
  • 예시: 예외 되던지기
  • 코드 설명
  • 출력 결과
  • 예외의 버블링(Exception Bubbling)
  • 예외 버블링의 작동 방식
  • 예시: 예외의 버블링
  • 코드 설명
  • 출력 결과
  • 버블링의 장점
  • 주의사항
  • Chained Exception (연쇄 예외)
  • 1. 연쇄 예외 사용법
  • 2. 연쇄 예외의 사용 예시
  • 코드 설명
  • 출력 결과
  • 연쇄 예외 사용이유
  • try-with-resources
  • try-with-resources 구문 사용법
  • try-with-resources 기본 구조
  • try-with-resources 예제: 파일 읽기
  • 코드 설명
  • try-with-resources와 기존 try-catch-finally 비교
  • 비교
  • AutoCloseable 인터페이스
  • 사용자 정의 자원 클래스와 try-with-resources
  • 출력 결과
  • NullPointerException와 Optional
  • NPE (NullPointerException)
  • 1. NullPointerException 발생 예시
  • 2. NPE 방지 방법
  • Optional 클래스
  • 4. Optional 생성 및 사용 방법
  • 5. Optional의 주요 메소드
  • 6. Optional을 이용한 NPE 방지 예시
  • NPE 위험이 있는 코드
  • Optional을 사용한 안전한 코드
  1. 자바

12 오류 대비하기

오류와 에러

자바에서 오류는 크게 컴파일 오류와 런타임 오류로 나눌 수 있습니다. 이 두 가지 오류는 발생 시점과 원인이 다르며, 각각의 처리 방법이 다릅니다. 또한, 런타임 오류는 Error와 Exception으로 구분됩니다.

1. 컴파일 오류 (Compile-time Error)

  • 발생 시점: 컴파일 오류는 코드가 컴파일될 때 발생합니다. 즉, 프로그램을 실행하기 전에 컴파일러가 코드를 번역하는 단계에서 발생합니다.

  • 원인: 컴파일 오류는 주로 문법적인 오류, 타입 불일치, 존재하지 않는 변수나 메소드 사용 등과 같은 문제 때문에 발생합니다. 컴파일 오류가 있는 경우, 컴파일러는 프로그램을 바이트코드로 변환하지 못하므로 실행할 수 없습니다.

예시: 컴파일 오류

edu.ch12. error패키지

public class CompileErrorExample {
    public static void main(String[] args) {
        int number = "Hello";  // 오류: 문자열을 정수에 할당할 수 없음 (타입 불일치)
        System.out.println(number);
    }
}

위 코드에서는 int 타입의 변수에 문자열을 할당하려고 하기 때문에 타입 불일치 오류가 발생하여 컴파일이 되지 않습니다.

2. 런타임 오류 (Runtime Error)

  • 발생 시점: 런타임 오류는 프로그램이 실행되는 동안 발생하는 오류입니다. 컴파일러는 코드를 번역할 때 이 오류를 감지하지 못하며, 실행 중에 특정 조건이 발생했을 때 나타납니다.

  • 원인: 주로 잘못된 사용자 입력, 파일의 부재, 배열의 인덱스 초과, null 참조, 네트워크 연결 문제 등과 같이 실행 중에 예측할 수 없는 상황에서 발생합니다.

런타임 오류의 종류: Error와 Exception

런타임 오류는 자바에서 Error와 Exception으로 분류됩니다. 이 두 가지는 모두 Throwable 클래스를 상속받지만, 그 목적과 처리 방법이 다릅니다.

1. Error

  • 설명: Error는 자바 프로그램에서 복구할 수 없는 심각한 문제를 나타냅니다. 일반적으로 애플리케이션이 처리할 수 없으며, 개발자가 직접 예외 처리(try-catch)를 하지 않습니다. 이러한 오류는 주로 JVM의 심각한 문제에서 발생합니다.

  • 예시:

    • OutOfMemoryError: 메모리가 부족할 때 발생합니다.

    • StackOverflowError: 스택 메모리가 가득 차서 더 이상 메소드를 호출할 수 없을 때 발생합니다.

    • InternalError: JVM 내부에 문제가 발생했을 때 발생합니다.

  • 처리 방법: 일반적으로 Error는 프로그램에서 직접 처리하지 않습니다. 이는 시스템 수준의 심각한 문제이기 때문에 프로그램이 강제 종료되는 것이 대부분의 대응 방식입니다.

Error 예시

edu.ch12. error패키지

public class ErrorExample {
    public static void main(String[] args) {
        // 무한 재귀 호출로 인한 StackOverflowError 발생
        recursiveMethod();
    }

    public static void recursiveMethod() {
        recursiveMethod();
    }
}

위 코드에서는 메소드가 무한히 재귀 호출되기 때문에 StackOverflowError가 발생합니다. 이는 스택 메모리의 한계로 인한 오류로 복구할 수 없습니다.

2. Exception

  • 설명: Exception은 프로그램이 실행되는 동안에 발생할 수 있는 예외적인 상황을 나타냅니다. 대부분의 경우 개발자가 예외를 예측하고 처리할 수 있습니다.

  • 종류:

    • 체크 예외(Checked Exception): 컴파일러가 예외 처리를 요구하는 예외로, 컴파일 시점에 예외 처리를 강제합니다. 예를 들어, 파일 입출력 시 발생하는 IOException 등이 있습니다.

    • 언체크 예외(Unchecked Exception, 런타임 예외): 컴파일러가 예외 처리를 강제하지 않는 예외로, 주로 프로그래밍 실수에 의해 발생합니다. 예를 들어, NullPointerException, ArrayIndexOutOfBoundsException 등이 있습니다.

  • 처리 방법: Exception은 주로 try-catch 블록을 사용하여 처리하거나, 메소드에 throws 키워드를 사용하여 호출자에게 예외를 전달할 수 있습니다.

Exception 예시 (체크 예외)

edu.ch12.exception 패키지

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class CheckedExceptionExample {
    public static void main(String[] args) {
        try {
            // 체크 예외 발생 가능
            File file = new File("nonexistentfile.txt");
            Scanner scanner = new Scanner(file);
        } catch (FileNotFoundException e) {
            System.out.println("파일을 찾을 수 없습니다: " + e.getMessage());
        }
    }
}

위 코드에서는 존재하지 않는 파일을 열려고 시도하기 때문에 FileNotFoundException이 발생합니다. 이 예외는 체크 예외이므로 컴파일러가 예외 처리를 요구하며, try-catch 블록으로 예외를 처리해야 합니다.

Exception 예시 (언체크 예외)

edu.ch12.exception 패키지

public class UncheckedExceptionExample {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3};

        // 언체크 예외 발생 가능
        System.out.println(numbers[5]);  // ArrayIndexOutOfBoundsException 발생
    }
}

위 코드에서는 배열의 유효한 인덱스 범위를 벗어난 인덱스에 접근하려고 하기 때문에 ArrayIndexOutOfBoundsException이 발생합니다. 이는 언체크 예외이므로 컴파일러가 예외 처리를 강제하지 않습니다.

3. Error와 Exception의 차이

특성

Error

Exception

발생 시점

주로 시스템 수준에서 발생하는 심각한 문제

애플리케이션 수준에서 발생하는 예외 상황

복구 가능성

대부분 복구 불가능

예외 처리를 통해 복구 가능

예외 처리

일반적으로 처리하지 않음

try-catch로 처리 가능

예시

OutOfMemoryError, StackOverflowError

IOException, NullPointerException 등

4. 예외 처리 방법

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

예외 처리 예시

edu.ch12.exception 패키지

public class ExceptionHandlingExample {
    public static void main(String[] args) {
        try {
            int result = 10 / 0;  // ArithmeticException 발생
        } catch (ArithmeticException e) {
            System.out.println("0으로 나눌 수 없습니다: " + e.getMessage());
        } finally {
            System.out.println("예외 처리 완료.");
        }
    }
}

5. 정리

  • 컴파일 오류: 코드를 컴파일할 때 발생하며, 주로 문법적인 오류로 인해 발생합니다.

  • 런타임 오류: 프로그램 실행 중에 발생하며, 주로 실행 중인 환경이나 입력 값에 의해 발생합니다. 이는 다시 Error와 Exception으로 분류됩니다.

    • Error: 프로그램이 복구할 수 없는 심각한 시스템 수준의 문제입니다. 개발자가 직접 처리하지 않으며, OutOfMemoryError, StackOverflowError 등이 있습니다.

    • Exception: 프로그램이 예측하고 처리할 수 있는 예외 상황입니다. IOException과 같은 체크 예외와 NullPointerException과 같은 언체크 예외로 나뉩니다.

예외 정의하고 발생시키기

throw 키워드를 사용하여 사용자 정의 예외를 발생시키는 방법을 예시를 통해 알아보겠습니다. 예외를 직접 발생시키고 싶을 때 throw를 사용하며, 이를 통해 특정 조건에서 예외를 발생시켜 프로그램의 흐름을 제어할 수 있습니다.

예외 떠넘기기 (Throwing an Exception)

  • 예외를 직접 처리하지 않고, 호출한 곳에서 처리하도록 던지는 것.

  • 메소드 선언에 throws 키워드를 사용하여 떠넘길 예외를 명시.

  • 예외를 처리하는 책임을 메소드를 호출한 곳으로 넘깁니다.

  • 용도: 메소드에서 발생한 예외를 즉시 처리하지 않고, 호출한 곳에서 처리해야 할 때 사용됩니다.

예시: 예외 떠넘기기

edu.ch12.exception.handlingAnException 패키지

// 사용자 정의 예외 클래스
class InvalidAgeException extends Exception {
    public InvalidAgeException(String message) {
        super(message);
    }
}

public class ThrowingExample {
    // 예외를 떠넘기는 메소드
    public static void checkAge(int age) throws InvalidAgeException {
        if (age < 0) {
            // 예외를 발생시키고 떠넘김
            throw new InvalidAgeException("나이는 음수일 수 없습니다: " + age);
        } else {
            System.out.println("나이는 정상입니다: " + age);
        }
    }

    public static void main(String[] args) {
        try {
            checkAge(25);  // 정상 실행
            checkAge(-5);  // 예외 발생
        } catch (InvalidAgeException e) {
            // 예외를 떠넘겨 받아서 처리
            System.out.println("예외 처리: " + e.getMessage());
        }
    }
}

코드 설명

  • checkAge 메소드: throws InvalidAgeException으로 해당 메소드가 InvalidAgeException을 던질 수 있음을 명시합니다. 이 메소드에서 예외가 발생하면 메소드를 호출한 곳으로 예외를 떠넘깁니다.

  • main 메소드: try-catch 블록에서 checkAge 메소드를 호출하고, 떠넘겨진 예외를 받아서 처리합니다.

출력 결과

나이는 정상입니다: 25
예외 처리: 나이는 음수일 수 없습니다: -5

예외 되던지기 (Rethrowing an Exception)

  • 예외를 잡아서 일부 처리한 후, 다시 예외를 던져 호출한 곳에서도 추가 처리를 할 수 있도록 하는 것.

  • 내부에서 예외를 처리하면서 로깅, 정리 작업 등을 수행한 후에 예외를 다시 던집니다.

  • 호출한 쪽에서 추가적인 예외 처리가 필요한 경우에 유용합니다.

  • 용도: 메소드 내부에서 예외를 일부 처리하거나 기록한 후에, 호출한 쪽에서 나머지 처리를 할 수 있도록 예외를 다시 던질 때 사용됩니다.

예시: 예외 되던지기

edu.ch12.exception.handlingAnException 패키지

// 사용자 정의 예외 클래스
class InvalidAgeException extends Exception {
    public InvalidAgeException(String message) {
        super(message);
    }
}

public class RethrowingExample {
    // 예외를 처리하고 다시 던지는 메소드
    public static void checkAge(int age) throws InvalidAgeException {
        try {
            if (age < 0) {
                // 예외 발생
                throw new InvalidAgeException("나이는 음수일 수 없습니다: " + age);
            } else {
                System.out.println("나이는 정상입니다: " + age);
            }
        } catch (InvalidAgeException e) {
            // 예외를 일부 처리하고 다시 던짐
            System.out.println("예외 처리 중: " + e.getMessage());
            throw e;  // 예외를 다시 던짐
        }
    }

    public static void main(String[] args) {
        try {
            checkAge(25);  // 정상 실행
            checkAge(-5);  // 예외 발생
        } catch (InvalidAgeException e) {
            // 다시 던져진 예외를 처리
            System.out.println("메인에서 예외 처리: " + e.getMessage());
        }
    }
}

코드 설명

  • checkAge 메소드: 내부에서 예외를 발생시키고 처리한 뒤, throw e;를 통해 예외를 다시 던집니다. 이는 호출한 곳에서 추가적으로 예외 처리를 할 수 있도록 합니다.

  • main 메소드: try-catch 블록에서 checkAge 메소드를 호출하고, 다시 던져진 예외를 받아서 처리합니다.

출력 결과

나이는 정상입니다: 25
예외 처리 중: 나이는 음수일 수 없습니다: -5
메인에서 예외 처리: 나이는 음수일 수 없습니다: -5

예외의 버블링(Exception Bubbling)

예외의 버블링은 메소드에서 발생한 예외가 처리되지 않고 호출된 상위 메소드로 전달되는 과정을 의미합니다.(거품처럼 올라간다 하여 버블링) 예외는 처음 발생한 곳에서 처리되지 않으면, 해당 예외를 호출한 메소드로 전달되고, 계속해서 상위 메소드로 전파됩니다. 이런 과정은 스택 트레이스(Stack Trace)를 통해 역추적할 수 있습니다.

예외의 버블링은 특정 예외가 발생했을 때 하위 메소드가 아닌 상위 메소드에서 예외를 처리하고자 할 때 사용됩니다. 이를 통해 코드를 간결하게 유지하고, 예외 처리를 중앙화할 수 있습니다.

예외 버블링의 작동 방식

  1. 예외가 발생하면, 해당 예외를 처리할 수 있는 try-catch 블록을 찾습니다.

  2. 예외를 처리할 수 있는 catch 블록이 없다면, 예외는 발생한 메소드의 호출 스택에서 상위 메소드로 전파됩니다.

  3. 이 과정이 계속 반복되며, 최종적으로 main 메소드까지 도달합니다.

  4. main 메소드에서도 예외를 처리하지 않으면, 프로그램이 비정상 종료되고 스택 트레이스가 출력됩니다.

예시: 예외의 버블링

다음 코드는 여러 메소드에서 예외를 발생시키고, 상위 메소드에서 처리하는 예시를 보여줍니다.

edu.ch12.exception.handlingAnException 패키지

// 사용자 정의 예외 클래스
class InvalidAgeException extends Exception {
    public InvalidAgeException(String message) {
        super(message);
    }
}

public class ExceptionBubblingExample {
    // 예외를 발생시키는 메소드
    public static void checkAge(int age) throws InvalidAgeException {
        if (age < 0) {
            // 예외 발생
            throw new InvalidAgeException("나이는 음수일 수 없습니다: " + age);
        }
    }

    // 예외를 떠넘기는 메소드
    public static void processAge(int age) throws InvalidAgeException {
        checkAge(age); // 예외를 다시 떠넘김
    }

    public static void main(String[] args) {
        try {
            processAge(-5);  // 여기서 예외가 발생하고 버블링됨
        } catch (InvalidAgeException e) {
            // 버블링된 예외를 여기서 처리
            System.out.println("예외 처리: " + e.getMessage());
        }
    }
}

코드 설명

  • checkAge 메소드: 나이가 음수인 경우 InvalidAgeException을 발생시키고 예외를 떠넘깁니다.

  • processAge 메소드: checkAge 메소드를 호출하지만 예외를 직접 처리하지 않고 떠넘깁니다.

  • main 메소드: 최상위 메소드로, processAge를 호출하면서 예외를 처리합니다. checkAge에서 발생한 예외가 버블링되어 main 메소드까지 도달하여 처리됩니다.

출력 결과

예외 처리: 나이는 음수일 수 없습니다: -5

버블링의 장점

  1. 중앙 집중식 예외 처리: 예외 처리를 코드의 최상위 또는 논리적으로 처리하기 적절한 위치에서 수행할 수 있습니다.

  2. 코드 가독성 향상: 메소드 내부에서 예외를 직접 처리하지 않고 상위 메소드로 예외를 던져, 하위 메소드를 간결하게 유지할 수 있습니다.

  3. 재사용성: 하위 메소드에서 세부적인 예외 처리를 강제하지 않음으로써, 재사용이 용이합니다.

주의사항

  • 모든 예외를 최상위 메소드로 떠넘기지 마세요: 모든 예외를 버블링으로 처리하면 프로그램의 예외 처리 논리가 복잡해질 수 있습니다. 상황에 따라 적절한 곳에서 예외를 처리해야 합니다.

  • 적절한 예외 처리 위치 결정: 어디에서 예외를 처리할 것인지는 코드의 목적과 흐름에 따라 결정해야 합니다. 중요한 것은 예외를 적절한 곳에서 처리하여 프로그램의 안정성을 유지하는 것입니다.

Chained Exception (연쇄 예외)

연쇄 예외(Chained Exception)는 한 예외가 다른 예외의 원인이 될 때 이를 체인 형태로 연결하는 기능입니다. 예외가 발생하는 상황에서, 어떤 예외가 새로운 예외의 원인이 되었는지를 추적하는 데 사용됩니다. 이 방식은 문제의 근본 원인을 파악하는 데 도움이 되며, 예외 처리에 있어 더욱 자세한 정보를 제공할 수 있습니다.

자바에서는 Throwable 클래스에서 제공하는 원인 예외(cause exception) 설정을 통해 연쇄 예외를 구현할 수 있습니다. 즉, 하나의 예외가 발생하면 그 예외의 원인으로 다른 예외를 연결하여 예외 발생의 원인을 추적할 수 있습니다.

1. 연쇄 예외 사용법

자바에서 연쇄 예외를 구현하는 방법은 다음과 같습니다:

  1. 예외 생성자의 인수로 원인 예외를 전달하여 연쇄 예외를 생성할 수 있습니다.

  2. Throwable 클래스의 initCause(Throwable cause) 메소드를 사용하여 원인 예외를 설정할 수 있습니다.

  3. getCause() 메소드를 통해 원인 예외를 얻을 수 있습니다.

2. 연쇄 예외의 사용 예시

edu.ch12.exception.handlingAnException 패키지

public class ChainedExceptionExample {
    // 파일 읽기 예외 처리 메소드
    public static void readFile() throws Exception {
        try {
            throw new NullPointerException("파일 객체가 null입니다."); // 원인 예외 발생
        } catch (NullPointerException e) {
            // 새로운 예외를 발생시키면서 원인 예외를 전달
            throw new Exception("파일을 읽는 중에 예외가 발생했습니다.", e);
        }
    }

    public static void main(String[] args) {
        try {
            readFile();
        } catch (Exception e) {
            // 예외의 메시지와 원인 예외를 출력
            System.out.println("최종 예외: " + e.getMessage());
            System.out.println("원인 예외: " + e.getCause());
        }
    }
}

코드 설명

  • readFile 메소드:

    • NullPointerException을 발생시킵니다. 이 예외는 파일 객체가 null일 때 발생한다고 가정합니다.

    • catch 블록에서 새로운 Exception을 발생시키면서 NullPointerException을 원인 예외(cause)로 전달합니다.

    • 새로운 예외는 "파일을 읽는 중에 예외가 발생했습니다."라는 메시지를 가지고 있으며, NullPointerException을 원인으로 포함합니다.

  • main 메소드:

    • readFile 메소드를 호출하고, 연쇄된 예외를 처리합니다.

    • getMessage()로 최종 예외의 메시지를 출력하고, getCause()로 원인 예외를 출력합니다.

출력 결과

최종 예외: 파일을 읽는 중에 예외가 발생했습니다.
원인 예외: java.lang.NullPointerException: 파일 객체가 null입니다.

연쇄 예외 사용이유

  • 근본 원인 파악: 예외가 여러 단계의 메소드 호출을 거쳐 발생할 때, 연쇄 예외를 사용하면 문제의 근본 원인을 파악할 수 있습니다.

  • 추적 용이성: 예외를 처리하는 과정에서 원인 예외를 포함함으로써 스택 추적 정보를 보존하고, 디버깅을 쉽게 할 수 있습니다.

  • 의미 있는 예외 전환: 하위 레벨의 예외를 상위 레벨의 의미 있는 예외로 전환하면서도, 원래의 예외를 유지할 수 있습니다.

try-with-resources

try-with-resources 구문 사용법

  • try 블록의 괄호 안에 닫아야 하는 자원을 선언합니다. 이 자원은 AutoCloseable 인터페이스를 구현해야 합니다.

  • try 블록이 끝나면 자원이 자동으로 닫힙니다.

  • 기존의 try-catch-finally 구문보다 훨씬 간결하고 안전한 방식으로 자원을 관리할 수 있습니다.

try-with-resources 기본 구조

try (자원 선언 및 생성) {
    // 자원을 사용하는 코드
} catch (예외 타입 e) {
    // 예외 처리 코드
}

try-with-resources 예제: 파일 읽기

다음 예제에서는 try-with-resources를 사용하여 파일을 읽는 작업을 수행하고, 사용된 자원(BufferedReader)을 자동으로 닫아줍니다.

edu.ch12.exception.handlingAnException 패키지

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

public class TryWithResourcesExample {
    public static void main(String[] args) {
        // try-with-resources 구문 사용
        try (BufferedReader br = new BufferedReader(new FileReader("example.txt"))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("파일을 읽는 도중 예외가 발생했습니다: " + e.getMessage());
        }
    }
}

코드 설명

  • try 구문: BufferedReader 자원을 try 괄호 안에 선언하여 자동으로 자원을 닫도록 합니다.

  • catch 블록: 파일을 읽는 도중 발생할 수 있는 IOException을 처리합니다.

  • 자원 자동 닫힘: try 블록이 끝나면 BufferedReader가 자동으로 닫힙니다. 수동으로 br.close()를 호출할 필요가 없습니다.

try-with-resources와 기존 try-catch-finally 비교

try-with-resources를 사용하지 않고 기존의 try-catch-finally를 사용하여 자원을 닫는 경우는 다음과 같습니다:

edu.ch12.exception.handlingAnException 패키지

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

public class TraditionalTryCatchExample {
    public static void main(String[] args) {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader("example.txt"));
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("파일을 읽는 도중 예외가 발생했습니다: " 
	            + e.getMessage());
        } finally {
            // 자원을 수동으로 닫아야 함
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    System.out.println("자원을 닫는 도중 예외가 발생했습니다: " 
	                    + e.getMessage());
                }
            }
        }
    }
}

비교

  • 코드 길이: try-with-resources를 사용하면 finally 블록이 필요 없으므로 코드가 훨씬 간결해집니다.

  • 자원 닫힘 보장: try-with-resources는 예외 발생 여부와 상관없이 항상 자원을 닫아줍니다.

  • 에러 처리 단순화: 기존 방식에서는 자원을 수동으로 닫는 과정에서 예외가 발생할 수 있으며, 이를 추가로 처리해야 하지만, try-with-resources에서는 자동으로 처리됩니다.

AutoCloseable 인터페이스

try-with-resources 구문에서 사용할 수 있는 자원은 반드시 AutoCloseable 인터페이스를 구현해야 합니다. AutoCloseable 인터페이스에는 close() 메소드가 선언되어 있어, 자원이 더 이상 필요하지 않을 때 자동으로 호출됩니다.

사용자 정의 자원 클래스와 try-with-resources

사용자 정의 클래스에서도 AutoCloseable 또는 Closeable 인터페이스를 구현하면 try-with-resources를 사용할 수 있습니다.

edu.ch12.exception.handlingAnException 패키지

class CustomResource implements AutoCloseable {
    public void doSomething() {
        System.out.println("자원을 사용하고 있습니다.");
    }

    @Override
    public void close() {
        System.out.println("자원을 닫습니다.");
    }
}

public class CustomResourceExample {
    public static void main(String[] args) {
        try (CustomResource resource = new CustomResource()) {
            resource.doSomething();
        }
    }
}

출력 결과

자원을 사용하고 있습니다.
자원을 닫습니다.

NullPointerException와 Optional

NPE (NullPointerException)

NPE는 NullPointerException의 약자로, 자바에서 가장 흔하게 발생하는 런타임 오류 중 하나입니다. 이 예외는 널(null) 참조에 대해 메소드 호출, 필드 접근, 배열 접근 등의 작업을 수행하려고 할 때 발생합니다.

1. NullPointerException 발생 예시

edu.ch12.exception.nullAndOptional 패키지

public class NPEExample {
    public static void main(String[] args) {
        String str = null;  // str이 null로 초기화됨

        // NPE 발생: null 객체에 대해 메소드 호출
        System.out.println(str.length());
    }
}

위 코드에서는 str 변수가 null이므로 str.length()를 호출하면 NullPointerException이 발생합니다.

2. NPE 방지 방법

  • 널 체크: 객체를 사용하기 전에 반드시 null 체크를 하는 습관을 들입니다.

    if (str != null) {
        System.out.println(str.length());
    }
  • 삼항 연산자 사용: null일 경우에 대한 처리 로직을 포함하여 안전하게 사용할 수 있습니다.

    int length = (str != null) ? str.length() : 0;
  • Optional 클래스 사용: 자바 8에 추가된 **Optional*을 사용하면 NPE를 방지하고, 더 안전하게 코드를 작성할 수 있습니다.

Optional 클래스

  • Optional은 자바 8에서 도입된 클래스입니다. 이는 null이 될 수 있는 객체를 감싸는 컨테이너로, 객체가 null인지 여부를 명시적으로 처리할 수 있게 도와줍니다. Optional을 사용하면 NPE를 예방하고, 명시적인 null 처리를 할 수 있어 코드의 안정성과 가독성을 향상시킵니다.

4. Optional 생성 및 사용 방법

  • Optional 생성: Optional은 주로 정적 팩토리 메소드인 of(), ofNullable(), empty()를 사용하여 생성합니다.

edu.ch12.exception.nullAndOptional 패키지

import java.util.Optional;

public class OptionalExample {
    public static void main(String[] args) {
        String str = "Hello, World!";

        // Optional 생성
        // str이 null이 아니어야 함
        Optional<String> optionalStr = Optional.of(str);

        // Optional.empty()로 빈 Optional 생성
        Optional<String> emptyOptional = Optional.empty();

        // Optional.ofNullable()로 null 가능성이 있는 객체를 감쌈
        Optional<String> nullableOptional = Optional.ofNullable(null);
    }
}

5. Optional의 주요 메소드

edu.ch12.exception.nullAndOptional 패키지 OptionalExample 클래스

  • isPresent(): 값이 존재하는지 여부를 반환합니다.

    optionalStr.isPresent();  // true
    nullableOptional.isPresent();  // false
  • isEmpty(): 값이 비어있는지의 여부를 반환합니다.

    optionalStr.isEmpty();  // false
    nullableOptional.isEmpty();  // true
  • ifPresent(Consumer<? super T> action): 값이 존재하면 해당 값에 대해 동작을 수행합니다.

    optionalStr.ifPresent(s -> System.out.println(s));  // 출력: Hello, World!
  • orElse(T other): 값이 존재하면 해당 값을 반환하고, 그렇지 않으면 기본 값을 반환합니다.

    String result = nullableOptional.orElse("Default Value");
    System.out.println(result);  // 출력: Default Value
  • orElseGet(Supplier<? extends T> other): 값이 존재하지 않을 때, 람다식이나 메소드를 통해 기본 값을 제공합니다.

    String result = nullableOptional.orElseGet(() -> "Generated Default Value");
    System.out.println(result);  // 출력: Generated Default Value
  • orElseThrow(Supplier<? extends X> exceptionSupplier): 값이 존재하지 않을 때 예외를 던집니다.

    String result = nullableOptional.orElseThrow(() -> 
    	new IllegalArgumentException("값이 없습니다."));
  • map(Function<? super T, ? extends U> mapper): 값을 변환하여 새로운 Optional을 반환합니다. 만약 값이 존재하지 않으면 빈 Optional을 반환합니다.

    Optional<Integer> length = optionalStr.map(String::length);
    System.out.println(length.orElse(0));  // 출력: 13

6. Optional을 이용한 NPE 방지 예시

NPE 위험이 있는 코드

edu.ch12.exception.nullAndOptional.prevetionNPE 패키지

public class NPEExample {
    public static void main(String[] args) {
        String str = null;

        // NPE 발생 가능
        if (str.length() > 0) {
            System.out.println("String is not empty");
        }
    }
}

Optional을 사용한 안전한 코드

edu.ch12.exception.nullAndOptional.prevetionNPE 패키지

import java.util.Optional;

public class OptionalExample {
    public static void main(String[] args) {
        String str = null;

        // Optional을 이용하여 안전하게 처리
        Optional<String> optionalStr = Optional.ofNullable(str);

        optionalStr.ifPresent(s -> {
            if (s.length() > 0) {
                System.out.println("String is not empty");
            }
        });
    }
}
Previous람다식 보충자료Next오류 보충자료

Last updated 6 months ago