[java] 프로덕션 코드에서 assert 문으로 null을 선언하지 않아야합니까? [닫은]

나는 본 적이 질문을하지만의 사용에 대한 몇 가지 더 질문이 assert키워드. 나는 다른 코더들과 사용하는 것에 대해 토론했다 assert. 이 유스 케이스의 경우 특정 전제 조건이 충족되면 널을 리턴 할 수있는 메소드가있었습니다. 내가 작성한 코드는 메서드를 호출 한 다음 null을 반환하지 않고 반환 된 객체를 계속 사용한다고 주장합니다.

예:

class CustomObject {
    private Object object;

    @Nullable
    public Object getObject() {
        return (object == null) ? generateObject() : object;
    }
}

이제 다음과 같이 사용한다고 상상해보십시오.

public void useObject(CustomObject customObject) {
    object = customObject.getObject();
    assert object != null;
    // Do stuff using object, which would throw a NPE if object is null.
}

나는 프로덕션 코드에서 절대 사용 assert해서는 안되며 테스트에만 사용해야한다는 것을 제거해야한다고 들었습니다 . 그게 사실입니까?



답변

Objects.requireNonNull(Object)그것을 위해 사용하십시오 .

지정된 개체 참조가 null이 아닌지 확인합니다. 이 메소드는 주로 메소드와 생성자에서 매개 변수 유효성 검증을 수행하도록 설계되었습니다. […]

귀하의 경우 이것은 다음과 같습니다.

public void useObject(CustomObject customObject) {
    object = customObject.getObject();
    Objects.requireNonNull(object);
    // Do stuff using object, which would throw a NPE if object is null.
}

이 함수는 당신이 언급 한 목적을 위해 만들어졌습니다. 즉, 널이 아닌 것을 명시 적으로 표시합니다. 생산에서도. 가장 큰 이점은 null 값이 처음에 발생하지 않아야하는 곳에서 null 값을 찾을 수 있다는 것입니다. 원하지 않는 곳으로 전달 된 null 값으로 인해 문제를 디버깅하는 데 어려움이 줄어 듭니다.

또 다른 이점은와 달리 null 검사에 대한 추가 유연성 assert입니다. assert부울 값을 확인하기위한 키워드 인 반면 Objects.requireNonNull(Object)함수이므로 훨씬 유연하고 읽기 쉬운 코드에 포함될 수 있습니다. 예 :

Foo foo = Objects.requireNonNull(service.fetchFoo());

// You cannot write it in on line.
Bar bar = service.fetchBar();
assert bar != null;
service.foo(Objects.requireNonNull(service.getBar()));

// You cannot write it in on line.
Bar bar = service.getBar();
assert bar != null;
service.foo(bar);

명심 Objects.requireNonNull(Object)널 (null) 검사에 대한 독점적 인 assert일반화되어있다. assert이와 관련하여 약간 다른 목적, 즉 주로 테스트가 있습니다. 테스트를 위해 활성화하고 프로덕션에서 비활성화 할 수 있습니다. 어쨌든 프로덕션 코드에는 사용하지 마십시오. 테스트를위한 불필요하고 복잡한 유효성 검사로 인해 응용 프로그램 속도가 느려질 수 있습니다. 프로덕션 전용 검사에서 테스트 전용 검사를 분리하는 데 사용하십시오.

에 대한 자세한 내용은 공식 문서 를 확인하십시오 assert.


답변

어설 션에 대해 기억해야 할 가장 중요한 사항은 비활성화 할 수 있으므로 실행되지 않는다고 가정하는 것입니다.

이전 버전과의 호환성을 위해 JVM은 기본적으로 어설 션 유효성 검사를 비활성화합니다. -enableassertions 명령 행 인수 또는 축약 형 -ea를 사용하여 명시 적으로 사용 가능해야합니다.

java -ea com.whatever.assertion.Assertion

따라서 의존하는 것은 좋은 습관이 아닙니다.

어설 션은 기본적으로 활성화되어 있지 않으므로 코드에서 사용될 때 어설 션이 실행된다고 가정 할 수 없습니다. 따라서 항상 null 값을 검사하고 선택 사항을 비워 두어야합니다. 어설 션을 사용하여 입력을 공용 메서드로 확인하지 말고 대신 확인되지 않은 예외를 사용하십시오. 일반적으로 모든 확인은 어설 션이없는 것처럼 수행합니다.


답변

분명히 당신이 말하는 것은 뻔뻔스러운 거짓말입니다. 이유는 다음과 같습니다.

독립형 jvm 만 실행하면 어설 션이 기본적으로 사용되지 않습니다. 사용하지 않으면 설치 공간이 없어 프로덕션 응용 프로그램에 영향을 미치지 않습니다. 그러나 코드를 개발하고 테스트 할 때 가장 친한 친구 일 것입니다. 대부분의 테스트 프레임 워크 러너는 어설 션을 활성화하므로 (JUnit에서 수행) 단위 테스트를 실행할 때 어설 션 코드가 실행되어 잠재적 인 버그 (예 : 일부 비즈니스 로직 경계 검사에 대한 어설 션을 추가 할 수 있으며 이는 부적절한 값을 사용하는 일부 코드를 감지하는 데 도움이됩니다.

다른 답변에서 알 수 있듯이, 정확히 그런 이유로 (항상 가능하지는 않지만) 중요한 점검을 수행하거나 (특히!) 상태를 유지하기 위해 어설 션에 의존 할 수는 없습니다.

어설트를 사용하는 방법에 대한 흥미로운 예를 보려면 여기를 살펴보십시오 . 파일 끝에 singleThreadedAccess()201 행의 어설트 명령문에서 호출되는 메소드 가 있으며 테스트에서 잠재적 인 멀티 스레드 액세스를 포착 할 수 있습니다.


답변

다른 답변은 이미 충분히 다루었지만 다른 옵션이 있습니다.

예를 들어 Spring에는 정적 메소드가 있습니다.

org.springframework.util.Assert.notNull(obj)

자체 Assert.something()메소드 가있는 다른 라이브러리 도 있습니다. 직접 작성하는 것도 매우 간단합니다.

그러나 이것이 웹 서비스 인 경우 어떤 예외가 발생하는지 명심하십시오. 예를 들어 앞에서 언급 한 방법 IllegalArgumentException은 Spring에서 기본적으로 500을 반환 하는 것을 던집니다 .

웹 서비스의 경우, 이것은 종종 하지 내부 서버 오류 및 500이어야한다, 오히려 잘못된 요청을하는 (400).


답변

프로그래밍 오류 (예 : 버그)를 잡는 데 도움이 될 때마다 어설 션을 자유롭게 사용하십시오 .

논리적으로 발생할 수있는 잘못된 형식의 입력을 잡기 위해 assert를 사용하지 마십시오. 오류를 복구 할 수없는 경우에만 assert를 사용하십시오.

어설 션을 확인할 때 실행되는 코드에 프로덕션 로직을 두지 마십시오. 소프트웨어가 제대로 작성된 경우 이는 사실이 아니지만, 그렇지 않은 경우 어설 션을 사용하거나 사용하지 않도록 설정하면 미묘한 부작용과 다른 전체 동작이 발생할 수 있습니다.

귀사에 “테스트 코드”와 “제작 코드”가 동일하지만 다른 코드 기반 (또는 다른 편집 단계)을 수행하는 경우에는 빠져 나와 다시는 돌아 오지 마십시오. 무능한 수준을 고치려고하는 것은 아마도 시간 낭비 일 것입니다. 회사가 테스트 코드 외부에 주장 진술을하지 않으면 생산 빌드에서 주장이 비활성화되어 있고 그렇지 않은 경우 해당 실수를 수정하는 것이 우선 순위라고 말합니다.

어설 션의 가치는 테스트 스위트뿐만 아니라 비즈니스 로직 내에서 정확하게 사용되어야합니다. 이를 통해 많은 양의 코드를 통과하기 위해 많은 것을 명시 적으로 테스트 할 필요가없는 많은 고급 테스트를 쉽게 수행 할 수 있으며 이러한 모든 주장을 트리거 할 수 있습니다. 내 프로젝트 중 일부에서 일반적인 테스트는 실제로 아무 것도 주장하지 않았으며 특정 입력을 기반으로 계산을 주문했기 때문에 수백 개의 어설 션을 확인하고 작은 논리 부분에서도 문제가 발견되었습니다.


답변

언제든 assert를 사용할 수 있습니다. 토론은 언제 사용되는지에 관한 것입니다. 예를 들어 가이드에서 :

  • 공개 메소드에서 인수 확인에 어설 션을 사용하지 마십시오.
  • 어설 션을 사용하여 응용 프로그램에서 올바른 작업을 수행하는 데 필요한 작업을 수행하지 마십시오.

답변