Home 자바스터디 9주차
Post
Cancel

자바스터디 9주차

GOAL

자바의 예외 처리에 대해 학습하세요.

학습할 것 (필수)

  • 자바에서 예외 처리 방법 (try, catch, throw, throws, finally)
  • 자바가 제공하는 예외 계층 구조
  • Exception과 Error의 차이는?
  • RuntimeException과 RE가 아닌 것의 차이는?
  • 커스텀한 예외 만드는 방법

자바에서 예외 처리 방법 (try, catch, throw, throws, finally)

예외(exception)란 ?

‘예외적인 이벤트’의 약자로 프로그램의 정상적인 흐름은 방해하는 이벤트라고 정의 한다
오라클

에외 전체 흐름도

흐름도

try

  • try블럭 내에서 예외가 발생한 경우, 해당 되는 catch 블록을 실행 한다.
  • 일치하는 catch블럭을 찾으면, 그 catch블럭 내의 문장들을 수행
  • 일치하는 catch블럭이 없으면, 처리하지 못하고 그대로 잔행

catch

  • try블럭에서 발생한 예외와 catch블록에 있는 예외를 비교하여 일치하는 예외 블록시 실행 된다
1
2
3
4
5
6
7
8
9
public class TryCatchFinally {
    public static void main(String[] args) {
        try{
          ...처리작업
        }catch (Exception e){
          ...예외발생시 처리작업
        }
    }
}

컴파일소스

1
2
3
4
5
6
7
8
9
10
11
public class TryCatchFinally {
  public TryCatchFinally();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: return
}

추가
catch블럭(자바7)

  • 기호(|)를 통해 하나의 catch블럭으로 통합
  • 기호(|)로 연결된 예외 클래스가 부모와 자식 관계에 있다면 컴파일 에러가 발생
  • 참조변수 e는 상수 라서 값을 변경할 수 없다
1
2
3
4
5
try {
	...
} catch (ExceptionA | ExceptionB e) {
	e.printStackTrace();
}

finally

  • 블록내 처리후 반드시 실행되는 블럭 io나 connect 등 사용후 종료 하는 자원이 있을 경우 사용
  • finally 블록에서 예외 발생시, catch블록의 예외 추적이 불가하다.
  • 이런 문제는 자바7에서 try-with-resources로 해결할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
spublic class TryCatchFinally {
    public static void main(String[] args) {
        try{
          ...처리작업
        }catch (Exception e){
          ...예외발생시 처리작업
        }finally {
          ...항상 실행 작업
        }
    }
}

컴파일소스

1
2
3
4
5
6
7
8
9
10
11
12
public class TryCatchFinally {
  public TryCatchFinally();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: return
}
ch

try-with-resources(자바7)

  • 대상이 되는 메소드는 AutoCloseable 인터페이스를 구현해야 한다.
  • try블록이 종료 되면, AutoCloseable 의 close()메소드의 구현체가 실행된다.
  • try-catch문과 AutoCloseable.close()에서 모두 예외가 발생되면, 두 예외가 동시에 발생할 수는 없기 때문에 close()에서 발생되는 예외는 억제된 예외 로 처리되어 실제 발생한 예외(try-catch문에서 발생한 예외)에 저장된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class TryCatchResource {
    public static void main(String[] args){
        try(TryCatchResourceMethod c = new TryCatchResourceMethod()){

        } catch (Exception e) {
        }
    }
}

class TryCatchResourceMethod implements AutoCloseable {

    @Override
    public void close() {
        System.out.println("always exec");
    }
}


컴파일 소스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class TryCatchResource {
  public TryCatchResource();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #7                  // class TryCatchResourceMethod
       3: dup
       4: invokespecial #9                  // Method TryCatchResourceMethod."<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #10                 // Method TryCatchResourceMethod.close:()V
      12: goto          16
      15: astore_1
      16: return
    Exception table:
       from    to  target type
           0    12    15   Class java/lang/Exception
}

실행 순서를 보면

  1. 0번에서 생성한 클래스를 7번라인에서 저장
  2. 7번라인에서 저장한 클래스를 8번 라인에서 로드
  3. 8번라인에서 로드한 클래스의 close()를 9번 라인에서 실행

예외 처리는 Exception table 테이블을 이용하여, 12번 라인의 목적이 메모값을 변경 (종료인 16라인에서 Exception 클래스 가 있는 15번 라인으로 이동)

output

1
always exec

getSuppressed,addSuppressed

  • Throwable에 추가된 getSuppressed메소드를 이용하면 예외를 가져올 수도 있다.
  • Throwable에 추가된 addSuppressed메소드를 이용하면 예외를 추가할 수도 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Throwable implements Serializable {

  public final synchronized Throwable[] getSuppressed() {
      if (suppressedExceptions == SUPPRESSED_SENTINEL ||
          suppressedExceptions == null)
          return EMPTY_THROWABLE_ARRAY;
      else
          return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
  }

  public final synchronized void addSuppressed(Throwable exception) {
    if (exception == this)
        throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE, exception);

    Objects.requireNonNull(exception, NULL_CAUSE_MESSAGE);

    if (suppressedExceptions == null) // Suppressed exceptions not recorded
        return;

    if (suppressedExceptions == SUPPRESSED_SENTINEL)
        suppressedExceptions = new ArrayList<>(1);

    suppressedExceptions.add(exception);
}
}

throw

  • throw키워드를 이용해서 고의로 예외를 발생 가능
    1
    2
    
    Exception e = new Exception("예외");
    throw e;
    

throws

  • throws키워드를 이용해서 예외를 호출한 메소드로 넘길 수 있다. 하지마세요
  • throws키워드를 사용할 경우, 예외 처리를 위한 Exception table 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class TryCatchResource {
    public static void main(String[] args) {
        parent();
    }

    public static void parent(){
        try{
            child();
        } catch (Exception e) {
            System.out.println("parent");
            e.printStackTrace();
        }
    }

    private static void child() throws Exception {
        throw new Exception("child Exception");
    }
}

컴파일소스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class TryCatchResource {
  public TryCatchResource();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #7                  // Method parent:()V
       3: return

  public static void parent();
    Code:
       0: invokestatic  #12                 // Method child:()V
       3: goto          19
       6: astore_0
       7: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
      10: ldc           #23                 // String parent
      12: invokevirtual #24                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      15: aload_0
      16: invokevirtual #30                 // Method java/lang/Exception.printStackTrace:()V
      19: return
    Exception table:
       from    to  target type
           0     3     6   Class java/lang/Exception
}

컴파일 소스를 보면 예외 처리를 위한 Exception table이 생긴걸 알 수 있다.

output

1
2
3
4
5
parent
java.lang.Exception: child Exception
	at TryCatchResource.child(TryCatchResource.java:18)
	at TryCatchResource.parent(TryCatchResource.java:10)
	at TryCatchResource.main(TryCatchResource.java:5)

자바가 제공하는 예외 계층 구조

https://madplay.github.io/post/java-checked-unchecked-exceptions

  • Exception과 Error는 Throwable이라는 클래스를 상속받고 있으며 Throwable은 Object를 직접 상속받음

Exception과 Error의 차이는?

  • Throwable은 Error와 Exception이라는 두 개의 하위 클래스를 갖는데, 필요한 곳에서 Exception클래스를 확인하고 수정하는 것으로 개발자가 직접 처리 할 수 있다
  • Error는 OutOfMemoryError나 NoClassDefFoundError클래스처럼 개발자 스스로 처리 할 수 있는것이 아니다.

RuntimeException과 RE가 아닌 것의 차이는?

  • 예외는 ‘런타임 예외(runtime exception)’이거나 ‘확인해야 하는 예외(checked exception)’ 두 가지로 구분
  • 런타임 예외는 모두 RuntimeException의 하위 클래스고, 확인해야 하는 예외는 모두 다른 예외
  • 확인해야 하는 예외(checked exception)를 처리하는 메소드(또는 생성자)를 사용할 때는 메소드 정의에 명시적으로 예외가 정의되어야 하며, 따라 코드를 호출하는 모든 호출자들은 해당 예외를 처리 즉, 메소드의 호출자에게 전달하거나 try/catch/finally문으로 예외를 적절히 처리 참고

커스텀한 예외 만드는 방법

  • 기존 정의된 예외 클래스 외에 필요에 따라 새로운 예외 클래스를 정의
  • 보통 Exception클래스로부터 상속받는 클래스를 만들지만, 필요에 따라 알맞은 예외 클래스를 선택 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class CustomException extends Exception {
    private final int ERROR_CODE;
    CustomException(String message, int errorCode) {
        super(message);
        this.ERROR_CODE = errorCode;
    }
    CustomException(String message) {
        this(message, 100);
    }
    public int getErrorCode() {
        return ERROR_CODE;
    }
}

컴파일소스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ublic class CustomException extends java.lang.Exception {
  CustomException(java.lang.String, int);
    Code:
       0: aload_0
       1: aload_1
       2: invokespecial #1                  // Method java/lang/Exception."<init>":(Ljava/lang/String;)V
       5: aload_0
       6: iload_2
       7: putfield      #7                  // Field ERROR_CODE:I
      10: return

  CustomException(java.lang.String);
    Code:
       0: aload_0
       1: aload_1
       2: bipush        100
       4: invokespecial #13                 // Method "<init>":(Ljava/lang/String;I)V
       7: return

  public int getErrorCode();
    Code:
       0: aload_0
       1: getfield      #7                  // Field ERROR_CODE:I
       4: ireturn
}

참고

9주차

This post is licensed under CC BY 4.0 by the author.

라라벨로 배우는 php 웹 프로그래밍

라라벨로 배우는 php 웹 프로그래밍

Comments powered by Disqus.

Trending Tags