IT TIP

Guava checkNotNull의 요점은 무엇입니까

itqueen 2020. 11. 27. 21:52
반응형

Guava checkNotNull의 요점은 무엇입니까


나는 구아바를 처음 접했고 (솔직히 말해서, 나는 "아주 새롭지 않다", 나는 그 주제에 대한 완전한 신인입니다) 그래서 몇 가지 문서를 검토하기로 결정했고 이것을 읽는 동안 상당히 놀랐습니다.

com.google.common.base.Preconditions.checkNotNull(...)

이 방법의 요점을 이해하지 못합니다. 이것은 대신 다음을 의미합니다.

myObject.getAnything();

(이로 인해 NullPointerExceptionmyObject가 null 인 경우 발생할 수 있음 )

나는 사용해야한다

checkNotNull(myObject).getAnything();

하는 것입니다 를 던질 NullPointerException경우 myObjectnull이 반환이 myObjectnull가 아닌 경우.

나는 의아해하고 이것은 가장 어리석은 질문 일지 모르지만 ...

이것의 요점은 무엇입니까? 이 두 줄은 내가 생각할 수있는 모든 상황에서 결과와 똑같은 일을합니다.

후자가 더 읽기 쉽다고 생각조차하지 않습니다.

그래서 뭔가 빠졌 나봐요. 뭐야?


아이디어는 빨리 실패하는 것입니다. 예를 들어, 다음과 같은 어리석은 클래스를 고려하십시오.

public class Foo {
    private final String s;

    public Foo(String s) {
        this.s = s;
    }

    public int getStringLength() {
        return s.length();
    }
}

에 대해 null 값을 허용하지 않기를 원한다고 가정 해 보겠습니다 s. (또는 그렇지 않으면 getStringLengthNPE를 던질 입니다). 수업이있는 그대로 null, 그것을 잡을 때 까지는 너무 늦었습니다. 누가 그것을 거기에 넣었는지 알아 내기가 매우 어렵습니다. 범인은 완전히 다른 클래스에 Foo있을 수 있으며 해당 인스턴스는 오래 전에 생성되었을 수 있습니다. 이제 누가 null을 넣을 수 있었는지 찾기 위해 코드베이스를 살펴 봐야 합니다.

대신 다음 생성자를 상상해보십시오.

public Foo(String s) {
    this.s = checkNotNull(s);
}

이제 누군가가 null거기 에 a 넣으면 즉시 알 수 있으며 잘못된 호출을 정확히 가리키는 스택 추적을 갖게됩니다.


이것이 유용 할 수있는 또 다른 경우는 상태를 수정할 수있는 작업을 수행하기 전에 인수를 확인하려는 경우입니다. 예를 들어, 모든 문자열 길이의 평균을 계산하는 다음 클래스를 고려하십시오.

public class StringLengthAverager {
    private int stringsSeen;
    private int totalLengthSeen;

    public void accept(String s) {
        stringsSeen++;
        totalLengthSeen += s.length();
    }

    public double getAverageLength() {
        return ((double)totalLengthSeen) / stringsSeen;
    }
}

호출 accept(null)하면 NPE가 발생하지만 이전 stringsSeen에는 증가 하지 않습니다 . 이것은 당신이 원하는 것이 아닐 수도 있습니다. 클래스의 사용자로서 null을 허용하지 않으면 null을 전달하면 상태가 변경되지 않을 것으로 예상 할 수 있습니다 (즉, 호출이 실패해야하지만 객체를 무효화해서는 안 됨). 분명히이 예제 에서는 s.length()증가하기 전에 가져 와서 수정할 수도 stringsSeen있지만 더 길고 더 복잡한 메서드의 경우 먼저 모든 인수가 유효한지 확인한 다음 상태를 수정하는 것이 유용 할 수 있습니다.

    public void accept(String s) {
        checkNotNull(s); // that is, s != null is a precondition of the method

        stringsSeen++;
        totalLengthSeen += s.length();
    }

myObject.getAnything(); (which might cause a NullPointerException if myObject is null)

No... it will throw NPE whenever myObject == null. In Java, there's no chance of calling a method with null receiver (a theoretical exception are static methods, but they can and should be always called without any object).


I should use checkNotNull(myObject).getAnything();

No you should not. This would be rather redundant (Update).

You should use checkNotNull in order to fail fast. Without it, you may pass an illegal null to another method, which passes it further, and so on and so on, where it finally fails. Then you can need some good luck to find out that actually the very first method should have refused null.


The answer by yshavit mentions an important point: Passing an illegal value is bad, but storing it and passing it later is even worse.

Update

Actually,

 checkNotNull(myObject).getAnything()

makes sense, too, as you clearly express your intent to not accept any nulls. Without it, someone could think that you forgot the check and convert it into something like

 myObject != null ? myObject.getAnything() : somethingElse

OTOH, I don't think the check is worth the verbosity. In a better language, the type system would consider nullability and give us some semantic sugar like

 myObject!!.getAnything()                    // checkNotNull
 myObject?.getAnything()                     // safe call else null
 myObject?.getAnything() ?: somethingElse    // safe call else somethingElse

for nullable myObject, while the standard dot syntax would be allowed only when myObject is known to be non-null.


I have read this whole thread few minutes ago. Nevertheless I was confused why should we use checkNotNull. Then look over Precondition class doc of Guava and I got what I expected. Excessive use of checkNotNull will degrade performance definitely.

My thought is checkNotNull method is worth required for data validation which comes from user directly or very end API to user interaction. It shouldn't be used in each and every methods of internal API because using it you can't stop exception rather correct your internal API to avoid Exception.

According to DOC: Link

Using checkNotNull:

public static double sqrt(double value) {
     Preconditions.checkArgument(value >= 0.0, "negative value: %s", value);
     // calculate the square root
}

Warning about performance

The goal of this class is to improve readability of code, but in some circumstances this may come at a significant performance cost. Remember that parameter values for message construction must all be computed eagerly, and autoboxing and varargs array creation may happen as well, even when the precondition check then succeeds (as it should almost always do in production). In some circumstances these wasted CPU cycles and allocations can add up to a real problem. Performance-sensitive precondition checks can always be converted to the customary form:

if (value < 0.0) {
     throw new IllegalArgumentException("negative value: " + value);
}

참고URL : https://stackoverflow.com/questions/26184322/whats-the-point-of-guava-checknotnull

반응형