본문 바로가기

프로그래밍/자바

[자바/기본] 예외처리 Exception

728x90
반응형
SMALL

예외

  • 컴파일 에러는 문법상의 오류로 컴파일러가 고쳐주는 경우가 많다
  • 예외 (Exception) 은 문법상의 오류가 아닌 실행중에 발생되는 오류 상황을 말한다.
  • 기본적으로 예외가 발생되면, 예외 관련 메세지를 출력하고 프로그램이 종료된다.
  • 예외 객체층
java.lang.Object
|__ java.lang.Throwable
  |
  |__ java.lang.Exception  : 복구 가능
  |    |
  |    |__ java.lang.RuntimeException
  |    |    |__ ArithmeticException, NullPointerException, ArrayIndexOUtOfBoundsException ...
  |    |
  |    |__ IOException, ParseException ...
  |
  |__ java.lang.Error    : 복구 불가
         ...   OutOfMemoryError, StackOverFlowError ...
  • Object 클래스가 Throwable 클래스의 상속을 받고 그 밑으로 RuntimeException, IOException 등이 상속받는다.
  • getMessage(), printStackTrace() 등의 메소드는 Throwable 클래스에 정의되어있기 때문에 오버라이드 하여 사용 할 수 있다.

예외 처리 TRY~CATCH

  • 예외 처리를 할 때 try ~ catch ~ 문을 사용하는데 그 이유는 if문은 예외 처리 이외의 용도로 사용되기 때문에 예외처리를 구분 하는데 어려움이 있다.
  • try문에는 일반적인 흐름을 작성한다.
  • catch문에서는 예외처리(handling 이라고 표현) 블럭으로 만들어서 코드 분석이 훨씬 용이하다.
  • 예제
// if 문을 사용한 처리
if (num2 != 0) {
	result = num1 / num2;
} else {
	System.out.println("0으로 나눌 수 없습니다... ");
} // end if
		
System.out.println("결과: " + result);


// 위의 코드를 try~catch 로 만들어 처리

try{
	result = num1 / num2;
	System.out.println("결과: " + result);
} catch(ArithmeticException ex) {
	// catch{ .. } 예외 처리 블럭. 예외 발생시 수행되는 코드들.
	// 위 try 블럭 수행중에 ArithmeticException 이 발생(throw)되면 이를 처리(handling)하는 catch 블럭

	System.out.println("0으로 나누는 Exception");
	System.out.println(ex.getMessage());
	ex.printStackTrace();
}
  • 특히 시스템 자원, HW(하드웨어. DB) 등의 네트워크를 사용하는 프로그래밍에서는 예외가 언제든지 발생할 수 있기때문에 try~catch 문이 필수적이다.

FINALLY

  • 예외 발생의 여부와 상관없이 항상 실행 되어야할 코드블럭
  • finally 블럭 안에 있는 코드들은 항상, 반드시 실행
  • 예외가 발생했을 때
    • try (예외 발생) -> catch -> finally
  • 예외 발생하지 않을 때
    • try -> finally
  • try 나 catch 블럭 안에 return 이 있더라고 finally 블럭의 코드를 실행 한 이후에 return 을 실행하게 됨 **
  • 예제
System.out.println("#1 try{} 직전");
       try{
          System.out.println("#2 try{} 시작");

//        Integer.parseInt("abc");

          int[] numbers = new int[10];
          numbers[10] = 123;

          System.out.println("#3 try{} 종료");
       } catch (ArrayIndexOutOfBoundsException ex){
          System.out.println("#4 catch{} 시작");
          System.out.println("예외메세지: " + ex.getMessage());

          //System.out.println("#5 catch{} 종료");
          //return;
       } finally {
          System.out.println("#6 finally{}");
       }
       System.out.println("#7 try 종료");

해당 코드 출력 예시


thorws

  • 메소드를 설계 할 때, 예외 처리를 직접 하지 않는 경우
    • 메소드 이름 뒤에 throws Exception을 추가하면 예외가 발생 했을 때, 메소드를 호출 한 곳으로 exception이 던져짐
  • Exception 혹은 Exception을 상속받은 예외를 throws 하는 메소드는 반드시 호출하는 쪽에서 예외처리가 되어야한다.(하지 않을 경우 uncheck exception)
  • 하지만 RuntimeException 혹은 이를 상속받은 예외를 throws하는 메소드는 굳이 예외 처리를 해주지 않아도 된다.
  • 예제
public class TestClass {
    // throws x
    public int divide(int x, int y) {
       int result = 0;
       try{
          result = x / y;
       } catch (ArithmeticException ex){
          System.out.println(ex.getMessage());
       }

       return result;
    } // end divide()
    
    // 메소드 설계를 할 때 예외 처리를 직접 하지 않는 경우:
    // 메소드 이름 뒤에 throws Exception을 추가하면,
    // 예외가 발생한 경우에는 메소드를 호출한 곳으로 exception이 던져짐.
    // Exception 및 이를 '직접 상속받은' Exception 을 throws 하는 메소드의 경우,
    // 이 메소드를 호출하는 쪽에서 반.드.시 예외 처리 (handling) 해야 한다. 안하면 에러!
    
    public int divide2(int x, int y) throws Exception  {
       return x / y;
    } // end divide2()
    
    
    // 반면 'RuntimeException' 및 이를 상속받은 예외를 throws 하는 메소드는
    // 굳이 호출하는 쪽에서 매번 예외 처리 할 필요는 없다
    public int divide3(int x, int y) throws RuntimeException{
       return x / y;
    } // end divide3()

} // end class TestClass

public class Exception06Main {
	public static void main(String[] args) throws Exception {
		System.out.println("throws");
		
		System.out.println();
		TestClass test = new TestClass();
		int result = test.divide(123, 0);
		System.out.println("result = " + result);


		System.out.println();
		try {
			//test.divide2(123, 0);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

//		test.divide2(111, 0);  // 만약에 try-catch 안할거면 main 메소드가 throws Exception 을 해줘야 한다.
// main() 메소드는 가상머신이 호출하는 메소드이다.  예외상황 처리는 가상머신에게 넘어간다
// 가상머신의 예외처리 순서
//    1 : getMessage 호출
//    2 : 예외상황이 발생해서 전달되는 과정 출력
//	  3 : 프로그램 종료
		//test.divide3(111,0);
		Thread.sleep(1000);
		System.out.println("프로그램 종료...");
	} // end main()

} // end class Exception06Main

CustomException

  • Exception을 직접 만들어서 사용할 수 있다
  • Exception & RuntimeException 클래스를 상속 받아서 만듬
  • 예제
// 아래와 같이 Exception 을 상속받아 예외 클래스를 정의해 주었음
public class ScoreException extends Exception{

    // 생성자
    public ScoreException(){
        super("점수 입력오류");
    }
    public ScoreException(String msg){
        super(msg);
    }
    
    
} // end class ScoreException
public class Exception07Main {

	static Scanner sc = new Scanner(System.in);
    //inputScore() 메서드에 ScoreException throws
	public static int inputScore() throws ScoreException{
		int score = sc.nextInt();
		if(score < 0 || score > 100){ // 예외발생
//			ScoreException ex = new ScoreException();
			var ex = new ScoreException(score + "는 유효한 숫자가 아닙니다");
			throw ex; //예외 객체를 throw
		}
		
		return score;
	} // end inputScore()
	
	
	public static void main(String[] args) {
		System.out.println();
		try{
			System.out.println("국어 점수 입력:");
			int kor = inputScore();
			System.out.println("kor = " + kor);

			System.out.println("영어 점수 입력:");
			int eng = inputScore();		// 메소드레서 throws를 해주었기 때문에 호출한 곳으로 넘어옴
			System.out.println("eng = " + eng);
		}catch(ScoreException e){
			System.out.println(e.getMessage());
		}finally {
			sc.close();
		}

	} // end main()

} // end class Exception07Main

 

728x90
반응형
LIST