본문 바로가기
JAVA

예외 처리

by 융디's 2024. 4. 25.
728x90
예외 처리

예외 처리

@2024.04.11

예외 처리(Exception Handling)

💡
프로그램 실행 중에 발생할 수 있는 예상치 못한 상황(예외)에 대비하여 프로그램의 정상적인 흐름을 유지하고 예외 상황을 안전하게 처리하는 프로그래밍 기법


@기본 구조

try{

//예외가 발생할 수 있는 코드

}catch(예외 예외 객체){

// 발생한 예외 처리

}finally{

// 생략할 수 있으며, 예외 발생 여부와 관계없이 실행되는 코드

}
  • 필요성
    • 프로그램의 안정성과 신뢰성 보장
      • 예상치 못한 상황에 직면했을 때 안전하게 동작하도록 보장
      • 프로그램이 중단되지 않고 계속 실행될 수 있음
    • 오류의 조기 발견 및 대응
      • 오류 메시지를 통해 문제가 발생되는 원인과 위치를 파악하고, 이를 바탕으로 빠른 시간 내에 오류를 수정
    • 사용자 경험 개선
      • 사용자에게 보다 명확하게 이해하기 쉬운 피드백을 제공
    • 시스템 자원의 안전한 관리
      • 프로그램이 예외인 상황에도 finally 블록 또는 자동 리소스 닫기 구문을 통해 필수적인 자원 해제 작업을 보장함으로써, 시스템 자원을 안전하게 관리할 수 있다.
      • 메모리 누수와 같은 문제를 예방

  • 예외 처리를 제대로 하지 않았을 때
    • 프로그램의 비정상적 중단
      • 사용자에게 혼란을 주고, 프로그램의 신뢰성을 저하시키며, 중요한 작업이 완료되지 못하는 상황을 초래
    • 데이터 손실
      • 파일 작업 중 예외가 발생하면 파일이 손상될 위험 존재
      • 데이터 베이스 작업 중 예외가 발생하면 일관성 없는 상태가 된다.
    • 보안 취약점
      • 시스템의 취약한 부분이 노출 되어 보안 공격에 쉽게 노출될 수 있다.
    • 사용자 경험 저하
      • 사용자는 프로그램의 오류 상황을 이해하기 어려운 메시지로 접하게 된다.
      • 사용자 경험을 저하시키고, 사용자가 프로그램에 대한 신뢰를 잃게 만든다.
    • 유지 보수의 어려움
      • 예외 발생 시 정확한 원인을 파악하기 어렵다.
      • 문제 해결 과정을 복잡하고 시간이 오래 걸린다.
try {
  int result = 10 / 0; // 예외 발생 -> catch문으로 이동 
  System.out.println("Result: " + result); // 해당 코드 실행 X
} catch (ArithmeticException e) {
  System.out.println("0으로 나눌 수 없어!"); // 사용자에게 알려주는 오류 메시지 
} finally {
  System.out.println("이건 무조건 출력될거야");
}

예외 오류 메시지 출력

try {
	// 예외가 발생할 수 있는 코드
	// 예외가 발생한 시점부터 나머지 코드는 실행되지 않는다!
		int result = 10 / 0; // ArithmeticException
} catch (ArithmeticException e) {
		e.printStackTrace();
		System.out.println(e.getMessage());
		System.out.println(e); //객체를 출력하면 toString()을 자동으로 호출
}
e.printStackTrace();
System.out.println(e.getMessage());
System.out.println(e);

예외 종류

예외는 크게 컴파일 시점에서 체크하지 않는 RunTimeException 컴파일 시점에서 체크하는 CheckedException이 존재

RunTimeException

💡
자바 예외 처리 체계에서 중요한 부분을 차지하는 클래스로, java.lang 패키지에 속하며 Exception 클래스의 서브 클래스
  • 특징
    • 비검사형 예외(Unchecked Exception) ⇒ 실행 시에 체크
      • 파일 시점에서 체크되지 않으며, 주로 프로그래머의 실수로 인해 발생
      • 잘못된 형 변환, 배열의 잘못된 인덱싱
    • 자동으로 전파
      • 메서드 시그니처에 예외를 명시적으로 선언하지 않아도 자동으로 호출 스택을 통해 전파
  • 주요 예외
    • ArrayIndexOutOfBoundsIOException : 배열의 인덱스를 잘못 접근하는 경우
    • NullPointerIOException : null 참조에 대한 연산 시도
    • ClassCastIOException : 잘못된 형 변환 시도
    • ArithMeticIOException : 수학적으로 불가능한 연산 시도(0으로 나누기)

CheckedException

💡
컴파일 시점에 체크되는 예외 유형으로, Exception의 서브 클래스지만, RuntimeException의 서브 클래스는 아니다.
  • 특징
    • 컴파일 시점에서 체크
      • 컴파일러에 의해 체크되며, 이 예외를 처리하지 않으면 컴파일 오류가 발생
      • 이런 예외를 처리하기 위해 try-catch 블록을 사용하거나, throws를 사용하여 예외를 호출한 메서드로 던져야 한다.
    • 예측 가능한 예외
      • 프로그램의 외부 요인으로 발생하는 것이 일반적
      • 파일 시스템 오류, 네트워크 문제, 데이터베이스 연결 오류
  • 주요 예외
    • IOException : 파일 입출력 작업 시 발생
    • SQLIOException : 데이터베이스 연결 시 발생
    • FileNotFoundIOException : 존재하지 않는 파일에 접근할 때 발생

사용자 정의 예외 클래스

💡
개발자가 특정한 애플리케이션 요구에 맞게 사용자 정의 예외 클래스를 만들 수 있도록 하며, 이를 통해 더 명확하고 구체적인 예외 처리가 가능

예외 클래스 만들기

💡
사용자 정의 예외 클래스를 만들 때는 기존의 Exception 클래스나 그 하위 클래스를 확장하여 새로운 클래스를 정의하면 됩니다.
  • 예외를 unchecked로 만들고 싶을 땐 RunTimeException을 상속
  • 예시
    • InvalidRangeException 예외 만들기
      • 사용자가 입력한 값이 특정 값의 범위를 넘어갈 때 예외 발생
    // Exception을 상속받아 사용자 정의 예외 생성
    public class InvalidRangeException extends Exception {
    
        // 생성자
        public InvalidRangeException(String message) {
        // 부모 클래스인 Exception의 생성자를 호출하여 예외 메시지를 설정
            super(message); 
        }
    }                     
    public class Main {
    
    	 public static int getUserInput() {
          int num = sc.nextInt(); //150입력
          return num; 
      }
      
      public static void main(String[] args) {
    	    Scanner sc = new Scanner(System.in);
          try {
              int userInput = getUserInput();
              if (userInput < 0 || userInput > 100) {
    	            // 임의로 예외 발생 시키기 
                  throw new InvalidRangeException("입력한 값이 유효한 범위를 벗어났습니다.");
              }
          } catch (InvalidRangeException e) {
              // 예외 처리
              System.out.println(e.getMessage());
          }
      }
    }

예외 처리 하기

try-catch 구문 사용

try{
  //예외가 발생할 수 있는 코드 
}catch(예외  예외객체){
  // try 블록에서 발생한 예외 처리
}finally{
  // 생략 할 수 있으며, 예외 발생 여부와 관계 없이 실행되는 코드 
}

예외 떠넘기기(thorws)

💡
메서드가 발생시킨 예외를 처리하지 않고, 그 메서드를 호출한 상위 메서드에 예외 처리를 위임하는 방법


@기본 구조

메소드 thorws 예외
  • 사용 이유
    • 책임의 분리
      • 예외 처리는 호출한 상위 메서드에 위임하여 메서드는 기능의 실행만 집중
    • 코드의 간결성 유지
      • 메서드 내에서 예외 처리 시 그 메서드의 주된 기능과 관련 없는 코드가 추가되어 코드가 길고 복잡해질 수 있다.
      • 따라서 예외를 떠넘기면 메서드는 더 간결하고 명확하게 유지된다.
    • 재사용성 및 유지 보수성 향상
      • 예외 처리 로직을 특정 메서드에만 구현하면, 다른 상황에서 동일한 예외 처리가 필요할 때 코드를 중복하여 작성해야 한다.
      • 예외를 상위 메서드로 넘김으로써, 재사용성을 높이고, 유지 보수를 용이하게 만든다.
    • 흐름 제어
      • 예외가 발생했을 때 예외를 떠넘기면, 프로그램의 흐름을 상위 레벨로 쉽게 이동 가능
      • 프로그램의 흐름을 더 효과적으로 제어할 수 있다.
  • 예시
    • 파일을 읽어오는 메서드에서 파일이 존재하지 않는 경우 FileNotFoundException을 발생
    public class Main {
        public static void main(String[] args) {
            try {
                readFile("non_existent_file.txt");
            } catch (FileNotFoundException e) {
                System.out.println("파일을 찾을 수 없습니다: " + e.getMessage());
            }
        }
    		// throws를 사용하여 해당 메서드를 호출한 곳에서 예외 처리하도록 위임
        public static void readFile(String fileName) throws FileNotFoundException {
            File file = new File(fileName);
            Scanner scanner = new Scanner(file);
            // 파일 읽기 작업 수행
        }
    }

예외 발생시키기

💡
개발자가 정의한 예외를 발생시키는 특정 조건을 만족할 시 프로그램의 흐름을 인위적으로 중단하는 것


@기본 구조

thorws new 예외(”오류메시지”);
  • 예외를 발생시키는 상황
    • 비정상적인 상황 식별
      • 프로그램 실행 중 특정 조건에서 정상적인 흐름을 유지하기 어려울 때 사용
      • ex) 잘못된 입력, 파일 미 존재, 네트워크 연결 실패
    • 프로그램 무결성 유지
      • 프로그램의 정확성과 안정성을 유지하기 위해, 허용되지 않거나 기대하지 않은 동작이 발생할 때 예외 발생
      • 코드의 로직 오류나 잠재적 문제를 미리 방지 가능
  • 예시
    • 사용자가 입력한 값이 특정 조건을 만족하지 않을 때 예외 발생
    public class Main {
        public static void main(String[] args) {
            try {
                int userInput = getUserInput();
                
                if (userInput < 0 || userInput > 100) {
    		            // IllegalArgumentException 예외 발생 시키기 
                    throw new IllegalArgumentException("입력한 값이 유효한 범위를 벗어났습니다.");
                }
               
                System.out.println("입력한 값은 유효합니다.");
            } catch (IllegalArgumentException e) {
                // 예외 처리
                System.out.println(e.getMessage());
            }
        }
    
        public static int getUserInput() 
            return 150;
        }
    }

728x90

'JAVA' 카테고리의 다른 글

내부 클래스  (0) 2024.04.25
자동 리소드 닫기  (0) 2024.04.25
Final  (0) 2024.04.25
인터페이스  (0) 2024.04.25
추상 클래스  (0) 2024.04.25