필수 메소드 매개 변수에 assert 또는 IllegalArgumentException을 사용하는 것이 더 낫습니까?


87

Java에서 더 권장되는 이유는 무엇입니까? 두 유형 모두 예외가 발생하므로 처리 측면에서 동일합니다. assert약간 짧지 만 얼마나 중요한지 잘 모르겠습니다.

public void doStuff(Object obj) {
    assert obj != null;
    ...
}

vs

public void doStuff(Object obj) {
    if (obj == null) {
        throw new IllegalArgumentException("object was null");
    }
    ...
}

나는 obj.hashCode()대신 간단한 것을 선호한다 ;-)
Marco

답변:


117

조심해!

코드를 컴파일 할 때 "어설 션 사용"을 명시 적으로 지정하지 않으면 어설 션 이 런타임에 제거됩니다. Java 어설 션은 프로덕션 코드에서 사용되지 않아야하며 개인용 메소드는 개발자 만 알고 사용할 것으로 예상되므로 개인용 메소드 ( 예외 어설 션 참조) 로 제한해야합니다 . 또한 assert발생합니다 AssertionError를 확장 Error하지 Exception, 그리고 일반적으로 당신은 매우 비정상적인 오류를 나타냅니다 (복구하기 어렵다 "OutOfMemoryError가"와 같은을, 그렇지?) 당신은 치료를 할 수있을 것으로 예상되지 않습니다.

"enable assertions"플래그를 제거하고 디버거를 확인하면이 코드가 컴파일되지 않았기 때문에 ( "ea"가 제거 될 때) IllegalArgumentException throw 호출을 밟지 않을 것입니다.

공용 / 보호 된 메소드에는 두 번째 구성을 사용하는 것이 좋으며 한 줄의 코드로 수행되는 것을 원한다면 적어도 한 가지 방법이 있습니다. 개인적으로 사용하는 스프링 프레임 워크Assert인수 실패에 그 던져 ", IllegalArgumentException를"확인하기위한 몇 가지 방법을 가지고 클래스를. 기본적으로 수행하는 작업은 다음과 같습니다.

Assert.notNull(obj, "object was null");

... 실제로 두 번째 예제에서 작성한 것과 정확히 동일한 코드를 실행합니다. 다음과 같은 몇 가지 다른 유용한 방법이 있습니다 hasText, hasLength거기에.

필자는 필요한 것보다 더 많은 코드를 작성하는 것을 좋아하지 않으므로 작성된 줄 수를 2 줄로 줄이면 행복합니다 (2 줄> 1 줄) :-)


아, 나는 단언이 제거되는 것을 잊었다! 좋은 대답입니다. 다른 내용이 들어
왔는지 조금 기다렸다가

2
컴파일시 어설 션을 제거하는 플래그는 없습니다 ( 조건부 준수 를 통해 제거 될 수 있음 ). 어설 션은 기본적으로 런타임에 비활성화되어 있지만 (JVM이 NOOP로 처리한다고 생각합니다) java -ea프로그래밍 방식 으로 활성화 할 수 있습니다 . @Jalayn 필드에서 디버깅
Justin Muller

@ 잘린 -1. 컴파일러는 어설 션 코드를 제거 하지 않습니다 . cmd를 수행하지 않으면 실행되지 않습니다 java -ea.
Pacerier

5
사용할 수있을 때 Spring 프레임 워크가 필요하지 않음Objects.requreNonNull

46

예외를 사용해야합니다. 어설 션을 사용하면 기능이 잘못 사용됩니다.

검사되지 않은 예외는 라이브러리 사용자 의 프로그래밍 오류 를 감지하도록 설계되었으며 어설 션은 자체 논리 에서 오류를 감지하도록 설계되었습니다 . 이들은 혼합해서는 안되는 별도의 문제입니다.

예를 들어 어설 션

assert myConnection.isConnected();

"이 어설 션으로 이어지는 각 코드 경로 myConnection가 연결되어 있는지 확인합니다. 위의 코드가 유효한 연결을 얻지 못하면이 지점에 도달하기 전에 예외가 발생하거나 반환되어야합니다."

한편, 수표

if (!myConnection.isConnected()) {
    throw new IllegalArgumentException("connection is not established");
}

"연결을 설정하지 않고 라이브러리를 호출하는 것은 프로그래밍 오류"를 의미합니다.


1
이 정보는 정말 도움이 되겠지만, 어설트 방법으로 버그를 어떻게 도입 할 수 있는지 잘 알고 있기 때문에 Jalayn을 받아들이고 있습니다.
데니스

4
우수 점 "체크되지 않은 예외는 라이브러리 사용자의 프로그래밍 오류를 감지하도록 설계되었지만 어설 션은 자체 로직의 오류를 감지하도록 설계되었습니다. 이러한 문제는 혼합해서는 안되는 별도의 문제입니다."
Asim Ghaffar

그러나 이것은 OP가 라이브러리를 작성한다고 가정합니다. 코드가 내부 용인 경우 어설 션이 허용됩니다.
user949300

11

당신이 허용하지 않는 기능을 작성하는 경우 null유효한 매개 변수 값으로를, 당신은 추가해야합니다 @Nonnull서명에 주석을 사용할 Objects.requireNonNull인수가 있는지 확인을 null하고 던져 NullPointerException가됩니다. @Nonnull주석은 문서 용이며 어떤 경우에는 컴파일시에 도움이 경고를 제공 할 것입니다. null런타임시 전달 되지 않습니다 .

void doStuff(@Nonnull Object obj) {
    Objects.requireNonNull(obj, "obj must not be null");

    // do stuff...
}

업데이트 :@Nonnull 주석이 자바 표준 라이브러리의 일부가 아닙니다. 대신, 타사 라이브러리의 수많은 경쟁 표준이 있습니다 ( 어떤 @NotNull Java 주석을 사용해야합니까? 참조 ). 그것은 그것을 사용하는 것이 나쁜 생각이 아니라 표준이 아니라는 것을 의미하지는 않습니다.


지적 해 주셔서 감사합니다 Objects.requireNonNull(). 비슷한 "requireTrue ()"또는 "requireEqual ()"메소드가 어디에 있는지 알고 있습니까? Spring의 Assert에 반대하는 것은 없지만 모든 사람이 그것을 사용하지는 않습니다.
user949300

@ user949300 Objects.requireNonNull()은 인수 유효성 검사를위한 것입니다. 인수가 true무언가 같거나 같으면 인수가 의미가 없습니다. 불법 인수가 아닌 다른 오류의 경우를 들어, 당신은해야 throwException보다 정확하게 오류를 설명하는. JUnit도 Assert있지만 테스트 용입니다.
모욕적 인

제곱근 함수 Objects.requireTrue(x >= 0.0);또는 해시에 대해 더 생각하고있었습니다 .Objects.requireEquals(hash.length == 256)
user949300

어떤 @Nonnull을 사용해야합니까? javax.validation.constraints.NotNull?
Aguid

나는 영리한 사람에 의해 만들어지기 때문에 Eclipse JDT 주석을 사용할 것이다 :). 문서 : help.eclipse.org/neon/…-IntelliJ 를 사용하도록 구성 할 수도 있습니다.
koppor

2

나는 항상 어설 션보다 IllegalArgumentException을 던지는 것을 선호합니다.

어설 션은 주로 JUnit 또는 기타 테스트 도구에서 테스트 결과를 확인 / 검증하기 위해 사용됩니다. 따라서 다른 개발자에게는 메소드가 테스트 메소드라는 잘못된 인상을 줄 수 있습니다.

또한 메소드에 잘못된 인수 나 부적절한 인수가 전달 되면 IllegalArgumentException을 발생 시키는 것이 좋습니다 . 이는 Java 개발자가 따르는 예외 처리 규칙과 더 일치합니다.


5
주장은 JUnit보다 약 40 년 전이었습니다. C 프로그래머에게 ASSERT 매크로에 대해 문의하십시오.
JBR 윌킨슨

3
이 질문은 c에 관한 것이 아닙니다. Java에 관한 것입니다. 그래서 Java와 관련하여 대답했습니다.
rai.skumar

assert (예약 된 키워드)와 Assert (JUnit 클래스)를 혼동하지 마십시오. 둘 다 변수에 대한 검사를 수행하는 데 사용되지만 두 가지 매우 다른 것이므로 매우 다르게 작동합니다.
Newtopian

1

두 번째 IMO는 더 많은 정보를 제공하고 (예를 들어 예외 클래스를 확장하여) 더 많은 정보를 제공하기 위해 확장 될 수 있기 때문에 약간 더 좋습니다. 또한 부정적인 비교를 사용하지 않으므로 이해하기 쉽습니다.


1

나는 aserts를 많이 사용하지 않지만 Lombock @NonNull의 일반적인 접근 방식 : https://projectlombok.org/features/NonNull

롬복 구현 : import lombok.NonNull;

public class NonNullExample extends Something {
  private String name;

  public NonNullExample(@NonNull Person person) {
    super("Hello");
    this.name = person.getName();
  }
}

자바 버전 :

 import lombok.NonNull;

public class NonNullExample extends Something {
  private String name;

  public NonNullExample(@NonNull Person person) {
    super("Hello");
    if (person == null) {
      throw new NullPointerException("person");
    }
    this.name = person.getName();
  }
}

롬복은 정말 좋은 라이브러리입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.