requireNonNull()
메소드에서 첫 번째 명령문으로 사용하면 지금 예외의 원인을 식별 / 빠르게 식별 할 수 있습니다.
스택 트레이스는 호출자가 요구 사항 / 계약을 존중하지 않기 때문에 메소드가 입력되는 즉시 예외가 발생했음을 명확하게 나타냅니다 .
지나가는 null
다른 방법으로 목적하는 것은 할 수 참으로 한 번에 예외하지만 문제의 원인이 더 많은 예외가의 특정 호출에 던져 질 것이다로 이해하는 복잡 할 수있다 도발 null
훨씬 더 할 수있다 개체를.
여기에 우리가 일반적으로 실패를 선호해야하는 이유를 보여주는 구체적이고 실제적인 예가 Object.requireNonNull()
있습니다 null
.
에 포함 된 단어 를 나타내는 Dictionary
a LookupService
와 a 를 구성 하는 클래스를 가정하십시오 . 이러한 필드는 설계되지 않았 으며 이들 중 하나는 List
String
null
Dictionary
생성자에 .
이제 메소드 엔트리 (여기서 생성자) Dictionary
를 null
점검 하지 않고 "나쁜"구현을 가정 해 보자 .
public class Dictionary {
private final List<String> words;
private final LookupService lookupService;
public Dictionary(List<String> words) {
this.words = this.words;
this.lookupService = new LookupService(words);
}
public boolean isFirstElement(String userData) {
return lookupService.isFirstElement(userData);
}
}
public class LookupService {
List<String> words;
public LookupService(List<String> words) {
this.words = words;
}
public boolean isFirstElement(String userData) {
return words.get(0).contains(userData);
}
}
이제 매개 변수에 Dictionary
대한 null
참조를 사용하여 생성자를 호출 해 보겠습니다 words
.
Dictionary dictionary = new Dictionary(null);
// exception thrown lately : only in the next statement
boolean isFirstElement = dictionary.isFirstElement("anyThing");
JVM은 다음 명령문에서 NPE를 발생시킵니다.
return words.get(0).contains(userData);
스레드 "main"의 예외 java.lang.NullPointerException
LookupService.isFirstElement (LookupService.java:5)에서
Dictionary.isFirstElement (Dictionary.java:15)에서
Dictionary.main (Dictionary.java:22)에서
예외는 LookupService
클래스 에서 발생 하며 그 기원은 훨씬 빠릅니다 ( Dictionary
생성자). 전체 이슈 분석이 훨씬 덜 명확 해집니다.
입니까 words
null
? 입니까 words.get(0) null
? 둘 다? 왜 하나, 다른 하나 또는 둘 다 null
인가? Dictionary
(생성자? 호출 된 메소드?) 의 코딩 오류 입니까? 의 코딩 오류 LookupService
입니까? (생성자? 호출 된 메소드?)?
마지막으로, 오류 원점을 찾기 위해 더 많은 코드를 검사해야하며, 더 복잡한 클래스에서는 디버거를 사용하여 발생한 상황을 더 쉽게 이해할 수도 있습니다.
그러나 왜 간단한 것 (널 체크가 없음)이 복잡한 문제가됩니까?
하위 구성 요소의 특정 구성 요소 누출에서 식별 가능한 초기 버그 / 부족을 허용했기 때문입니다.
상상 해봐LookupService
로컬 서비스가 아니라 원격 서비스 또는 디버깅 정보가 거의없는 타사 라이브러리 였거나 null
감지 되기 전에 2 층이 아니라 4 또는 5 층의 객체 호출이 있다고 상상해보십시오 . 문제는 여전히 분석하기가 더 복잡합니다.
따라서 선호하는 방법은 다음과 같습니다.
public Dictionary(List<String> words) {
this.words = Objects.requireNonNull(words);
this.lookupService = new LookupService(words);
}
이런 식으로 두통이 발생하지 않습니다.이를 수신하자마자 예외가 발생합니다.
// exception thrown early : in the constructor
Dictionary dictionary = new Dictionary(null);
// we never arrive here
boolean isFirstElement = dictionary.isFirstElement("anyThing");
스레드 "main"의 예외 java.lang.NullPointerException
java.util.Objects.requireNonNull (Objects.java:203)에서
com.Dictionary. (Dictionary.java:15)에서
com.Dictionary.main (Dictionary.java:24)에서
여기서는 생성자와 관련된 문제를 설명했지만 메서드 호출은 null이 아닌 동일한 검사 제약 조건을 가질 수 있습니다.