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. 예외 처리가 필요한 이유
  • 2. 예외 처리 예제
  • 3. 예외 처리에서 로그 활용
  • 5. 예외 처리 기본 규칙
  • 6. 예외 처리 예제 코드
  1. 자바
  2. 12 오류 대비하기

오류 보충자료

1. 예외 처리가 필요한 이유

  1. 정상적인 흐름 유지:

    • 애플리케이션에서 예기치 못한 상황(에러)이 발생하더라도 애플리케이션이 중단되지 않고 실행될 수 있도록 제어.

    • 예시 상황: 사용자가 잘못된 데이터를 입력하거나 네트워크가 불안정할 경우.

  2. 리소스 낭비 방지:

    • 에러 발생 시 조치를 취하지 않으면 애플리케이션이 메모리 누수나 과부하로 인해 서버가 중단될 가능성이 있음.

  3. 코드 가독성 향상:

    • 정상 흐름과 예외 흐름을 분리하여 코드의 가독성 및 유지보수성을 높임.

  4. 디버깅 및 로그:

    • 발생한 에러를 기록(logging)하여 디버깅에 도움을 줌.

    • 로그를 통해 문제의 원인을 추적 가능.


2. 예외 처리 예제

(1) 기본적인 예외 처리: 정상 흐름 유지

코드 예시

public class ExceptionExample {
    public static void main(String[] args) {
        try {
            int result = divide(10, 0); // 0으로 나누기 시도
            System.out.println("Result: " + result);
        } catch (ArithmeticException e) {
            System.out.println("Error: Division by zero is not allowed."); // 에러 처리
        }
        System.out.println("Program continues...");
    }

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

실행 결과

Error: Division by zero is not allowed.
Program continues...

(2) 에러 발생 시 작업 누적의 문제: 메모리 누수 예제

  • 설명: 예외를 처리하지 않고 계속 실행하면 메모리 누수가 발생할 수 있음.

코드 예시

import java.util.ArrayList;
import java.util.List;

public class MemoryLeakExample {
    public static void main(String[] args) {
        List<String> memory = new ArrayList<>();
        for (int i = 0; i < 100000; i++) {
            try {
                memory.add("Data: " + i);
                if (i % 1000 == 0) {
                    throw new RuntimeException("Simulated exception");
                }
            } catch (RuntimeException e) {
                System.out.println("Exception caught: " + e.getMessage());
            }
        }
        System.out.println("Completed without fixing the memory issue.");
    }
}

실행 결과

Exception caught: Simulated exception
Exception caught: Simulated exception
...
Completed without fixing the memory issue.
  • 문제점: 리스트에 데이터가 계속 쌓이지만, 에러 발생 후 제거되지 않아 메모리 누수가 발생할 가능성이 있음.


(3) 서버 과부하 및 메모리 누적 문제

  • 상황: 서버가 며칠마다 죽는 문제 발생 → 로그 확인 시 메모리 누적 또는 디스크 용량 부족.

코드 예시

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class ServerExample {
    public static void main(String[] args) {
        while (true) {
            try (BufferedWriter writer = new BufferedWriter(new FileWriter("logs.txt", true))) {
                writer.write("Processing request...\n");
                simulateError(); // 에러 발생 가능
            } catch (IOException e) {
                System.out.println("I/O error occurred: " + e.getMessage());
            } catch (RuntimeException e) {
                System.out.println("Application error occurred: " + e.getMessage());
            }
        }
    }

    public static void simulateError() {
        if (Math.random() > 0.9) { // 10% 확률로 에러 발생
            throw new RuntimeException("Simulated runtime error");
        }
    }
}

(4) 정상 흐름과 예외 흐름의 혼합 문제

  • 문제: 정상 흐름과 예외 흐름이 섞이면 코드 이해가 어려워짐.

반환값으로 에러를 처리하는 코드

public class ReturnValueExample {
    public static void main(String[] args) {
        String result = divideWithReturn(10, 0);
        if (result.equals("Error")) {
            System.out.println("Division failed.");
        } else {
            System.out.println("Result: " + result);
        }
    }

    public static String divideWithReturn(int a, int b) {
        if (b == 0) {
            return "Error";
        }
        return String.valueOf(a / b);
    }
}

예외 처리를 활용한 코드

public class ExceptionHandlingExample {
    public static void main(String[] args) {
        try {
            int result = divide(10, 0);
            System.out.println("Result: " + result);
        } catch (ArithmeticException e) {
            System.out.println("Error: Division by zero is not allowed.");
        }
    }

    public static int divide(int a, int b) {
        return a / b;
    }
}
  • 차이점:

    • 반환값 방식: 에러와 정상 데이터가 동일한 데이터 흐름을 공유하여 혼란 발생.

    • 예외 처리 방식: 에러 흐름과 정상 흐름을 분리하여 가독성 향상.


3. 예외 처리에서 로그 활용

  • 로그 기록의 중요성:

    • 애플리케이션 실행 중 발생한 에러를 기록하여 디버깅에 도움을 줌.

    • 로그는 운영 환경에서 문제를 진단하는 주요 도구.

코드 예시: 로그 기록

import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

public class LoggingExample {
    private static final Logger logger = Logger.getLogger(LoggingExample.class.getName());

    public static void main(String[] args) {
        try {
            FileHandler fileHandler = new FileHandler("application.log", true);
            fileHandler.setFormatter(new SimpleFormatter());
            logger.addHandler(fileHandler);

            int result = divide(10, 0); // 에러 발생
            System.out.println("Result: " + result);
        } catch (ArithmeticException e) {
            logger.severe("Error: Division by zero. " + e.getMessage());
        } catch (IOException e) {
            logger.severe("Failed to set up logging. " + e.getMessage());
        }
    }

    public static int divide(int a, int b) {
        return a / b;
    }
}

로그 결과 (application.log)

SEVERE: Error: Division by zero. / by zero

4. 자바의 예외 계층 구조


(1) 예외 계층

자바의 예외는 모두 Throwable 클래스를 상속하며, 두 가지 주요 분류로 나뉩니다:

  1. Error:

    • 정의: 복구 불가능한 시스템 수준의 예외.

    • 예시: OutOfMemoryError, StackOverflowError.

  2. Exception:

    • 정의: 프로그램에서 예외적인 상황을 처리하기 위한 클래스.

    • 세부 분류:

      • 체크 예외: 개발자가 명시적으로 처리해야 함.

        • 예시: IOException, SQLException.

      • 언체크 예외: 명시적 처리 불필요, 런타임에 발생.

        • 예시: NullPointerException, IllegalArgumentException.


(2) 예외 계층 다이어그램

Throwable
   ├── Error (복구 불가능한 예외)
   │    ├── OutOfMemoryError
   │    ├── StackOverflowError
   │
   └── Exception (프로그램 예외)
        ├── Checked Exception (체크 예외)
        │    ├── IOException
        │    ├── SQLException
        │
        └── RuntimeException (언체크 예외)
             ├── NullPointerException
             ├── IllegalArgumentException
             ├── ArithmeticException

(3) 체크 예외와 언체크 예외의 차이점

특징

체크 예외

언체크 예외

정의

컴파일 시점에 명시적 예외 처리 요구

런타임 시점에 발생, 명시적 처리 불필요

대표 클래스

IOException, SQLException

NullPointerException, ArithmeticException

처리 필요 여부

반드시 try-catch 또는 throws 선언 필요

필요 없음, 자동으로 호출자에게 전달됨

예시 상황

파일 읽기/쓰기 실패, 네트워크 연결 실패

배열 인덱스 초과, null 객체 접근


5. 예외 처리 기본 규칙

(1) 기본 규칙

  1. 예외 발생 시 처리하거나 던져야 함:

    • 발생한 예외는 try-catch로 처리하거나, throws로 호출자에게 전달.

  2. 상위 타입 예외 처리:

    • 부모 타입 예외를 잡으면, 해당 타입의 모든 자식 예외도 처리 가능.


6. 예외 처리 예제 코드

(1) 체크 예외: IOException 처리

코드 예시

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

public class CheckedExceptionExample {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) {
            System.out.println(reader.readLine());
        } catch (IOException e) {
            System.out.println("Error: Unable to read file. " + e.getMessage());
        }
    }
}

실행 결과 (파일이 없을 경우)

Error: Unable to read file. test.txt (No such file or directory)

(2) 언체크 예외: NullPointerException 처리

코드 예시

public class UncheckedExceptionExample {
    public static void main(String[] args) {
        String str = null;
        try {
            System.out.println(str.length());
        } catch (NullPointerException e) {
            System.out.println("Error: Null value encountered.");
        }
    }
}

실행 결과

Error: Null value encountered.

(3) throws를 사용한 예외 전달

코드 예시

import java.io.IOException;

public class ThrowsExample {
    public static void main(String[] args) {
        try {
            readFile();
        } catch (IOException e) {
            System.out.println("Handled in main: " + e.getMessage());
        }
    }

    public static void readFile() throws IOException {
        throw new IOException("Simulated file read error.");
    }
}

실행 결과

lua코드 복사Handled in main: Simulated file read error.

(4) 상위 예외로 처리

코드 예시

public class GeneralExceptionExample {
    public static void main(String[] args) {
        try {
            throwException(1);
            throwException(2);
        } catch (Exception e) { // 부모 타입으로 모든 예외 처리
            System.out.println("Caught: " + e.getClass().getSimpleName());
        }
    }

    public static void throwException(int type) throws Exception {
        if (type == 1) {
            throw new NullPointerException("Null value!");
        } else if (type == 2) {
            throw new IllegalArgumentException("Illegal argument!");
        }
    }
}

실행 결과

Caught: NullPointerException

(5) Error 예외 예제 (복구 불가능)

코드 예시

public class ErrorExample {
    public static void main(String[] args) {
        try {
            causeError();
        } catch (Error e) {
            System.out.println("Caught: " + e.getMessage());
        }
    }

    public static void causeError() {
        throw new OutOfMemoryError("Simulated out of memory!");
    }
}

실행 결과

Caught: Simulated out of memory!

7. finally 키워드와 반드시 실행되는 블록


(1) finally 키워드란?

  • 정의: try-catch 블록이 종료될 때 항상 실행되는 코드 블록.

  • 용도:

    • 리소스 정리, 연결 해제 등 반드시 실행해야 하는 작업 처리.

    • 예외 발생 여부와 관계없이 실행됨.

  • 주의:

    • finally는 try 블록에 리턴값이 있어도 항상 실행됨.


(2) finally 사용 예제

코드 예시

public class FinallyExample {
    public static void main(String[] args) {
        try {
            System.out.println("Try block executed.");
            throw new RuntimeException("Simulated exception");
        } catch (Exception e) {
            System.out.println("Catch block executed: " + e.getMessage());
        } finally {
            System.out.println("Finally block executed. Always runs.");
        }
    }
}

실행 결과

Try block executed.
Catch block executed: Simulated exception
Finally block executed. Always runs.

(3) finally 블록 활용

  • 리소스 해제:

    • 파일, 네트워크 연결, 데이터베이스 등 외부 자원 해제.

  • 예시: 파일 닫기

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

public class FinallyFileExample {
    public static void main(String[] args) {
        FileReader reader = null;
        try {
            reader = new FileReader("test.txt");
            System.out.println("File opened.");
        } catch (IOException e) {
            System.out.println("Error reading file: " + e.getMessage());
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                    System.out.println("File closed.");
                } catch (IOException e) {
                    System.out.println("Error closing file: " + e.getMessage());
                }
            }
        }
    }
}

8. 언체크 예외와 체크 예외의 현대적 사용


(1) 언체크 예외 중심 개발

  • 현재 자바 애플리케이션 개발은 언체크 예외 중심으로 이루어짐.

  • 언체크 예외의 장점:

    • 명시적 처리 없이 자동으로 호출자에게 전달되어 코드 간결화.

  • 단점:

    • 처리하지 않은 예외가 시스템 전반으로 확산될 위험.


(2) 공통 예외 처리

  • 전략:

    • 공통 예외 처리 로직을 작성하여 대부분의 예외를 한 곳에서 처리.

    • 시스템에서 복구 불가능한 에러만 체크 예외로 처리.

코드 예시: 공통 예외 처리

public class GlobalExceptionHandler {
    public static void handleException(Exception e) {
        System.out.println("Exception handled globally: " + e.getMessage());
    }
}

public class UncheckedExceptionExample {
    public static void main(String[] args) {
        try {
            String str = null;
            System.out.println(str.length());
        } catch (Exception e) {
            GlobalExceptionHandler.handleException(e);
        }
    }
}

실행 결과

Exception handled globally: null

9. Try-with-resources (자바 7 이상)


(1) try-with-resources란?

  • 정의: try 블록에서 사용한 리소스를 자동으로 반납하는 구조.

  • 장점:

    • finally 블록 없이도 리소스 반납 가능.

    • try가 종료되면 close() 메서드가 자동으로 호출.

  • 조건:

    • 사용된 객체가 AutoCloseable 인터페이스를 구현해야 함.

    • close() 메서드를 오버라이드하여 반납 작업 정의.


(2) try-with-resources 예제

코드 예시: 파일 읽기

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

public class TryWithResourcesExample {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("Error reading file: " + e.getMessage());
        }
    }
}

실행 결과 (파일이 존재할 경우)

File content...

(3) AutoCloseable과 close() 오버라이드

코드 예시: 커스텀 리소스 관리

class CustomResource implements AutoCloseable {
    @Override
    public void close() {
        System.out.println("Resource closed automatically.");
    }

    public void use() {
        System.out.println("Using resource.");
    }
}

public class CustomResourceExample {
    public static void main(String[] args) {
        try (CustomResource resource = new CustomResource()) {
            resource.use();
        } catch (Exception e) {
            System.out.println("Exception: " + e.getMessage());
        }
    }
}

실행 결과

Using resource.
Resource closed automatically.

Previous12 오류 대비하기Next13 멀티태스킹

Last updated 5 months ago