공부/Java

[JAVA] 예외 처리, Exception 클래스 (Test149~ Test155)

린구 2022. 2. 7. 20:21
반응형

 

예외(Exception) 처리


 

프로그램에서 발생하는 오류는 컴파일 오류와 런타임 오류 두 가지로 나눌 수 있다.

 

 

1. 컴파일 오류

- 잘못된 문법을 사용하거나 변수 등을 정의하지 않은 상태에서 사용함으로써

  컴파일 단계에서 발생하는 문법적인 오류

 

 

2. 런타임 오류

- 프로그램을 실행하는 과정에서 발생하는 런타임 오류

  런타임 오류는 두 가지로 나눌 수 있는데 시스템 이상에서 발생하는 시스템 오류(Error),

  프로그램 실행 중 발생되는 비정상적인 상황을 의미하는 예외사항(Exception).

  Exception은 개발자가 고칠 수 있지만 Error는 고칠 수 없음 !

 

 

 

Exception 클래스

 

- 자바에서 예외는 하나의 객체

- 프로그램 실행 중 오류가 발생할 경우, 메소드는 그 오류에 해당하는 예외 객체를 만들고

   그것을 자바 런타임 시스템에 전달 -> 따라서 예외처리를 해주지 않아도 에러를 알려줬던 것 !

- 자바에서 모든 예외 클래스는 Throwable 클래스나 그 하위 클래스를 상속받아 사용

  Throwable 클래스의 하위 클래스

  ▶ Exception 클래스 (메소드가 실행 중에 던지는 예외)

  ▶ Error 클래스 (개발자가 복원할 수 없는 형태의 예외)

 

 

 

예외의 종류

 

 

- checked exception

  ▶ 메소드 내에서 예외가 발생한 경우

  ▶ 메소드를 정의할 때 throws 문에 예외를 명시해주거나 try~catch 해서 처리해 주어야만 하는 예외

  ▶ 프로그램에서 예외를 처리해주지 않으면 컴파일 자체가 불가능

   ex) throws IOException (우리가 항상 해주던 이 예외가 checked exception !! 신기하다) 

         throws UnsupportedEncodingException

 

 

- unchecked exception

  ▶ 런타임 시에 발생할 수 있는 예외

  ▶ 사전에 처리할 필요 X, 컴파일러가 체크 X

   ex) IndexOutOfBoundsEncodingException

  ▶ 주요 런타임 예외 클래스

   - ArrayStoreException, IndexOutOfBoundsException, NullPointerException...

 

 

 

 java.lang.Throwable 클래스의 주요 메소드

 

- toString() (Object 클래스의 toString() 오버라이딩)

  : 에러의 Exception 내용과 원인을 반환 (위치는 X)

 

- printStackTrace()

  : 에러의 발생 근원지를 찾아서 단계별로 에러를 출력

 

- getMessage()

  : 에러의 원인을 간단하게 반환

  

 

try
{
    System.out.print("첫 번째 정수 입력 : ");
    a = Integer.parseInt(br.readLine());
    System.out.print("두 번째 정수 입력 : ");
    b = Integer.parseInt(br.readLine());

    c = a + b;

    System.out.println("결과 : " + c);
}
catch (IOException e)
{
    // IOException → checked Exception
    //-- 메소드를 정의하는 과정에서 throws 한 예외
    //   잡아내거나 던지지 않을 경우 컴파일 에러 발생 -> 따라서 예외를 잡아내고 있다
    System.out.println(e.toString());
}

 

IOException 예외는 checked error 로 던지거나 잡아내지 않으면 컴파일 자체가 불가능하다.

따라서 위 코드에서는 예외를 잡아내고 있다.

 

그러나 NumberFormatException 과 같은 unchecked error 는 반드시 던질 필요도, 잡아낼 필요도 없다.

이와 같이 특정 예외 객체를 잡아낼 수도 있고 

 

try
{
    System.out.print("첫 번째 정수 입력 : ");
    a = Integer.parseInt(br.readLine());
    System.out.print("두 번째 정수 입력 : ");
    b = Integer.parseInt(br.readLine());

    c = a + b;

    System.out.println("결과 : " + c);
}
catch (Exception e)
{
    System.out.println(e.toString());
    System.out.println(e.getMessage());
    System.out.println("printStackTrace...");
    e.printStackTrace();

 

위의 코드와 같이 예외를 모두 Exception 객체로 처리하여 해당 예외의 내용을 출력할 수도 있다.

 

 

 

finally

 

예외가 발생해도 발생하지 않아도 언제나 실행되는 영역을 설정할 수 있는데, finally 를 사용하면 된다.

 

try
{}
catch
{}
finally
{}

 

이런 식으로 finally 블럭을 추가하여 그 내용을 넣어주면 된다.

 

 

메소드에서 조건을 검사하여 조건에 어긋날 때 return을 사용할 수 있지만,

에러를 발생시켜 프로그램을 종료하는 것이 좋을 때도 있다 ! (Test152, Test153 비교)

 

public void setValue(int value)  throws Exception
{
    if(value <= 0)
    {
        //return; -- 종료 → 메소드 종료
        throw new Exception("value 는 0보다 작거나 같을 수 없습니다."); // 폭탄을 품고 있는 상태 (던져줘야한다!)
    }

    this.value = value;
}

 

위의 코드에서는 해당 메소드만 종료시키는 return 대신,  새로운 예외를 발생시키고 있다. 

이렇게 예외를 직접 발생시키면 프로그램 전체를 종료시킬 수 있다 !!

 

 

 

예외 다시 던지기 

 

잡아낸 예외를 다시 던질 수 있다. 이렇게 하는 이유는 상위 계층에 예외를 알리기 위해서 ! 라고 배웠다..!

 

public int getData(int data) throws Exception
{
    if(data<0)
    {
        throw new Exception("data가 0보다 작습니다.");
    }

    return data + 10;
}

public int getValue(int value) throws Exception 
{
    int a = 0;

    try
    {
        a = getData(-2); 
    }
    catch (Exception e)  
    {
        System.out.println("ⓐ printStackTrace.....");
        e.printStackTrace();
    }
    return a;
}

 

또한 이런식으로 메소드 내부에서 예외를 던졌다면 그 메소드를 사용한 곳에 예외 (폭탄이라 생각하자!!)

떨어지므로 이 예외를 또 던져줘야 한다!!

 

위의 코드를 보면 getData()를 사용한 곳에서  Exception을 다시 throws 하는 것을 알 수 있다.

 

 


예외 처리 너무 어렵다...............

무슨 원리인지는 대충 이해가 가는데........

Throwable 클래스의 메소드들이 아직은 너무 낯설고 어렵다!

많이 접해봐야지

반응형