Java에서 try~catch문, 남용하면 문제 없을까?

2024. 7. 30. 13:29개발/개념 및 기법

728x90
반응형

Java에서 예외(Exception) 처리를 할 때 흔히 사용하는 try~catch 문.

 

이걸 사용하면 아무래도 강제 종료의 위험성은 떨어진다.

하지만 남용할 때의 부작용은 없을까?


1. 예외(Exception)이란?

예외(Exception)는 프로그램 실행 중에 발생할 수 있는 비정상적인 상황을 나타내는 객체이다.

프로그램의 일반적인 흐름을 방해하며, 적절히 처리하지 않으면 프로그램이 비정상적으로 종료될 수 있다.

그렇기에 Java에서는 예외를 처리하기 위해 try~catch~finally 블록을 사용한다.

 

예외는 크게 두 가지로 분류할 수 있다.

 

1-(1) Checked Exception

Checked Exception은 컴파일 시점에서 체크되는 예외로,

반드시 try~catch 블록을 사용하여 처리하거나 throws 키워드를 사용해 선언해야 한다.

 

IOEException, SQLException, ClassNotFoundException 등과 같이 파일, 네트워크 등과의 입출력에서 발생하는 예외가 여기에 해당된다.

1-(2) Unchecked Exception

Unchecked Exception은 런타임 시점에서 발생하는 예외로, 컴파일러가 체크하지 않는다.


NullPointerException, ArrayIndexoutOfBoundsException, illegalArgumentException 등과 같이 프로그래밍 오류에서 발생하는 예외가 여이게 해당된다.


2. try~catch~finally 사용법

  • try : 예외가 발생할 가능성이 있는 코드를 포함
  • catch : 발생한 예외를 처리
  • finally : 예외 발생 여부와 관계 없이 항상 실행되는 코드
try {
    // 예외가 발생할 가능성이 있는 코드
    int result = 10 / 0;
} catch (ArithmeticException e) {
    // 예외 처리 코드
    System.out.println("ArithmeticException 발생: " + e.getMessage());
} finally {
    // 항상 실행되는 코드
    System.out.println("Finally 블록 실행");
}

 

프로그래밍을 하다보면 예외 처리를 필수로 해야하는 경우가 있다.

대표적인 예가 바로 예외의 전파이다.

 

메서드 내에서 예외가 발생하면, 해당 예외는 호출한 메서드로 전파될 수 있다.

throws 키워드를 사용하여 예외를 선언한 메서드를 호출하면 반드시 try~catch로 예외를 처리해야 한다.

public void readFile() throws IOException {
    FileInputStream file = new FileInputStream("test.txt");
    // 파일 읽기 코드
}
try {
    readFile();
} catch (IOException e) {
    e.printStackTrace();
}

3. 예외 처리가 중요한 이유

예외 처리는 프로그램의 안정성을 높이고, 예기치 않은 상황에서도 프로그램이 올바르게 동작할 수 있도록 돕는다.

  • 프로그램의 비정상 종료 방지: 예외 발생 시 프로그램이 비정상적으로 종료되는 것을 방지
  • 디버깅 용이성: 예외 메시지와 스택 트레이스를 통해 문제의 원인을 쉽게 파악 가능
  • 사용자 경험 향상: 예외 발생 시 사용자에게 적절한 메시지를 제공함으로써 사용자 경험을 향상

위와 같은 이점으로 볼 때, 적절한 예외 처리를 통해 프로그램의 안정성과 신뢰성을 높일 수 있다.


4. 예외 처리가 중요한 건 알겠어. 근데 남용해도 되는거야?

예외 처리는 프로그램의 안정성을 높이는 중요한 기법이지만, 남용할 경우 성능 저하 및 코드 가독성 문제가 일어날 수 있다. 또한 catch 문에서 적절한 대응을 해주지 않은 경우, 문제 원인을 파악하기 어려워진다.

  • 성능 저하: 예외 발생 시 스택 트레이스를 생성하고 예외 객체를 생성하는 과정은 상당한 비용이 든다. 빈번한 예외 발생은 성능 저하를 초래할 수 있습니다.
  • 코드 가독성 감소: 지나치게 많은 try-catch 블록은 코드의 가독성을 낮추고 유지보수를 어렵게 만든다.
  • 오류 은폐: 모든 예외를 포괄적으로 처리하면 실제 문제의 원인을 파악하기 어려워질 수 있다. 특히, 예외를 잡고 아무런 조치를 취하지 않거나 로그만 남기는 경우.

5. 그럼 예외처리는 어떻게 사용해야 적절할까?

5-(1) 예외는 예외적인 상황에서만 사용할 것

일반적인 흐름 제어를 위해 예외를 사용하면 안된다.

예외는 진짜 예외적인 상황에서만 사용해야 한다.

// 나쁜 예: 예외를 사용한 흐름 제어
try {
    int value = Integer.parseInt("abc"); // NumberFormatException 발생
} catch (NumberFormatException e) {
    // 예외 발생 시 다른 값 사용
    value = 0;
}

 

5-(2) 입력 검증을 통한 예외 방지

가능하다면 예외가 발생하기 전에 입력을 검증하여 예외를 방지할 것!

// 좋은 예: 입력 검증을 통한 예외 방지
String input = "abc";
if (input.matches("\\d+")) {
    int value = Integer.parseInt(input);
} else {
    value = 0; // 기본값 사용
}

 

5-(3) 특정 예외만 잡기

포괄적인 Exception을 잡기보다는 특정 예외를 잡아 처리해야 한다.

이렇게 하면 실제로 발생한 예외의 원인을 더 잘 파악할 수 있다.

Exception 하나만으로 퉁치는 예외처리는 가장 최악 !!

try {
    // 코드 실행
} catch (NullPointerException e) {
    // NullPointerException 처리
} catch (IOException e) {
    // IOException 처리
} catch (Exception e) {
    // 기타 예외 처리
}

5-(4) 예외 정보 로깅 및 재발생

예외 발생 시 로그를 남기고 필요한 경우 예외를 재발생시켜 호출자에게 문제를 알려야 한다.

try {
    // 코드 실행
} catch (IOException e) {
    // 예외 정보 로깅
    logger.error("IOException 발생: " + e.getMessage());
    // 예외 재발생
    throw e;
}

5-(5) 자원 해제는 반드시 finally 또는 try-with-resources 사용

파일, 데이터베이스 연결 등 자원을 사용하는 경우, 예외 발생 여부와 관계없이 자원을 해제해야 한다.

이를 위해 finally 블록이나 try-with-resources 문법을 사용할 것.

// try-with-resources 사용 예
try (FileInputStream fileInputStream = new FileInputStream("test.txt")) {
    // 파일 읽기 코드
} catch (IOException e) {
    // 예외 처리
}

6. 결론

예외 처리는 프로그램의 안정성을 높이는 데 필수적이지만, 남용하면 성능 저하 및 코드 가독성 문제를 일으킬 수 있다.

따라서 예외 처리는 진짜 예외적인 상황에서만 사용하고,  입력 검증을 통해 예외를 미리 방지하며,  특정 예외를 잡아 처리하는 것이 좋다.

또한, 자원 해제는 반드시 보장되도록 finally 블록이나 try-with-resources 문법을 사용해야 한다.

이러한 가이드라인을 따르면 보다 안정적이고 유지보수하기 쉬운 코드를 작성할 수 있다.

728x90
반응형

'개발 > 개념 및 기법' 카테고리의 다른 글

Kotlin Multiplatform (KMP)  (0) 2025.01.24
JVM이란?  (1) 2025.01.23
[개발 기본 개념]비트 연산자  (0) 2023.05.26
참조  (1) 2023.02.24
Interface(인터페이스)  (0) 2021.07.26