본문 바로가기

Study/Java

[JAVA socket 통신] Java에서 Runnable의 run 메서드 내 IOException 처리 방법

 

 

 

Java에서 Runnable의 run 메서드 내 IOException 처리 방법

문제 상황

Runnable 인터페이스의 run 메서드는 예외를 던질 수 없기 때문에, IOException과 같은 체크 예외를 직접 던지려고 하면 컴파일 오류가 발생한다. 

try {
    // 예외가 발생할 수 있는 코드
} catch (IOException ioe) {
    throw ioe; // 컴파일 오류 발생
}

 

위 코드에서는 IOException을 다시 던지려고 시도하지만, run 메서드는 체크 예외를 던질 수 없으므로 컴파일러가 이를 허용하지 않는다. 이로 인해 unreported exception IOException; must be caught or declared to be thrown 라는 컴파일 오류가 발생한다.

컴파일 오류가 발생하는 이유?

  • 체크 예외: Java에서 IOException은 체크 예외로, 반드시 처리하거나 메서드 선언에 throws 키워드로 명시해야 한다.
  • run 메서드는 Runnable 인터페이스의 메서드로, 예외를 던질 수 있도록 설계되지 않았다. 

해결 방법

  1. 예외를 try-catch 블록에서 처리
  2. 체크 예외를 RuntimeException으로 변환

 

1. try-catch 블록에서 예외 처리

run 메서드 내에서 발생할 수 있는 예외를 try-catch 블록으로 처리하는 방법입니다.

public class IOExceptionHandlingInRunnable {
    public static void main(String[] args) {
        Runnable task = new Runnable() {
            @Override
            public void run() {
                try {
                    simulateIOException();
                } catch (IOException ioe) {
                    System.err.println("IOException 처리: " + ioe.getMessage());
                }
            }

            private void simulateIOException() throws IOException {
                throw new IOException("예제 IOException 발생");
            }
        };

        Thread thread = new Thread(task);
        thread.start();
    }
}
  • 장점: 예외를 run 메서드 내에서 즉시 처리
  • 단점: 호출자에게 예외 정보를 전달하지 않기 때문에, 예외 발생을 외부에서 알 수 없다

 

2. 체크 예외를 RuntimeException으로 변환

체크 예외인 IOException을 언체크 예외인 RuntimeException으로 변환하여 다시 던집니다.

public class IOExceptionHandlingInRunnable {
    public static void main(String[] args) {
        Runnable task = new Runnable() {
            @Override
            public void run() {
                try {
                    simulateIOException();
                } catch (IOException ioe) {
                    throw new RuntimeException("IOException 발생", ioe);
                }
            }

            private void simulateIOException() throws IOException {
                throw new IOException("예제 IOException 발생");
            }
        };

        Thread thread = new Thread(task);
        thread.start();
    }
}
  • 장점: RuntimeException은 언체크 예외이므로, run 메서드에서 자유롭게 던질 수 있다. 
  • 단점: 예외를 감싸서 던지기 때문에 호출자가 예외를 받을 때 예외 체인을 통해 원래의 예외를 분석해야 한다. 

simulateIOException 메서드

이 메서드는 IOException을 강제로 발생시키는 예제.

private void simulateIOException() throws IOException {
    throw new IOException("예제 IOException 발생");
}

 

 


RuntimeException에 대한 추가 설명

RuntimeException은 Java의 표준 예외 계층에서 언체크 예외(Unchecked Exception)의 기본 클래스이다.

이는 java.lang 패키지에 속하며, 개발자가 명시적으로 예외 처리를 강제하지 않아도 된다. 

주요 특징

  • 언체크 예외: RuntimeException을 상속한 예외는 컴파일러가 예외 처리를 강제하지 않는다. 즉, try-catch 블록이나 throws 선언 없이도 사용할 수 있다. 
  • 상속 구조: RuntimeException은 Exception 클래스를 상속받지만, 체크 예외가 아닌 언체크 예외로 분류된다. 
public class RuntimeException extends Exception {
    // ...
}

사용 목적

  • 프로그래밍 오류: 런타임 예외는 보통 프로그래밍 오류, 잘못된 API 사용, 논리적 버그 등을 나타내기 위해 사용된다. 
    • 예: NullPointerException, IndexOutOfBoundsException
  • 예외 처리의 단순화: 언체크 예외를 통해 예외 처리 코드를 간결하게 유지할 수 있다. 

예제

public class RuntimeExceptionExample {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3};
        System.out.println(numbers[3]); // ArrayIndexOutOfBoundsException 발생
    }
}
  • 위 코드에서 ArrayIndexOutOfBoundsException은 RuntimeException의 서브클래스이며, 예외 처리를 강제하지 않습니다.

주의사항

  • 적절한 사용: 언체크 예외를 남용하면 예외 처리 로직이 누락되어, 예상치 못한 프로그램 종료로 이어질 수 있다. 
  • 문서화: 메서드가 RuntimeException을 던질 수 있음을 명확히 문서화하여 사용자에게 예외 발생 가능성을 알리는 것이 중요합니다.

 

 

 


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

Java에서 예외(Exception)는 크게 체크 예외(Checked Exception)와 언체크 예외(Unchecked Exception)로 나눌 수 있다.

1. 체크 예외 (Checked Exception)

정의

체크 예외는 컴파일 타임에 예외 처리를 강제하는 예외이다. 

즉, 해당 예외가 발생할 수 있는 코드를 작성하면 반드시 예외 처리를 해주어야 한다.

예외가 발생할 가능성이 있는 메서드는 throws 키워드를 사용해 해당 예외를 던질 수 있음을 선언하거나, try-catch 블록을 사용하여 예외를 처리해야 한다. 

특징

  • 컴파일 타임에 검사 됨: 체크 예외는 반드시 처리해야 하므로, 예외가 발생할 수 있는 코드에서 컴파일 오류를 방지하기 위해 예외 처리를 강제로 하도록 요구한다. 
  • 명시적인 예외 처리: 예외를 명시적으로 처리하거나 메서드 서명에 throws를 추가하여 호출자에게 처리 책임을 위임해야 한다.

예시

체크 예외는 일반적으로 입출력(I/O), 네트워크 등 외부 리소스를 사용할 때 발생할 수 있다. 

import java.io.*;

public class CheckedExceptionExample {
    public static void main(String[] args) {
        try {
            readFile("example.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void readFile(String filename) throws IOException {
        FileReader reader = new FileReader(filename);
        BufferedReader br = new BufferedReader(reader);
        br.readLine();
    }
}
  • 위 코드에서 FileReader와 BufferedReader는 IOException을 발생시킬 수 있으므로, readFile 메서드는 throws IOException을 선언하여 예외 처리를 강제
  • 호출자는 try-catch를 사용해 예외를 처리하거나, 예외를 다시 던질 수 있다. 

대표적인 체크 예외

  • IOException
  • SQLException
  • FileNotFoundException
  • ParseException

2. 언체크 예외 (Unchecked Exception)

정의

언체크 예외는 컴파일 타임에 예외 처리를 강제하지 않는 예외이다.

이러한 예외는 try-catch 블록을 사용하지 않아도 컴파일 오류가 발생하지 않으며, 예외 처리가 선택적이다. 
주로 런타임 중 발생할 수 있는 예외로, 프로그래밍 오류나 논리적 실수에서 발생한다. 

특징

  • 컴파일 타임 검사 없음: 언체크 예외는 컴파일러가 예외 처리를 강제하지 않으므로, 예외를 처리하지 않고도 프로그램을 실행할 수 있다. 
  • 주로 프로그래밍 오류: 잘못된 API 사용이나 논리적 오류로 발생하며, 개발자가 미리 예측하고 방지해야 할 상황에서 발생한다. 

예시

언체크 예외는 NullPointerException, ArrayIndexOutOfBoundsException 등과 같이 자주 발생하는 예외

public class UncheckedExceptionExample {
    public static void main(String[] args) {
        String text = null;
        System.out.println(text.length());  // NullPointerException 발생
    }
}
  • 위 예시에서 NullPointerException은 언체크 예외이다. 예외를 처리하지 않으면 런타임에서 예외가 발생하지만, 컴파일 타임에 예외 처리를 강제하지 않는다

대표적인 언체크 예외

  • NullPointerException
  • ArrayIndexOutOfBoundsException
  • ArithmeticException
  • IllegalArgumentException
  • IllegalStateException

체크 예외 vs 언체크 예외

컴파일 타임 검사 컴파일러가 예외 처리를 강제 컴파일러가 예외 처리를 강제하지 않음
처리 방식 반드시 try-catch 블록을 사용하거나 throws 선언 예외 처리 선택적 (필수 아님)
주로 발생하는 상황 I/O 작업, 네트워크 작업, 파일 처리 등 외부 리소스 사용 시 논리적 오류, 잘못된 코드 사용 시
대표적인 예외 IOException, SQLException, FileNotFoundException NullPointerException, ArrayIndexOutOfBoundsException, ArithmeticException

언제 체크 예외를 사용하고 언제 언체크 예외를 사용해야 할까?

  1. 체크 예외 사용:
    • 예측 가능한 외부 리소스 문제: 예를 들어 파일을 읽을 때 파일이 없거나 네트워크 연결이 끊어지는 상황처럼, 외부 환경에서 발생할 수 있는 문제는 체크 예외로 처리하는 것이 적합하다
    • 예외가 반드시 처리되어야 하는 경우: 예외가 발생하면 시스템 안정성에 심각한 영향을 미칠 수 있어 반드시 처리해야 할 때 체크 예외를 사용한다
  2. 언체크 예외 사용:
    • 개발자 실수: 예를 들어, NullPointerException이나 ArrayIndexOutOfBoundsException과 같은 예외는 프로그래밍 오류로 발생하며, 개발자가 코드 로직을 수정하여 방지해야한다. 
    • 자주 발생하는 예외: 언체크 예외는 예상할 수 없는 오류가 발생할 수 있는 예외로, 예외 처리보다는 오류를 방지하는 방식으로 작성하는 것이 좋다. 

 

 

 

'Study > Java' 카테고리의 다른 글