에몽이

자바 1.4의 새기능: Assertion 본문

java

자바 1.4의 새기능: Assertion

ian_hodge 2018. 11. 2. 11:21

1.4에 새롭게 추가된 Assertion이 무엇이며 어떻게 사용하는지에 대해서 살펴본다.

Assertion 기본

자바 1.4 버전은 1.3 버전에 보안을 비롯한 다양한 확장 API를 추가하여 그 크기가 방대해졌을 뿐만 아니라 NIO와 로깅 등 새로운 기능을 추가함으로써 완벽한 개발 플랫폼으로 확장되었다. 이러한 새로운 기능들 중에서 자바에서는 전혀 새로운 기능이라고 할 수 있는 게 Assertion 기능이다.

Assertion은 무엇인가

JSR(Java Specifiaction Request) 41을 보면 다음과 같이 Assertion에 대해서 정의를 내리고 있다.

Assertion은 불리언 식(expression)을 포함하고 있는 문장으로서, 프로그래머는 그 문장이 실행될 경우 불리언 식이 참이라고 단언할 수 있다.

다시 말해서 개발자가 자신이 개발한 프로그램에서 가정하고 있는 사실이 올바른 지 검사할 수 있도록 하기 위해서 자바 1.4에 추가된 기능이 바로 Assertion인 셈이다. 예를 들어, 이러한 가정에는 이자율에 해당하는 변수가 0보다 커야 한다는 것 등이 있을 수 있다. Assertion은 그러한 가정이 올바른 지 검사할 수 있도록 함으로써 프로그램이 부드럽게 수행될 수 있도록 도와준다. 이러한 검사 기능은 예외(Exception)를 사용해서도 구현할 수 있긴 하지만, Assertion은 예외와는 다른 의미의 검사 기능을 제공한다. 이에 대해서는 이 글을 진행하면서 살펴볼 것이다.

왜 Assertion을 사용하는가?

실, 예외를 사용하면 에러 검사 기능을 어느 정도 처리할 수 있다. 그런데 왜 Assertion이라는 새로운 검사 기능을 도입한 것일까? 이제 이 질문에 답을 해 보도록 하자. 먼저 자바의 예외는 주로 프로그램을 실행하는 도중에 예상하지 못한(또는 드물게 발생하는) 상태를 처리하는 데 사용된다. 예를 들어 파일을 열수 없다던가, 네트워크의 연결이 끊어졌다던가 하는 등의 이상 상태를 처리할 때 주로 예외가 사용된다. 반면에 Assertion은 개발자가 참이라고 가정하는 상태를 명시하기 위해서 사용된다. 에를 들어, 어떤 메소드가 파라미터로 양수만 입력받아야 한다고 확한다면, Assertion을 사용하여 그 사실을(즉, 파라미터가 양수라는 것을) 명시할 수 있다.

외는 프로그램을 수행하는 도중에 발생하는 비정상적인 상태를 처리하기는 하지만 프로그램의 코드가 수행되는 도중에 예외가 발생한다. 반면에 Assertion은 프로그램이 올바르게 수행될 수 있는 조건을 명시해주어 그 조건을 만족시키는 경우에만 코드가 실행될 수 있도록 해 준다. 따라서 Assertion은 프로그램이 올바르게 실행되도록 해주는 효과적인 도구가 될 수 있으며, 프로그램의 안정성을 높여줄 수 있.

Assertion의 문법

Assertion 문장은 다음과 같은 두가지 형태를 취한다.

  assert 불리언식;  assert 뷸라온식:수식;


첫번 형태는 간단한 형태로서 불리언식을 인자로 받는다. 불리언 식은 개발자가 참(true)이라고 생각하는 식이다. 만약 그 가정이 틀렸다면(즉, 불리언식이 false가 된다면), 불리언식은 Assertion이 틀렸음을 나타내는 false 값을 리턴하고, 불리언식이 성공한 경우에는 프로그램의 수행이 정상적으로 진행된다.

두번째 형태는 좀더 상황에 맞는 설정을 하는 것으로서, 첫번째 인자에는 불리언 식이 오며, 두번째 수식에는 Assertion이 틀렸을 때 사용할 수식이 온다. 두번째 수식은 값이 될 수도 있고, 또는 메소드를 수행한 결과값이 올 수도 있다. 두번째 수식이 void 값을 리턴할 경우 컴파일러는 에러를 발생시킨다.

첫번째 형태 두번째 형태 모두 불리언식이 틀렸을 때, 즉 불리언식이 false를 리턴하면 AssertionError를 발생시킨다. 일반적인 예외와 마찬가지로 AssertionError도 스택 트레이스의 한 부분으로서 보여진다. 두번째 형태에서 지정한 수식의 결과값은 AssertionError의 생성자에 전달되어 스택 트레이스에 출력되는 메시지로 사된다.

다음은 몇가지 assert의 사용 예를 보여준 것이다.

    assert i<0;
    assert (!pageNo.equals(""));
    assert age > 0 : "나이는 음수가 될 수 없습니다:"+age;
    assert ((i/2*23-12)>0):checkValue();


의 서 첫번째 assert 문장은 i가 0보다 작지 않을 경우 AssertionError를 발생시킨다. 세번째 assert 문장의 경우는 age가 0보다 크지 않은 경우 AssertionError를 발생시키며, 그때 AssertionError의 예외 메시지는 "나이는 음수가 될 수 없습니다:"와 age 변수를 연결한 문자열이 된다. 네번째 예제의 checkValue() 메소드는 void가 아닌 값을 리턴해야만 한다.

Assertion의 사용

Assertion은 예외를 대체하진 않지만 예외보다 효과적인 기능을 제공할 수가 있다. 프로그램을 매끄럽게 실행하기 위해서는 Assertion의 위치가 중요하다. 만약 Assertion의 위치가 올바르지 않다면 Assertion이 아무 소용이 없기 때문이다.

전위조건으로 Assertion 사용하기

Assertion을 사용하기 가장 좋은 경우는 어떤 동작을 수행하기 전에 수행에 필요한 값들의 조건을 검사하는 것이다. 예를 들어, 회원 가입을 처리하는 register(MemberInfo member)라는 메소드를 생각해보자. register() 메소드는 다음과 같이 전달받은 파라미터를 검사할 수 있을 것이다.

    private void register(MemberInfo member) {
        assert Member != null:"MemberInfo cannot be null";
        assert member.getId() != null && !member.getId().equals("");
        
        ...
    }


후위조건으로 Assertion 사용하기

어떤 동작을 수행하기 전에 값들을 검사할 때 Assertion을 사용하는 것과 반대로, 동작을 수행한 후의 결과값들을 검사하기 위해서도 Assertion을 사용할 수 있다. 예를 들어, 어떤 값을 리턴하기 전에 assert 문장을 사용하여 리턴할 값이 올바른지의 여부를 판단할 수 있다.

Assertion을 사용해선 안 되는 경우

예외가 모든 경우에 알맞은 것이 아니듯이, Assertion도 모든 경우에 알맞지는 않다. 다음의 경우에는 Assertion을 사용하지 않는 것이 좋다.

  • public 메소드의 파라미터를 검사하는 경우
  • 올바른 수행을 위해 필요한 작업을 수행하는 경우

 public 메소드의 파라미터를 검사하는 경우를 살펴보자. 일반적으로 public 메소드에 전달된 파라미터를 검사할 때에는, 파라미터의 값이 잘못된 경우에 메소드에 알맞은 의미를 나타내지 않는 AssertionError 보다는 IllegalArgumentException과 같이 알맞은 의미를 갖는 예외를 발생시키는 것이 좋다.

또한, 올바른 수행을 위해서 필요한 작업을 assert 문장에서 실행하면 안된다. 예를 들어, 다음과 같은 코드를 생각해보자.

    assert checkName();


1.4버전의 자바가상환경(JRE)는 기본적으로 Assertion 기능을 사용하지 않는다. 따라서, 기본적으로 기능을 사용하도록 명시하지 않는다면 위의 메소드는 실행되지 않을 것이다. 따라서, 올바른 수행을 하는 데 반드시 필요한 코드는 assert 문장에 넣어서는 안 되며, 다음과 같이 해 주어야 한다.

    boolean checked = checkName();
    assert checked;


Assertion을 사용하는 소스코드의 컴파일 및 실행

1.4 버전의 컴파일러는 컴파일하는 동안에 Assertion 기능을 사용하지 않기 때문에, Assertion 기능이 사용되도록 컴파일 하기 위해서는 컴파일러를 실행할 때 다음과 같이 -source 옵션을 사용해야 한다.

    javac -source 1.4 AssertionTest.java 


assert는 1.4 버전에 새롭게 추가된 키워드이기 때문에, assert를 포함한 소스 코드를 1.4 이전 버전의 컴파일러를 사용하여 컴파일할 경우에는 컴파일 에러가 발생한다.

Assertion 기능을 사용할 수 있도록 컴파일 하는 것으로 Assertion을 사용할 수 있는 것이다. 1.4 버전이 자바실행환경(JRE)은 클래스가 Assertion 기능이 사용되도록 컴파일됐는지의 여부에 상관없이 기본적으로 Assertion 기능을 사용하지 않는다.

Assertion 기능을 사용하거나 사용하지 않으려면 명령행에서 -ea 또는 -enableassertions 옵션과 -da 또는 -disableassertions 옵션을 사용하면 된다. -ea 옵션은 Assertion 기능을 사용할 수 있도록 해 주고, 반대로 -da 옵션은 Assertion 기능을 사용할 수 없도록 해 준다. 예를 들어, 클래스를 실행할 때 Assertion 기능을 사용가능하도록 하기 위해서는 다음과 같이 하면 된다.

    java -ea AssertionTest


때에 따라서는 특정 패키지에 속한 클래스나 특정 클래스에 대해서만 Assertion 기능을 적용하고 싶은 경우가 있을 수 있다. 이런 경우에는 -ea 옵션 다음에 다음과 같은 값을 입력해주면 된다.

  • 패키지명... : 패키지와 그 하위 패키지에 있는 모든 클래스에 적용
  • 클래스명 : 특정 클래스에 대해서만 적용

예를 들어, com.javacan.member 패키지에 있는 모든 클래스에 대해서만 Assertion 기능을 수행하고 싶다면 다음과 같이 실행하면 된다.

    java -ea:com.javacan.member... ViewMemberInfo


-da 옵션도 -ea 옵션과 마찬가지로 패키지 단위 또는 특정 클래스에 대해서 Assertion 기능을 수행하지 않게 하고 싶은 경우에 위와 같은 방식으로 값을 지정할 수 있다. 예를 들어, com.javacn.member 패키지에 있는 모든 클래스에 대해서 Assertion 기능을 수행하고 싶지만, com.javacan.member.MemberUtil 클래스에 대해서는 Assertion 기능을 수행하고 싶지 않다면 다음과 같이 실행하면 된다.

    java -ea:com.javacan.membmer... -da:com.javacan.member.MemberUtil ViewMemberInfo


결론

JDK 1.0의 이벤트 모델을 사용하던 개발자가 JDK 1.1부터 적용된 위임형 이벤트 모델을 사용해야 하는 경우와 비슷하게, Assertion을 사용하는 것은 아직 많은 개발자에게 익숙하지 못한 기능이다. 물론, Assertion 개념을 포함하고 있던 언어를 사용해본 경험이 있는 개발자들은 자바의 Assertion 기능을 적극적으로 사용하겠지만, 자바 1.4 이전 버전의 예외 처리 방식에 익숙한 개발자들의 경우는 Assertion 기능을 알맞게 사용하기 까지 시간이 걸릴 것이다.

하지만 Assertion 기능을 사용하기까지 시간이 걸린다 하더라도, 콜렉션 API가 그랬던 것처럼 Assertion 기능도 점차 많은 개발자들에게서 사용될 것으로 생각되며 차기 버전에서는 보다 발전된 모습으로 다가올 것이라 믿는다. 지금부터라도 Assertion 기능을 활용하는 습관을 들인다면 깔끔한 코드를 작성할 수 있는 개발자로 거듭날 수 있게 될 것이다.

강제적으로 Assertion 기능을 사용하도록 만드는 방법 자바실행환경은 기본적으로 Assertion 기능을 사용하지 않기 때문에, 강제적으로 Assertion 기능을 사용하도록 유도하는 방법이 필요하다. 이런 경우에 사용할 수 있는 코드가 바로 다음과 같다.

    static {
        boolean assertsEnabled = false;
        assert assertsEnabled = true;        if (!assertsEnabled)
            throw new RuntimeException("Assertion 기능이 사용가능해야 합니다!");
    }    

위 코드를 main() 메소드가 있는 클래스에 추가하면 Assertion 기능을 사용하도록 유도할 수 있다. 예를 들어, Assertion 기능을 사용하지 않는 경우 위 코드의 assert 문장이 실행되지 않으므로 assertsEnabled 변수의 값이 false인 상태로 남게 될 것이며 RuntimeException이 발생하게 될 것이다.


관련링크:


원문 : http://javacan.tistory.com/entry/79


Comments