source

Null Pointer를 명시적으로 슬로우하는 이유자연스럽게 일어나는 것이 아니라 예외인가?

goodcode 2022. 8. 25. 23:53
반응형

Null Pointer를 명시적으로 슬로우하는 이유자연스럽게 일어나는 것이 아니라 예외인가?

JDK 소스 코드를 읽을 때 작성자는 파라미터가 null인 경우 파라미터를 확인하고 새로운 Null Pointer를 던지는 것이 일반적입니다.수동으로 예외()를 지정합니다.그들은 왜 그렇게 할까?새로운 Null Pointer를 던지기 때문에 그럴 필요가 없다고 생각합니다.임의의 메서드를 호출하는 경우의 예외().(다음은 예를 들어 HashMap의 소스 코드입니다.)

public V computeIfPresent(K key,
                          BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
    if (remappingFunction == null)
        throw new NullPointerException();
    Node<K,V> e; V oldValue;
    int hash = hash(key);
    if ((e = getNode(hash, key)) != null &&
        (oldValue = e.value) != null) {
        V v = remappingFunction.apply(key, oldValue);
        if (v != null) {
            e.value = v;
            afterNodeAccess(e);
            return v;
        }
        else
            removeNode(hash, key, null, false, true);
    }
    return null;
}

몇 가지 밀접한 관련이 있는 여러 가지 이유가 있습니다.

Fail-Fast:실패할 거면 빨리 실패하는 것이 상책이다.이를 통해 문제를 근원에 더 가깝게 파악할 수 있으므로 문제를 식별하고 복구하기가 쉬워집니다.또, 장해가 발생할 가능성이 있는 코드에 CPU 사이클의 낭비를 회피합니다.

의도: 예외를 명시적으로 설정하면 유지관리자에게 오류가 고의로 발생하고 작성자가 그 결과를 알고 있음을 명확히 알 수 있습니다.

일관성:에러가 자연스럽게 발생하는 것을 허용하고 있는 경우는, 모든 시나리오에서 에러가 발생하는 것은 아닙니다.예를 들어 매핑을 찾을 수 없는 경우,remappingFunction절대 사용되지 않을 것이고 예외가 던져지지 않을 것입니다.입력을 사전에 검증함으로써 보다 명확한 동작과 명확한 문서화를 실현할 수 있습니다.

안정성:코드는 시간이 지남에 따라 진화합니다.자연스럽게 예외가 발생한 코드는 약간의 리팩터링을 거친 후 리팩터링을 중지하거나 다른 상황에서 이를 수행할 수 있습니다.그것을 명시적으로 던지면, 의도치 않게 행동이 바뀔 가능성이 낮아집니다.

그것은 명확성과 일관성을 위해, 그리고 불필요한 추가 작업이 수행되는 것을 막기 위해서입니다.

방법의 맨 위에 guard 절이 없으면 어떻게 되는지 생각해 보십시오. 상상전 it it it it it it it it it it라고 부르죠.hash(key) ★★★★★★★★★★★★★★★★★」getNode(hash, key)★★★★★★★★★★★★★★★null했습니다.remappingFunctionNPE의 「NPE」입니다.

나쁜 것은, 쁜 가 even even, 약 even가if은 「」입니다.false 나서 는 ㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇ를 .else브런치(브런치는 하지 않습니다.remappingFunction 이 방법은 NPE가 NPE로 설정되어 있을 때 .null을 사용법

두 시나리오 모두 불량입니다. ifnull에 대한 유효한 값이 아닙니다.remappingFunction메서드는 콜 시 오브젝트의 내부 상태에 관계없이 항상 예외를 발생시켜야 합니다.또, 이 메서드는, 콜시에 오브젝트의 내부 상태를 불문하고, 불필요한 작업을 실시하지 않고, 단지 송신하는 것으로서 의미가 없는 작업을 실시할 필요가 있습니다.마지막으로 소스 코드를 검토하는 모든 사람이 쉽게 확인할 수 있도록 바로 앞에 가드를 배치하는 것이 깨끗하고 명확한 코드 원칙입니다.

비록 예외가 현재 코드의 모든 분기에 의해 발생하더라도, 향후 코드의 개정으로 인해 변경될 수 있습니다.처음에 체크를 실행하면 확실하게 실행됩니다.

@shmosel의 훌륭한 답변에 기재되어 있는 이유 외에...

퍼포먼스:JVM에 맡기지 않고 NPE를 명시적으로 던지면 (일부 JVM에서) 퍼포먼스상의 이점이 있을 수 있습니다.

Java 인터프리터와 JIT 컴파일러가 null 포인터의 참조를 검출하기 위해 취하는 전략에 따라 달라집니다.1가지 방법은 늘을 테스트하지 않고 명령어가 주소0 에 액세스 하려고 했을 때 발생하는 SIGSEGV 를 트랩 하는 것입니다.이것은 참조가 항상 유효한 경우 가장 빠른 접근법이지만 NPE의 경우 비용이 많이 듭니다.

에 대한 nullNPE가 빈번한 시나리오에서는 SIGSEGV의 퍼포먼스 저하를 회피할 수 있습니다.

(현대 JVM에서 마이크로 최적화가 가치 있는 것인지 의심스럽지만, 과거에는 그랬을 수도 있습니다.)


호환성:예외에 메시지가 없는 이유는 JVM 자체에 의해 느려지는 NPE와의 호환성을 위해서일 가능성이 있습니다.준거 Java 실장에서는 JVM에 의해 투척된NPE에는null (는 다릅니다(안드로이드 Java ) ) ) ) ) ) ) ) )

다른 사람들이 지적한 것과는 별개로, 여기서 인습의 역할에 주목할 필요가 있다.를 들어 #에서는 으로 예외를 은 구체적으로 「C#」ArgumentNullException은 (C# 음음음음)))))))))))))))))))))))))))))NullReferenceException 는 항상 어떤 종류의 버그를 나타내고 있습니다.단순히 프로덕션 코드에서는 발생하지 않아야 합니다.그렇습니다.ArgumentNullException일반적으로도 그렇지만, 「라이브러리를 올바르게 사용하는 방법을 이해할 수 없습니다」라고 하는 버그일 가능성이 있습니다.

즉, 기본적으로 C#에서는NullReferenceException프로그램이 실제로 사용하려고 시도했다는 것을 의미합니다.ArgumentNullException값이 틀렸다는 것을 인식하고 사용하려고 하지도 않았다는 것을 의미합니다.실제로는 (상황에 따라) 영향이 다를 수명은 다음과 같습니다.ArgumentNullException문제의 방법이 아직 부작용을 일으키지 않았음을 의미합니다(메서드 전제조건에 불합격했기 때문에).

덧붙여서, 만약 네가 이런 걸 키운다면ArgumentNullException또는IllegalArgumentException이것이 체크의 포인트입니다.그것은, 「실패」하는 것과는 다른 예외를 요구하고 있는 것입니다.

어느 쪽이든 예외를 명시적으로 제기하면 메서드의 전제 조건과 예상되는 인수를 명확하게 하는 모범적 관행이 강화되므로 코드를 읽고 사용하고 유지하기가 쉬워집니다.명시적으로 체크하지 않은 경우null아무도 합격할 수 없을 거라고 생각했기 때문인지는 모르겠지만null예외 발생을 세고 있거나 확인하는 것을 잊은 것입니다.

이는 나중에 지도를 사용하다가 왜 그런 일이 일어났는지 이해할 수 없게 되는 것이 아니라 오류를 저지르는 즉시 예외를 받기 위함입니다.

불규칙해 보이는 에러 상태를 명백한 계약 위반으로 바꿉니다.기능에는 올바르게 동작하기 위한 전제 조건이 몇 가지 있기 때문에 사전에 체크하고 충족되도록 합니다.

그 결과 디버깅을 할 필요가 없습니다.computeIfPresent()예외적인 경우를 대비해서 말이죠사전 조건 체크에서 예외가 발생했음을 확인하면 잘못된 인수를 사용하여 함수를 호출했음을 알 수 있습니다.체크가 없는 경우는, 그 안에 버그가 있을 가능성을 제외해 주세요.computeIfPresent()그 자체가 예외를 낳는 원인이 됩니다.

분명히, 일반을 던지는 건NullPointerException계약 위반 자체를 나타내는 것은 아니기 때문에 매우 나쁜 선택입니다. IllegalArgumentException더 나은 선택이 될 거야


사이드노트:
Java가 이것을 허용하는지 아닌지는 모르겠지만(의심스럽지만), C/C++ 프로그래머는 C/C++를 사용합니다.assert()이 경우 디버깅에 큰 도움이 됩니다.이 명령어는 제공된 조건이 false로 평가될 경우 가능한 한 빠르게 프로그램이 크래시하도록 지시합니다.그래서, 만약 네가 도망간다면

void MyClass_foo(MyClass* me, int (*someFunction)(int)) {
    assert(me);
    assert(someFunction);

    ...
}

디버거 아래, 그리고 뭔가가 지나갔어요.NULL어느 하나의 논쟁으로, 프로그램은 어느 논쟁이 어떤 것이었는지를 알려주는 선에서 바로 멈출 것이다.NULL콜 스택 전체의 모든 로컬 변수를 천천히 조사할 수 있습니다.

자연스럽게 일어나지 않을 가능성이 있기 때문입니다.다음과 같은 코드를 보겠습니다.

bool isUserAMoron(User user) {
    Connection c = UnstableDatabase.getConnection();
    if (user.name == "Moron") { 
      // In this case we don't need to connect to DB
      return true;
    } else {
      return c.makeMoronishCheck(user.id);
    }
}

(물론 이 샘플에는 코드 품질에 관한 많은 문제가 있습니다.완벽한 샘플을 상상하기 귀찮아서 죄송합니다.)

의 상황c실제로 사용되지 않습니다.NullPointerException해도 던져지지 않는다c == null가능합니다.

더 복잡한 상황에서는 그런 사건들을 찾아내는 것이 매우 쉽지 않습니다.이것이 일반적인 체크가 다음과 같은 이유입니다.if (c == null) throw new NullPointerException()더 좋아요.

이는 추가 손상을 보호하거나 일관성이 없는 상태가 되도록 의도하는 것입니다.

여기에 있는 다른 훌륭한 답변 외에도 몇 가지 사례를 추가하고 싶습니다.

고유한 예외를 만드는 경우 메시지를 추가할 수 있습니다.

만약 네가 네 것을 던진다면NullPointerException메시지를 추가할 수 있습니다(반드시 추가해야 합니다).

기본 메시지는null부터new NullPointerException()이를 사용하는 모든 방법, 예를 들어Objects.requireNonNull이 늘을 인쇄하면 빈 문자열로 변환될 수 있습니다.

조금 짧고 유익하지 않은...

스택 트레이스는 많은 정보를 제공하지만 사용자가 늘이 무엇이었는지 알기 위해서는 코드를 파헤쳐 정확한 행을 확인해야 합니다.

NPE가 랩되어 인터넷을 통해 전송된다고 가정해 봅시다.예를 들어, 다른 부문이나 조직간에 Web 서비스 에러 메세지로 송신되는 경우가 있습니다.최악의 경우엔, 아무도 뭘 알아내지 못할지도 몰라null약자...

연쇄 메서드 호출로 추측할 수 있습니다.

예외는 예외가 발생한 행만 알려줍니다.다음 행을 고려합니다.

repository.getService(someObject.someMethod());

NPE가 이 행을 가리키고 있는 경우, 다음 중 어느 것이repository그리고.someObject무효였습니까?

대신 이러한 변수를 가져올 때 체크하면 최소한 해당 변수가 처리되는 유일한 변수인 행을 가리킬 수 있습니다.또한 앞서 설명한 바와 같이 오류 메시지에 변수 이름 등이 포함되어 있으면 더욱 좋습니다.

입력 로트 처리 시 오류는 식별 정보를 제공해야 합니다.

프로그램이 수천 행의 입력 파일을 처리하고 있는데 갑자기 Null Pointer가 발생한다고 가정해 보십시오.예외.장소를 보고 입력이 틀렸다는 걸 깨달으면...어떤 입력?해당 파일에서 수정해야 하는 행을 이해하려면 행 번호, 열 또는 전체 행 텍스트에 대한 자세한 정보가 필요합니다.

언급URL : https://stackoverflow.com/questions/43928556/why-explicitly-throw-a-nullpointerexception-rather-than-letting-it-happen-natura

반응형