ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [자바] 예외처리
    자바 2022. 7. 13. 15:33
    728x90

    예외

    프로그램 에러, 오류 - 오작동, 비정상적인 종료

     

    컴파일 에러 - 컴파일시 에러
    런타임 에러 - 실행시 에러
    논리적 에러 - 실행은 되지만, 의도와 다르게 동작
    에러 - 코드로 수습 불가한 심각한 오류
    예외 - 코드로 수습 가능한 미약한 오류

     

    예외 클래스 계층 구조

    Exception, Error클래스 역시 Object 클래스의 자손이다.

    예외 클래스 계층도

     

    모든 예외의 최고 조상은 Exception클래스이다. 

    Exception 클래스와 RuntimeException 중심의 상속계층도

     

    Exception 클래스들 - 사용자 실수와 같은 외적인 요인에 의해 발생
    RuntimeException 클래스들 - 프로그래머 실수

     

    RuntimeException 

    1 . 배열의 범위를 벗어남 : ArrayIndexOutOfBoundsException
    2. 값이 null인 참조변수의 멤버를 호출하려 함 : NullPointerException
    3. 클래스간의 형변화 잘못함 : ClassCasException
    4. 정수를 0으로 나누려고함 : ArithmeticException

     

    Exception 

    1. 존재하지 않은 파일의 이름을 입력 : FileNotFoundException
    2. 실수로 클래스의 이름을 잘못 적음 : ClassNotFoundException
    3. 입력한 데이터 형식이 잘못됨 : DataFormatException

     

    예외처리 ( try - catch )

    try - catch : 프로그램의 비정상 종료를 막고, 정상적인 실행 상태를 유지할 수 있도록 하는 것이다

     

    try - catch 구조

    try {
    	// 예외가 발생할 가능성이 있는 문장
    } catch (Exception e1) {
    	// Exception 발생시 처리하기 위한 문자
    }

    - Exception은 모든 예외 클래스의 조상이므로, 다른 예외여도 처리가 가능

     

    catch 블럭 내에 또 하나의 try - catch문이 포함된 경우, 같은 이름의 참조변수를 하면 안된다.

    try {
    	try {  } catch ( Exception e) { }
    } catch (Exception e1) {
    	try {  } catch ( Exception e) { } // e가 중복됨 e이름을 e1 같이 바꿔야함
    }

    try문에서 예외가 발생하면 그 밑의 코드들은 실행 시키지 않고 블럭을 벗어난다

     

    printStackTrace() , getMessage()

    printStackTrace() : 예와시 당시 호출스택에 있던 메서드의 정보와 예외 메세지를 출력
    getMessage() : 예외 클래스의 인스턴스에 저장된 메세지를 얻을 수 있다.

     

    catch() 블럭 괄호에 선언된 참조변수를 통해 이 인스턴스에 접근 가능

    try {
        /* 내용 */
    } catch ( Exception ae ) {
        ae.printStaceTrace();
        System.out.println(ae.getMessage() );
    }

     

    멀티 catch 블럭

    '|' 기호를 통해 여러 catch 블럭을 하나의 블럭으로 나타낼 수 있다 ( 예외 클래스가 조상, 자손 관계이면 안된다. )

    참조변수 e 로 멀티 catch블럭에 '|' 기호로 연결된 예외 클래스들의 공통 분모의 조상 예외 클래에 선언된 멤버만 사용할 수 있다.

    try { 
    
    } catch (ExceptionA | ExceptionB e ) { 
    
    }

     

    예외 발생시키기

    키워드 throw를 사용해 고의로 예외를 발생시킬 수 있다.

    try {
        throw new Exception();
    } catch ( Exception e ) {
        e.printStackTrace(); // e.getMessage() 도 가능
    }

    Exception 클래스들은 컴파일도 되지 않아 예외 처리를 해야하는 'checked예외' 라고 부른다.

    RuntimeException 클래스들은 컴파일은 되지만 실행이 되지 않는거라 예외처리를 하지 않아도 되는 'unchecked예외' 라고 부른다.

    -> 그래서 RuntimeException 클래스들은 예외 처리를 필수로 하는 곳에만 해주면 된다.

     

    메서드에 예외 선언하기

    메서드의 선언부에 throws를 사용하면 된다.

    void method() throws Exception {
        // 메서드의 내용
    }

     

    모든 예외의 최고 조사인 Exception을 이렇게 메서드에 선언하면 모든 종류의 예외가 발생할 수 있으며, 자손타입의 예외까지 발생할 수 있어서, 상속도 고려해야한다.

     

    이렇게 메서드에 예외 처리를 해줌으로써, 이 메서드를 사용하기 위해서는 어떠한 예외 처리를 해줘야 하는지 미리 예측이 가능해서 더욱 견고한 코드를 작성할 수 있다. (JAVA.api 문서 참조 -> 메서드에 throws Exception 이런식으로 적혀있는데 그것을 예외처리해주면 됨 )

     

    finally 블럭

    구조 예시

    try {
    	// 예외가 발생할 가능성이 있는 문장
    } catch (Exception e1) {
    	// Exception 발생시 처리하기 위한 문자
    } finally {
        // 예외 발생 여부없이 수행되야 하는 문장 
    }

     

    코드 예시

    try {
    	startInstall();
        copyFiles();
        return; // 리턴문을 만나도 finally 문은 실행된다
    } catch (Exception e1) {
    	e1.printStackTrace();
    } finally {
        deleteFiles();
    }

    try, catch, finally 모든 블럭에서 return문 가능하고 try -> catch -> finally 순으로 진행된다.

    try - catch - finally 문에서 try나 catch문에서 return이 발생하면 finally문을 실행하고 메소드를 닫는다. ( try에서 return 발생시 바로 finally 문으로 간다 )

     

    try - with - resources문

    주로 입출력에서 사용되는 클래스 중에서는 사용 후 꼭 닫아줘야하는 것들이 있는데, 그들을 위한다

    try {
        fis = new FileInputStream("score.dat");
        dis = new DataInputStream(fis);
    } catch ( IOException ie) {
        ie.printStackTrace();
    } finally {
    	dis.close();
    }
    
    // 하지만 여기서 close에서도 예외가 발생 가능
    
    // ( ) 안에 두문장 이상은 ; 로 구분
    try ( FileInputStream fis = new FileInputStream("score.dat"); 
    	DataInputStream dis = new DataInputStream(fis) ) {
        
    	while(true) {
            /* */
        }
    } catch ( IOException ie) {
        ie.printStackTrace();
    }

    try - with - resources문의 괄호 안에 객체를 생성해서 넣으면 close() 호출하지 않아도 try 블럭을 벗어나면 자동적으로 호출한다.

     

     

    Throwable에 억제된 예외와 관련된 메서드

    void addSuppressed(Throwable exception) 억제된 예외를 추가
    Throwable[] getSuppressed() 억제된 예외(배열)를 반환

     

    사용자정의 예외 만들기

    예전에는 Exception 클래스를 상속받아 'checked 예외' 만들었지만, 요즘은 RuntimeException 클래스를 상속받아 'unchecked 예외'를 만드는것을 지향한다

     

    예시

    class newException {
        public static void main(String[] args) {
            try {
                startInstall();
            } catch (SpaceException e) {
            	/* */
            } catch (MemoryException me ) {
            	/* */
            } finally {
            	deleteFile();
            }
        }
    }
    
    static void startInstall() throws SpaceException, MemoryException {
    	if(!enoughSpace())  throw new SpaceException(" ");
    	if(!enoughMemory())  throw new MemoryException(" ");
    }
    
    static boolean enoughSpace() { }
    static boolean enoughMemory() { }
    
    class SpaceException extends Exception {
        SpaceException(String msg) {
            super(msg);
        }
    }
    
    class MemoryException extends Exception {
        MemoryException(String msg) {
            super(msg);
        }
    }

     

    예외 되던지기

    이 방법은 하나의 예외에 대해서 예외가 발생한 메서드와 이를 호출한 메서드 양쪽 모두에서 처리를 해줘야 할 작업이 있을 때 사용된다 ( 주의할 점은 try-catch문을 사용해 예외처리를 해줌과 동시에 메서드의 선언부에 발생한 예외를 throws에 지정해야함 )
    class Exception { 
        public static void main(String[] args) {
            try {
                method1();
            } catch(exception e) {
                System.out.println("main에서 예외 처리");
            }
        }
        
        
        static void method1() throws Exception {
            try {
                throw new Exception();
            } catch (Exception e) {
                System.out.println("method1에서 예외 처리");
                throw e;
            }
        }
    }
    
    // 반환값이 있는 return문 같은 경우에는 catch 블럭에서도 return문이 있어야 한다
    
        static void method1() throws Exception {
            try {
                System.out.println("method1호출");
                return 0; // 현재 실행중인 메소드 종료
            } catch (Exception e) {
                e.printStackTrace();
                // return 1; catch문에서도 return문 필요
                throw new Exception; // return문 대신 예외를 호출한 메서드로 전달
            } finally {
                System.out.println("finally");
            }
        }

     

     

     

    연결된 예외

    하나의 예외가 다른 예외를 발생 시킬 수 있다. ( a -> b 발생 : a를 b의 '원인 예외' 라고 부름 )

     

    try {
        startInstall();
    } catch ( SpaceException e ) {
        InstallException ie = new  InstallException(" "); // 예외 생성
        ie.initCause(e); // InstallException의 원인예외를 SpaceException으로지정
        throw ie; // InstallException 발생 시킴
    }

    InstallException 생성 -> initCause로 SpaceException를 InstallException의 원인 예외로 등록 -> throw로 예외를 던짐

     

    initCause() 는 원인 예외로 등록할 수 있는 메소드다 

    또한, Exception의 조상인 Throwable 클래스에 정의 되어있어서 모든 예외에 적용이 가능하다.

    Throwable initCause(Throwable cause) // 지정한 예외를 원인예외로 등록
    Throwable getCause(). // 원인 예외를 반환

     

     

    원인 예외로 등록해서 다시 예외를 발생 시키는 이유

    1. 여러가지 예외를 하나의 큰 분류의 예외로 묶어서 다루기 위해
    2. checked 예외 -> unchecked 예외로 바꿀수 있도록 하기 위해

     

    2번의 예시 코드

    static void startInstall() throws SpaceException, MemoryException {
    	if(!enoughSpace())  throw new SpaceException(" ");
    	if(!enoughMemory())  throw new MemoryException(" ");
    }
    
    // 바꾸면
    static void startInstall() throws SpaceException {
    	if(!enoughSpace())  throw new SpaceException(" ");
    	if(!enoughMemory())  throw new RuntimeEeception(new MemoryException(" "));
    }

    RuntimExcception 으로 감싸버렸기에 unchecked 예외가 되었다.

    initCause() 대신에 RuntimExcception의 생성자를 사용했다

     

    RuntimExcception(Throwable cause) 는 원인 예외를 등록하는 생성자다. 

    '자바' 카테고리의 다른 글

    [자바] 정규형 패턴  (0) 2022.07.15
    [자바] JAVA.LANG패키지와 유용한 클래스  (0) 2022.07.15
    [자바] 객체지향(2) - 2  (0) 2022.07.13
    [자바] 객체지향(2) - 1 ( 패키지 )  (0) 2022.07.09
    [자바] 객체지향(1)  (0) 2022.07.07
Designed by Tistory.