본문 바로가기

PMD

[한글화 시리즈-17] Strict Exception Rules

Strict Exception Rules

이 룰셋은 오류 처리에 관한 엄격한 가이드라인을 제공한다.



AvoidCatchingThrowable

Throwable을 catch절에서 처리하지 말자. java.lang.Throwable은 모든 오류 및 예외에 대한 수펴클래스이며, 이 객체로 오류 처리를 하면 명확한 오류 처리를 수행할 수 없다.

public class Foo {
  public void bar() {
    try {
      ...
    //throwable로 오류 처리를 하지말자. 
    //너무 범위가 넓어 명확하지 않은 오류 처리이다.
    } catch (Throwable th) {  
      th.printStackTrace();
    }
  }
}

SignatureDeclareThrowsException

오류 처리를 위하여 Exception을 반환하는 것은 좋지 않은 방법이다. 이는 문서 처리 및 모호한 인터페이스를 이해하기 어렵다. 해결방법으로는 RuntimeException을 바탕으로 만들어진 클래스를 사용하던가, 확인된 오류로 처리하자.

//단순히 Exception을 사용하지 말고 더욱 명확한 오류 객체를 사용하자.
public void methodThrowingException() throws Exception {
}

ExceptionAsFlowControl

Exception을 오류처리의 GOTO같은 흐름 관리를 위해서 사용하지 말자. 디버깅 할때 힘들다.

public class Foo {
  void bar() {
    try {
      try {
        ...
      } catch (Exception e) {
        throw new WrapperException(e);
        // 위와 같은 처리는 GOTO를 사용해서 처리하는 것과 별 차이가 없다.
        // 위와 같은 처리는 Exception에서 다시 WrapperException 처리로 이동하는 이중 처리이다.
      }
    } catch (WrapperException e) {
      // 뭔가 오류 처리
    }
  }
  //이런 식으로 각각 처리하자.
  void bar() {
    try {
      ...
    } catch(WrapperException e) {
      ...
    } catch(Exception e) {
      ...
    }
  }

  //JDK 7에서는 다음과 같이도 가능하다.
  void bar() {
    try {
      ...
    } catch(WrapperException e | Exception e) {
      ...
    } 
  }
}

AvoidCatchingNPE

일반적인 환경에서 절대 NPE(NullPointerException)을 단순히 catch절로 잡아서 처리하지 말자. 대부분의 NPE가 발생할 때 NPE는 표면적인 이유고 그 아래 근본적인 오류의 원인이 숨어있는 경우가 있다. 

public class Foo {
  void bar() {
    try {
      // do something
    }  catch (NullPointerException npe) {
      //NPE는 더욱 근본적인 오류의 원인이 숨겨지는 경우가 있다.
      //그러므로, NPE를 단순히 catch절로 숨기지 말자.
    }
  }
}

AvoidThrowingRawExceptionTypes

단순히 RuntimeException, Throwable, Exception 또는 Error를 전달하지말고 더욱 명확한 오류 타입들로 전달하자.

public class Foo {
  public void bar() throws Exception {
    //이런식의 오류처리는 명확한 오류를 인지하기 힘들다.
    throw new Exception();
  }
}

AvoidThrowingNullPointerException

오류를 NPE(NullPointerException)를 발생시켜 전달할 경우, 개발자는 이 오류가 VM(virtual machine)에서 전달한 것으로 인지할 수 있다. 그러므로, IllegalArgumentException을 NPE 대신 사용해서, 더욱 명확하게 프로그래머가 설정한 오류로 인식하게 하자.

public class Foo {
  void bar() {
    throw new NullPointerException();
    //위의 NPE가 아닌 아래의 방식으로 쓰자.
    throw new IllegalArgumentException();
  }
}

AvoidRethrowingException

catch절에서 오류를 재전달하는 것은 단지 코드 길이를 늘리고 runtime 복잡성을 높일 뿐이다.

public class Foo {
  void bar() {
    try {
      ...
    }  catch (SomeException se) {
      //오류를 재전달하는 것은 아무런 의미가 없다.
      throw se;
    }
  }
}

DoNotExtendJavaLangError

Error 객체는 시스템 오류(system exception) 객체이다 . 절대 상속받아서 사용하지말자.

//시스템 오류 객체를 상속하여 사용할 이유는 없다.
public class Foo extends Error { }

DoNotThrowExceptionInFinally

finally절에서 exception을 발생시켜 전달하는 것은 매우 혼란스럽다. 이런 방식은 또 다른 오류 또는 코드상의 결함을 만들어 낸다. 이런 부분은 깔끔하게 삭제하자. 참고: 이 룰은 Lint4j의 "A throw in a finally block"의 룰을 PMD로 구현한 것이다.

public class Foo {
  public void bar() {
    try {
      ...
    } catch( Exception e) {
      //오류 처리
    } finally {
      // 이게 과연 좋은 생각인지 고민해보자.
      throw new Exception();
    }
  }
}            

AvoidThrowingNewInstanceOfSameException

catch절 내에서 같은 오류 객체의 새로운 인스턴스를 만들어 재전달 하는 것은 단지 코드의 길이를 늘리고 runtime 복잡도를 올릴 뿐이다.

public class Foo {
  void bar() {
    try {
      ...
    }  catch (SomeException se) {
       // 무의미한 코드
       throw new SomeException(se);
    }
  }
}


AvoidCatchingGenericException

NullPointerException, RuntimeException, Exception 같은 generic exception을 catch절에서 처리하는 것은 피해야한다.

package com.igate.primitive;
    
public class PrimitiveType {
    
  public void downCastPrimitiveType() {
    try {
      System.out.println(" i [" + i + "]");
    //밑의 모든 오류 처리는 그리 좋은 방법이 아니다.
    } catch(Exception e) {
      e.printStackTrace();
    } catch(RuntimeException e) {
      e.printStackTrace();
    } catch(NullPointerException e) {
      e.printStackTrace();
    }
  } 
}

AvoidLosingExceptionInformation

Catch절에서 아무런 정보를 사용하지 않고 오류 객체의 접근자를 호출하는 것은 코드 길이만 늘리는 일이다. 이런 호출을 삭제하거나, 결과를 반환하자.

public class Foo {
  void bar() {
    try {
      // do something
    } catch (SomeException se) {
      //아무런 의미가 없는 코드
      se.getMessage();
    }
  }
}

해당 URL: http://pmd.sourceforge.net/pmd-4.2.6/rules/strictexception.html