페이지

2015. 1. 14.

[JAVA] Day7.예외처리(Exception Handling)

예외처리(Exception Handling)



 

예외(Exception)와 예외처리(Exception Handling)


 - 생각지도 못한 예외
 - 내부적으로 처리 가능한 오류
 - 예상하지 못한 일들을 Exception라 하고 대비하고 준비하는 것이 Exception Handling이다.






Exception Handling 대한 필요성과 이해


 - java에서 프로그램의 실행하는 도중에 Exception이 발생하면 발생된 그 시점에서 프로그램은 바로 종료된다.
 - Exception이 발생 했을 때 프로그램을 종료시키는 것이 바른 판단이다.
 - 하지만! 가벼운 Exception이거나 예상을 하고 있었던 Exception라면 프로그램을 종료시키는 것은 조금 가혹?하다..
 - 그래서 Exception Handling이라는 메커니즘이 제안되었고, Exception Handling을 통해 우선 프로그램의 비정상적인 종료를 막고 발생한 Exception에 대한 처리로 정상적인 프로그램을 게속 진행할 수 있도록 하는 것이 Exception Handling의 필요성이라 할 수 있다.

변수는 예외가 날 수 없다.
메서드 동작중에 발생하는 예외를 처리해 준다.





Exception의 종류


 - java에서 발생하는 모든 Exception은 다음과 같은 구조를 이루면서 각각 Object로 인식된다.

sec6p&e슬라이드9 그림 삽입





오류의 구분


 - 예외(Exception) : 가벼운 오류이며 프로그램적으로 처리한다.
 - 오류(Error) : 치명적인 오류이며 JVM에 의존하여 처리한다.


class ExceptionEx
{
    public static void main(String[] args)
    {
        int number = 10;
        int result = 0;
        for (int i = 0;i < 10;i++)
        {
            result = number / (int)(Math.random()*10);
            System.out.println(result);
        }
    }
}


실행결과 오류없이 끝까지 진행될떄도 있지만, zero로 나눌수 없는 예외를 알려준다.










try-catch


예외는 try-catch로 처리 할 수 있다.

 - try : 예외가 발생할 것 같은 문장
 - catch : 해당 Exception이 발생했을 시 수행할 문장들, catch에는 한가지의 참조변수가 들어갈 수 있다.
 - multiple catch문은 하나의 try문 내에 여러 개의 Exception이 발생 가능할 때 사용.

try
{
    //Exception이 발생할 것 같은 문장들
}
catch(예상되는 Exception Object1 변수명)
{
    //해당 Exception이 발생했을 시 수행할 문장들
}
catch(예상되는 Exception Object2 변수명)
{
    //해당 Exception이 발생했을 시 수행할 문장들
}


따라서 위의 ExceptionEx를 아래와 같이 수정할 수 있다.


class ExceptionEx2
{
    public static void main(String[] args)
    {
        int number = 10;
        int result = 0;
        try
        {
            for (int i = 0;i < 10;i++)
            {
                result = number / (int)(Math.random()*10);
                System.out.println(result);
            }
        }
        catch (ArithmeticException e)
        {
            System.out.println("예외 처리");
        }
    }
}

예외가 발생하면 catch가 잡고 다시 돌아가지는 않는다.
메서드가 아니기 예외 이벤트가 발생했던 곳으로 다시 돌아가는 것이 아니고 그냥 계속 내려간다.


예외발생에도 for문을 끝까지 돌기 위해서는 조금 수정하면됨.(for문에서 예외처리를 함)

class ExceptionEx2
{
    public static void main(String[] args)
    {
        int number = 10;
        int result = 0;
       
        for (int i = 0;i < 10;i++)
        {
            try    {
                result = number / (int)(Math.random()*10);
                System.out.println(result);
            }
            catch (ArithmeticException e){
                System.out.println("예외 처리");
            }
        }
    }
}



예외 class도 클래스이기 떄문에 상속도 다형성도 가능하다.
따라서 Exception의 가장 최고 조상은 Exception이다는 정도만 알아두자.
즉, Exception로 하면 모르겠는 모든 예외를 처리 할수 있다.(api참조)



for (int i = 0;i < 10;i++)
{
    try    {
            result = number / (int)(Math.random()*10);
            System.out.println(result);
        }
    catch (Exception e){
        System.out.println("예외 처리");
    }
}






throw new Exception(); //테스트 용으로 예외를 강제로 호출

class ExceptionEx
{
    public static void main(String[] args)
    {
        throw new Exception();    //컴파일도 안됨
        throw new RuntimeException();//컴파일은 됨
    }
}

 - 치명적인 에러가 있고 치명적이지 못한 에러가 있을수 있다.
 - 에러는 컴파일 Exception, 런타입 Exception이있다.
 - 런타임 Exception은 예외 처리를 선택적으로 할 수 있으나 컴파일 Exception은 꼭 처리해야 한다.
 - RuntimeException을 상속받고 있으면 종류가 런타입 익셉션이고
 - RuntimeException을 상속받지 않는다면 컴파일 Exception으로 꼭 예외를 처리해주어야 한다.(class ClassNotFoundException)


class RuntimeExceptionEx
{
    public static void main(String[] args) throws Exception
    {
        int x = Integer.parseInt("hello");
    }
}

//문법상 틀린것이 없기 때문에 컴파일은 가능하다.
//하지만 실행시에 런타임에러를 알린다.
//이것이 런타임에러


수정후

class RuntimeExceptionEx
{
    public static void main(String[] args) throws Exception
    {
        try
        {
            int x = Integer.parseInt("hello");
        }
        catch (Exception e)
        {
            System.out.println("숫자만 가능합니다.");
        }
       
    }
}











throws 키워드


 - 호출하는 쪽에 나타날수 있는 예외를 미리 알리는 키워드
 - Exception을 처리하기 보다는 발생한 Exception Object를 양도하는 것이다.
 - 즉, 현재 method에서 Exception처리를 하기가 조금 어려운 상태일 때 현재 영역을 호출해준 곳으로 발생한 Exception Object를 대신 처리해 달라며 양도하는것이다.
 - 사용법은 다음의 구성과 같이 throws라는 키워드를 통해 method를 선언하는 것이다.


class ThrowsEx
{
    public static void main(String[] args) throws Exception
    {
        method1();
    }
    static void method1() throws Exception{
        method2();
    }
    static void method2() throws Exception{
        throw new Exception();
    }
}

//호출하는 곳에서 조심하시오!! 라는 의미
//호출한 쪽으로 예외가 넘어간다.
//비로써 컴파일은 가능.








finally의 필요성


 - Exception가 발생하든 발생하지 않든, 무조건 수행하는 부분이 바로 finally영역이다.
 - DB의 open/close와 File open/close처리를 한다면 꼭 필요한 부분이다.
 - 즉, 예외 처리와는 상관없이 최종적으로 실행될 부분으로 항상 마지막에 반드시 실행된다.





class FinallyEx
{
    public static void main(String[] args) throws Exception
    {
        method1();
        System.out.println("method1()의 수행을 마치고 main메서드로 돌아옴!");
    }
    static void method1(){
        try
        {
            System.out.println("method1() 호출!");
            return;
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            System.out.println("method1()의 finally블록이 실행!");
        }
    }
}

return을 만나지만 finally을 실행하고 돌아간다.
즉, 반드시 실행하여할 부분이 있다면 필수적으로 거쳐간다.

예외를 처리 하거나 예외를 처리하기 싫으면 throws로 던저 버린다!