자바의 이상 처리에 대해 간단히 이야기하기(Try Catch Finally)

14114 단어 java이상
이상한 영어 단어는 exception으로 글자 번역은'의외, 예외'라는 뜻, 즉 비정상적인 상황이다.사실상, 이상은 본질적으로 프로그램의 오류이며, 프로그램 논리적 오류와 시스템 오류를 포함한다.
일언반구
자바 이상 처리는 모두 낯설지 않습니다. 전반적으로 다음과 같은 두 가지가 있습니다.
1. 이상 던지기:throw exception

class SimpleException{
  public void a() throws Exception{
    throw new Exception();
  };
}
2. 예외 포착:

public class MyException {
  public static void main(String[] args){
    MyException e = new MyException();
    SimpleException se = new SimpleException();
    try {
      se.a();
    } catch (Exception e1) {
      e1.printStackTrace();
    }
  }
}

class SimpleException{
  public void a() throws Exception{
    throw new Exception();
  };
}

본고는 이 기초 위에서 더욱 깊이 있게 세부 문제를 이야기할 것이다.
사용자 정의 이상 클래스
자바 언어는 우리에게 많은 이상 클래스를 제공하지만, 때때로 우리는 코드를 쓰기 편리하도록 사용자 정의로 이상 클래스를 만들어야 한다.
class SimpleException extends Exception {};
만든 후에 try catch를 사용하여 포획할 수 있습니다.

public class MyException {
  public static void main(String[] args){
    MyException e = new MyException();
    try {
      e.a();
    } catch (SimpleException e1) {
      e1.printStackTrace();
    }
  }
  
  public void a() throws SimpleException{
    throw new SimpleException();
  }
}

class SimpleException extends Exception {};

우리는 MyException에서 방법 a () 를 정의하여 Simple Exception 이상을 던지게 한 다음main () 에서 이 방법을 호출하고 try catch를 사용하여 이 이상을 포착했습니다.

SimpleException
  at MyException.a(MyException.java:15)
  at MyException.main(MyException.java:8)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:606)
  at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

Process finished with exit code 0


번역 실행 후의 결과는 주로 앞의 세 줄을 보면 된다.여기에 몇 가지를 중점적으로 설명한다.
1. 이상 유형의 지정을 던진다: (exception specification)
하나의 방법에서 이상을 던져야 할 때, 우리는throw를 사용한 후에 어떤 이상 클래스를 추가합니다. 프로그램은 클라이언트 프로그램 (이 코드를 호출하는 프로그램) 에 대응하는 이상을 던져서 종료합니다. (return 상당)또한 주의해야 할 것은 우리가 이 방법을 정의할 때 이상 유형을 가리켜야 한다는 것이다. 예를 들어 아래의 코드는 Simple Exception 이상을 던질 것이다
public void a() throws SimpleException
2. 여러 개의 이상을 던진다:

  public void a() throws SimpleException,AException,BException{
    throw new SimpleException();
    
  }
서로 다른 이상 클래스 사이를 쉼표로 구분하면 됩니다. 이런 상황에서throw 각 이상 클래스의 실례 () 는 필요하지 않지만, 클라이언트 코드는catch에서 각 이상 클래스로 구분해야 합니다.

public class MyException {
  public static void main(String[] args){
    MyException e = new MyException();
    try {
      e.a();
    } catch (SimpleException e1) {
      e1.printStackTrace();
    } catch (BException e1) {
      e1.printStackTrace();
    } catch (AException e1) {
      e1.printStackTrace();
    }
  }

  public void a() throws SimpleException,AException,BException{
    throw new SimpleException();
    
  }
}

class SimpleException extends Exception {};
class AException extends Exception{}
class BException extends Exception{}


3 stack trace
이상을 던지든지, 이상을 포획 처리하든지, 우리의 목적은 더욱 건장한 프로그램을 작성하기 위해서이다. 이것은 어느 정도에java이상 메커니즘이 우리에게 제공하는 이상 정보에 의존하고 그 캐리어는 stacktrace이다.
앞의 코드에서 printStackTrace () 를 사용하여 이상한 정보를 출력할 수 있습니다. 사실 getStackTrace () 방법으로 StackTrace Element형의 집합을 얻을 수 있습니다. 만약에 IDEA가 있다면 StackTrace Element 클래스를 검색하면 인터페이스 Serializable를 실현한 것을 발견할 수 있습니다. 클래스 설명을 보십시오.

/**
 * An element in a stack trace, as returned by {@link
 * Throwable#getStackTrace()}. Each element represents a single stack frame.
 * All stack frames except for the one at the top of the stack represent
 * a method invocation. The frame at the top of the stack represents the
 * execution point at which the stack trace was generated. Typically,
 * this is the point at which the throwable corresponding to the stack trace
 * was created.
 *
 * @since 1.4
 * @author Josh Bloch
 */
이 클래스의 모든 실례는 Stack trace의 한 요소로 Stack 프레임을 대표하고 Stack trace는 getStack Trace () 방법으로 되돌아옵니다.뒤에 있는 나는 몇 번을 번역해 보았지만 모두 좋지 않다고 느꼈다. 아니면 직접 코드를 올려야만 분명히 말할 수 있다.

public class MyException {
  public static void main(String[] args){
    MyException e = new MyException();
    e.a();

  public void a(){
    try {
      throw new Exception();
    } catch (Exception e) {
      StackTraceElement[] ste = e.getStackTrace();
      System.out.println(ste.length);

    }
  }
}

Exception 이상을 내보내면서 캡처하는 방법 a를 정의하고 getStackTrace () 방법으로 StackTrace Element형 배열을 얻어 배열의 길이를 출력합니다.

Process finished with exit code 0
우리는 코드를 조금 바꾸어 a에서 이상을 포착하지 않습니다. 우리는 방법 b를 다시 정의하여 a를 호출하는 동시에 이상을 포착하도록 합니다.

public class MyException {
  public static void main(String[] args){
    MyException e = new MyException();
    e.b();
  }

  public void b(){
    try {
      a();
    } catch (Exception e) {
      StackTraceElement[] ste = e.getStackTrace();
      System.out.println(ste.length);
    }
  }

  public void a() throws Exception{
    throw new Exception();
  }
}

결과는 다음과 같습니다.

Process finished with exit code 0
서두르지 말고 재미있는 것을 다시 한 번 봅시다.

public class MyException {
  public static void main(String[] args){
    MyException exception = new MyException();
    try {
      exception.c();
    } catch (Exception e) {
      StackTraceElement[] ste = e.getStackTrace();
      System.out.println(ste.length);
      System.out.println("---------------------------------------------------------------");
      for (StackTraceElement s : e.getStackTrace()){
        System.out.println(s.getClassName()+":method "+s.getMethodName()+" at line"+s.getLineNumber());
      }
      System.out.println("---------------------------------------------------------------");

    }

  }

 public void c() throws Exception{
    try {
      a();
    }catch (Exception e){
      throw e;
    }
  }

  public void a() throws Exception{
    throw new Exception();
  }
}

다음은 결과입니다.

8
---------------------------------------------------------------
MyException:method a at line43
MyException:method c at line39
MyException:method main at line9
sun.reflect.NativeMethodAccessorImpl:method invoke0 at line-2
sun.reflect.NativeMethodAccessorImpl:method invoke at line57
sun.reflect.DelegatingMethodAccessorImpl:method invoke at line43
java.lang.reflect.Method:method invoke at line606
com.intellij.rt.execution.application.AppMain:method main at line144
---------------------------------------------------------------

Process finished with exit code 0

즉, getStackTrace () 는 호출자 (main () 에서 초기 이상 (a () 까지의 기본 정보를 포함하는 창고로 되돌아옵니다. 위의 코드에서 우리가 c 방법에서 a 방법을 호출할 때 이상을 포획하고throws를 통해 다시 던지기 (rethrow), c 방법을 호출하는 방법은 이상을 포획하고 처리할 수 있으며, 더 높은 단계의 호출자 (창고 밑에 가까운) 처리를 선택할 수 있습니다.rethrow는 편리하지만 몇 가지 문제가 있습니다. 아래의 코드를 보십시오.

public class MyException {
  public static void main(String[] args){
    MyException exception = new MyException();
    try {
      exception.c();
    } catch (Exception e) {
      e.printStackTrace(System.out);
    }

  }

  public void c() throws Exception{
    try {
      a();
    }catch (Exception e){
      throw e;
    }
  }

  public void a() throws Exception{

    throw new Exception("Exception from a()");
  }
}
java.lang.Exception: Exception from a()
  at MyException.a(MyException.java:40)
  at MyException.c(MyException.java:30)
  at MyException.main(MyException.java:21)

우리는 c에서 e를 다시 던지고main에서 e.printStackTrace () 를 사용하여 인쇄하면 stacktrace가 a에 속하는지 볼 수 있습니다. 만약에 우리가 stacktrace를 c로 바꾸고 싶다면 이렇게 쓸 수 있습니다.

public class MyException {
  public static void main(String[] args){
    MyException exception = new MyException();

    try {
      exception.c();
    } catch (Exception e) {
      e.printStackTrace(System.out);
    }

  }

  public void c() throws Exception{
    try {
      a();
    }catch (Exception e){
//      throw e;
      throw (Exception)e.fillInStackTrace();
    }
  }

  public void a() throws Exception{

    throw new Exception("Exception from a()");
  }
}
java.lang.Exception: Exception from a()
  at MyException.c(MyException.java:22)
  at MyException.main(MyException.java:10)


4 이상 체인 Exception chaining
먼저 한 장면을 보겠습니다.

public class TestException {
  public static void main(String[] args){
    TestException testException = new TestException();
    try {
      testException.c();
    } catch (CException e) {
      e.printStackTrace();
    }
  }

  public void a() throws AException{
    AException aException = new AException("this is a exception");
    throw aException;
  }

  public void b() throws BException{
    try {
      a();
    } catch (AException e) {
      throw new BException("this is b exception");
    }
  }

  public void c() throws CException{
    try {
      b();
    } catch (BException e) {
      throw new CException("this is c exception");
    }
  }
}

class AException extends Exception{
  public AException(String msg){
    super(msg);
  }
}

class BException extends Exception{
  public BException(String msg){
    super(msg);
  }
}

class CException extends Exception{
  public CException(String msg){
    super(msg);
  }
}

세 가지 이상 클래스 AException, BException, CException을 만들고 a()에서 AException을 던지고 b()에서 AException을 잡고 BException을 던지고 마지막으로 c()에서 BException을 잡고 CException을 던지면 다음과 같이 출력됩니다.

CException: this is c exception
  at TestException.c(TestException.java:31)
  at TestException.main(TestException.java:8)
자, 우리는 CException의 정보만 보았습니다. AException, Bexception의 이상 정보는 이미 잃어버렸습니다. 이때 이상 체인의 작용이 나타났습니다. 코드를 보십시오.

public class TestException {
  public static void main(String[] args){
    TestException testException = new TestException();
    try {
      testException.c();
    } catch (CException e) {
      e.printStackTrace();
    }
  }

  public void a() throws AException{
    AException aException = new AException("this is a exception");
    throw aException;
  }

  public void b() throws BException{
    try {
      a();
    } catch (AException e) {
//      throw new BException("this is b exception");
      BException bException = new BException("this is b exception");
      bException.initCause(e);
      throw bException;
    }
  }

  public void c() throws CException{
    try {
      b();
    } catch (BException e) {
//      throw new CException("this is c exception");
      CException cException = new CException("this is c exception");
      cException.initCause(e);
      throw cException;
    }
  }
}

class AException extends Exception{
  public AException(String msg){
    super(msg);
  }
}

class BException extends Exception{
  public BException(String msg){
    super(msg);
  }
}

class CException extends Exception{
  public CException(String msg){
    super(msg);
  }
}

다음과 같이 initCause () 방법으로 예외 정보를 연결했습니다.

CException: this is c exception
  at TestException.c(TestException.java:35)
  at TestException.main(TestException.java:8)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:606)
  at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: BException: this is b exception
  at TestException.b(TestException.java:24)
  at TestException.c(TestException.java:32)
  ... 6 more
Caused by: AException: this is a exception
  at TestException.a(TestException.java:15)
  at TestException.b(TestException.java:21)
  ... 7 more

Process finished with exit code 0


후기
사실 자바 이상 처리에 관해서는 아직 연구해야 할 부분이 많지만 저는 경험이 제한되어 있어서 너무 깊이 느끼지 못했습니다. 가장 자주 사용하는 것은 바로

try {
      ...
    }catch (Exception e){
      ... 
    }finally {
     // , IO  
    }
그러나 어쨌든 우리는 자바가 우리에게 제공한 이상 메커니즘에 감사해야 한다. 자바는 마치 연장자처럼 때때로 우리에게 길을 안내해 주고 인코딩할 때 그렇게 지루하지 않다.

좋은 웹페이지 즐겨찾기