속성에 대한 간단한 setter 메서드가 있으며이 null
특정 속성에는 적합하지 않습니다. 난 항상 이런 상황에서 찢어되었습니다 내가 던져해야한다 IllegalArgumentException
, 또는를 NullPointerException
? javadoc에서 두 가지 모두 적절 해 보입니다. 이해되는 표준이 있습니까? 아니면 이것은 당신이 원하는대로해야하고 둘 다 정말로 올바른 것 중 하나입니까?
속성에 대한 간단한 setter 메서드가 있으며이 null
특정 속성에는 적합하지 않습니다. 난 항상 이런 상황에서 찢어되었습니다 내가 던져해야한다 IllegalArgumentException
, 또는를 NullPointerException
? javadoc에서 두 가지 모두 적절 해 보입니다. 이해되는 표준이 있습니까? 아니면 이것은 당신이 원하는대로해야하고 둘 다 정말로 올바른 것 중 하나입니까?
답변:
허용 된 값 IllegalArgumentException
이 null
되고 싶지 않다면 호출 된 것처럼 보이고 , 로 변하는 변수 NullPointerException
를 사용 하려고하면 throw됩니다 null
.
IllegalArgumentException
자바의와 모순에 Objects.requireNonNull (T) 와 구아바의 Preconditions.checkNotNull (T) 발생합니다 NullPointerException
. 그러나 Jason Cohen의 탁월한 답변과 설명 섹션에 설명 된대로 정답은 확실 합니다 . IllegalArgumentException
다음과 같은 이유로 (NPE)가 IllegalArgumentException
아닌 (IAE)를 사용해야합니다 NullPointerException
.
먼저 NPE JavaDoc 은 NPE가 적절한 경우를 명시 적으로 나열합니다. 그들 모두가 발생하는 것을 알 수 런타임에서 때 null
부적절하게 사용됩니다. 반대로 IAE JavaDoc 은 더 명확하지 않았다. "메소드가 부적절하거나 부적합한 인수를 전달했음을 나타냅니다." 그래, 너야!
둘째, 스택 추적에 NPE가 표시되면 무엇을 가정합니까? 아마도 누군가가 a null
. IAE가 표시되면 스택 맨 위에있는 메소드 호출자가 잘못된 값으로 전달되었다고 가정합니다. 다시, 후자의 가정은 사실이며, 전자는 오도합니다.
셋째, IAE는 매개 변수를 검증하기 위해 명확하게 설계되었으므로이를 기본 예외 선택으로 가정해야하므로 왜 NPE를 선택해야합니까? 분명히 다른 행동을위한 것은 아닙니다. 전화 코드가 IAE와 별도로 NPE를 포착하고 결과적으로 다른 것을 수행 할 것으로 기대합니까? 보다 구체적인 오류 메시지를 전달하려고합니까? 그러나 다른 모든 잘못된 매개 변수와 마찬가지로 예외 메시지 텍스트에서 그렇게 할 수 있습니다.
넷째, 다른 모든 잘못된 매개 변수 데이터는 IAE이므로 일관성이없는 이유는 무엇입니까? 불법 null
이 너무 특별하여 다른 모든 유형의 불법 주장과는 별도로 예외가 필요한 이유는 무엇 입니까?
마지막으로, 나는 Java API의 일부가 이런 식으로 NPE를 사용한다는 다른 답변에 의해 주어진 주장을 받아들입니다. 그러나 Java API는 예외 유형에서 명명 규칙에 이르기까지 모든 것과 일치하지 않으므로 Java API를 맹목적으로 복사하는 것만으로는 이러한 다른 고려 사항을 능가하기에 충분하지 않습니다.
Validate.notNull
(commons lang)과 Preconditions.checkNotNull
(guava)는 모두 NPE를 던집니다 :-(
checkArgument(arg != null)
arg를 반환하는 편리함없이 arg를 반환하거나 만들 수 있습니다. 프로젝트의 로컬 유틸리티입니다. " code.google.com/p/guava-libraries/wiki/IdeaGraveyard
표준은을 던지는 것 NullPointerException
입니다. 일반적으로 오류가없는 "유효한 Java"는 항목 42 (1 판), 항목 60 (2 판) 또는 항목 72 (3 판) "표준 예외 사용"에서 간단히 설명합니다.
"어쩌면 모든 잘못된 메소드 호출은 불법 인수 또는 불법 상태로 귀결되지만 다른 종류의 예외는 특정 종류의 불법 인수 및 상태에 표준으로 사용됩니다. 발신자가 null 값이 금지 된 일부 매개 변수에서 null을 전달하면 규칙에 따라 IllegalArgumentException이 아닌 NullPointerException이 발생합니다. "
Java 7 IllegalArgumentException
에서 java.util.Objects.requireNonNull
메소드를 발견했을 때까지 오늘까지 null 매개 변수 를 처리하는 것에 찬성했습니다 . 해당 메소드를 사용하는 대신 다음을 수행하십시오.
if (param == null) {
throw new IllegalArgumentException("param cannot be null.");
}
넌 할 수있어:
Objects.requireNonNull(param);
NullPointerException
전달하는 매개 변수 가 인 경우 throw됩니다 null
.
그 방법이 중간에 옳다는 것을 감안할 때, java.util
던지는 NullPointerException
것이 "일을하는 Java 방식" 이라는 꽤 강한 표시로 존재합니다 .
나는 어떤 속도로 결정되었다고 생각합니다.
NullPointerException
널 (null)이 무엇인지, 왜 널 (null)이되지 않아야하는지에 대한 메시지를 제공 할 수 있기 때문에 하드 디버깅에 대한 논증은 허위 임에 유의하십시오 . 와 마찬가지로 IllegalArgumentException
.
또 하나의 이점은 NullPointerException
고성능의 중요한 코드에서 널 (null)에 대한 명시 적 점검 (및 NullPointerException
친숙한 오류 메시지)을 생략 할 수 있으며 널 (null )에서 NullPointerException
메소드를 호출 할 때 자동으로 얻을 수 있다는 것입니다 매개 변수. 메소드를 빠르게 호출하면 (즉, 실패), 개발자에게 익숙하지 않은 본질적으로 동일한 효과가 있습니다. 대부분의 경우 명시 적으로 검사하고 어떤 매개 변수가 null인지 나타내는 유용한 메시지를 표시하는 것이 좋습니다. 그러나 퍼포먼스가 메소드 / 생성자의 공개 된 계약을 위반하지 않으면 서 변경하는 옵션을 갖는 것이 좋습니다.
Preconditions.checkNotNull(arg)
도 NPE를 던졌습니다.
JDK 라이브러리의 디자인, 특히 컬렉션 및 동시성 (Joshua Bloch, Doug Lea, 견고한 API를 디자인하는 방법을 알고 있음)을 따르는 경향이 있습니다. 어쨌든 JDK의 많은 API가 능동적으로 발생 NullPointerException
합니다.
예를 들어, Map.containsKey
상태에 대한 Javadoc은 다음과 같습니다.
@throws NullPointerException 키가 null이고,이 맵이 null 키를 허용하지 않는 경우는 (옵션)
자신의 NPE를 던지는 것이 완벽하게 유효합니다. 규칙은 예외 메시지에서 널인 매개 변수 이름을 포함하는 것입니다.
패턴은 다음과 같습니다.
public void someMethod(Object mustNotBeNull) {
if (mustNotBeNull == null) {
throw new NullPointerException("mustNotBeNull must not be null");
}
}
무엇을 하든지 나쁜 값을 설정하여 다른 코드에서 사용하려고 할 때 나중에 예외를 발생시키지 마십시오. 그것은 악몽을 디버깅합니다. 항상 "실패"원칙을 따라야합니다.
Jason Cohen의 주장은 잘 발표 되었기 때문에 투표했습니다. 단계별로 설명하겠습니다. ;-)
NPE의 javadoc에서는 명시 적으로 말한다 "널 객체의 다른 불법 사용" . 런타임에 null이 발생하지 않아야하는 상황으로 제한되는 경우 이러한 모든 경우를 간결하게 정의 할 수 있습니다.
잘못된 것을 가정하면 도움이되지 않지만 캡슐화가 올바르게 적용되었다고 가정하면 null이 부적절하게 역 참조되었는지 여부와 메소드가 부적합한 null을 감지하여 예외를 발생했는지 여부를 신경 쓰지 않아야합니다.
여러 가지 이유로 IAE 보다 NPE 를 선택했습니다.
실제로 다른 잘못된 인수로 인해 모든 종류의 다른 예외가 발생할 수 있습니다. UnknownHostException , FileNotFoundException , 다양한 구문 오류 예외, IndexOutOfBoundsException , 인증 실패 등
일반적으로 NPE는 전통적으로 페일 패스트 원칙 을 따르지 않는 코드와 관련되어 있기 때문에 NPE가 많이 악의적이라고 생각합니다 . 또한 JDK가 NPE를 메시지 문자열로 채우지 못하는 것은 실제로 제대로 확립되지 않은 강한 부정적인 감정을 만들어 냈습니다. 실제로 런타임 관점에서 NPE와 IAE의 차이점은 엄격하게 이름입니다. 이러한 관점에서 볼 때 이름이 정확할수록 발신자에게 더 명확 해집니다.
"성전"스타일 질문입니다. 다시 말해, 두 가지 대안이 모두 좋지만 사람들은 자신이 선호하는 죽음을 방어 할 것입니다.
NullPointerException
던져 져야 한다고 생각한다 : 그것은 JDK가 사용하고, 인터페이스를 위해 요구되는 관습이다. 더 구체적이다 (등과 같이 IndexOutOfBoundsException
) 등등.
Apache Commons Lang에는 NullArgumentException 이 있으며 여기에서 논의되는 많은 작업을 수행합니다. IllegalArgumentException을 확장하고 유일한 생성자는 널이 아닌 인수의 이름을 사용합니다.
NullArgumentException 또는 IllegalArgumentException과 같은 것을 던지면 예외적 인 상황을보다 정확하게 설명한다고 생각하지만 동료와 나는 주제에 대한 Bloch의 조언을 연기하기로 결정했습니다.
실제로, IllegalArgumentException 또는 NullPointerException을 던지는 문제는 겸손한 견해로는 소수의 사람들에게 Java의 예외 처리에 대한 이해가 불완전한 이해에 불과합니다. 일반적으로 규칙은 간단하며 다음과 같습니다.
모든 종류의 인수 제약 조건 위반을 IllegalArgumentException에 매핑하는 경우에 대해 적어도 세 가지 이유가 있습니다. 세 번째는 연습 스타일을 나쁜 스타일로 표시하는 것입니다.
(1) 프로그래머는 인수 제약 조건 위반의 모든 경우에 IllegalArgumentException이 발생한다고 안전하게 가정 할 수 없습니다. 표준 클래스의 대부분은 더 이상 사용할 수있는 특정 종류의 예외가없는 경우이 예외를 휴지통으로 사용하기 때문입니다. 표준 라이브러리는 대부분 자신을 위반하는 다른 규칙을 따르므로 대부분의 API 사용자도이를 사용하므로 API에서 인수 제약 조건 위반의 모든 사례를 IllegalArgumentException에 매핑하려고하면 클래스를 사용하는 프로그래머가 좌절하게됩니다.
(2) 예외를 매핑하면 실제로 단일 상속으로 인해 다른 종류의 예외가 발생합니다. 모든 Java 예외는 클래스이므로 단일 상속 만 지원합니다. 따라서 서브 클래스는 하나만 상속 할 수 있으므로 NullPointerException과 IllegalArgumentException을 모두 나타내는 예외를 만들 수있는 방법이 없습니다. 따라서 null 인수의 경우 IllegalArgumentException을 발생 시키면 프로그램이 프로그래밍 방식으로 문제를 수정하려고 할 때마다 (예 : 기본값을 호출 반복에 공급하여) API 사용자가 문제를 구분하기가 더 어려워집니다!
(3) 매핑은 실제로 버그 마스킹의 위험을 만듭니다. 인수 제약 조건 위반을 IllegalArgumentException에 매핑하려면 제한된 인수가있는 모든 메서드 내에서 외부 try-catch를 코딩해야합니다. 그러나이 catch 블록에서 RuntimeException을 단순히 포착하는 것은 의문의 여지가 없습니다. 왜냐하면 인수 제약 조건 위반으로 인한 것이 아니더라도 자신의 내부에서 사용되는 리버티 메소드에 의해 발생 된 문서화 된 RuntimeException을 IllegalArgumentException에 매핑 할 위험이 있기 때문입니다. 따라서 매우 구체적이어야하지만 그 노력으로도 다른 API의 문서화되지 않은 런타임 예외 (예 : 버그)를 API의 IllegalArgumentException에 실수로 매핑하는 경우를 막을 수는 없습니다.
반면에 표준 관행을 사용하면 규칙이 단순하게 유지되고 예외로 인해 예외가 발생하지 않고 구체적으로 유지됩니다. 메소드 호출자의 경우 규칙도 간단합니다.-잘못된 값을 전달하여 문서화 된 런타임 예외가 발생하는 경우 기본값을 사용하여 호출을 반복하거나 (이 특정 예외가 필요한 경우) 코드를 정정하십시오. -반면에 주어진 인수 집합에 대해 발생하지 않는 런타임 예외가 발생하면 메서드 제조업체에 버그 보고서를 작성하여 코드 또는 설명서가 수정되었는지 확인하십시오.
IllegalArgumentException (String message) 을 사용하여 매개 변수를 유효하지 않은 것으로 선언하고 가능한 한 자세하게 설명 하는 경우 허용되는 관행 ... 예외가 null이 아닌 동안 매개 변수가 null 인 것으로 판단되면 무언가를 수행합니다. 이처럼 :
if( variable == null )
throw new IllegalArgumentException("The object 'variable' cannot be null");
"NullPointerException"을 암시 적으로 사용할 이유가 없습니다. NullPointerException은 null 참조 (Like toString () ) 에서 코드를 실행하려고 할 때 Java Virtual Machine에서 발생하는 예외 입니다.
null
인수 에만 적용되는 예외 ( NullPointerException
사용자 정의 유형에 관계없이 )를 발생 시키면 자동화 된 null
테스트의 안정성이 향상됩니다. 이 자동화 된 테스트는 같이 반사 및 기본 값 세트와 함께 할 수 구아바 의 NullPointerTester
. 예를 들어 NullPointerTester
다음 방법을 호출하려고 시도합니다.
Foo(String string, List<?> list) {
checkArgument(string.length() > 0);
// missing null check for list!
this.string = string;
this.list = list;
}
... 두 개의 인수 목록이 있습니다 : "", null
및 null, ImmutableList.of()
. 이러한 각 호출이 예상대로 발생하는지 테스트합니다 NullPointerException
. 이 구현의 경우 null
목록을 전달해 도 생성 되지 않습니다NullPointerException
. 그러나 기본 문자열 인을 사용 IllegalArgumentException
하기 때문에 를 생성합니다 . 경우 에만이 기대 에 대한 값은 버그를 잡는다. 기대 하면 놓칩니다.NullPointerTester
""
NullPointerTester
NullPointerException
null
IllegalArgumentException
일부 컬렉션에서는가 아닌을 null
사용하여 거부 된 것으로 가정합니다 . 예를 들어,이 포함되는 세트 비교하면 불량이있는 세트로 , 첫 번째 세트가 호출 다른과의 잡을 -하지만를 . (의 구현을보고 있습니다.)NullPointerException
IllegalArgumentException
null
null
containsAll
NullPointerException
IllegalArgumentException
AbstractSet.equals
당신은 합리적으로 포함 비교 컬렉션 것으로,이 방법으로 체크되지 않은 예외를 사용하여 안티 패턴이라고 주장 할 수 null
포함 할 수 없습니다 컬렉션에이 null
정말 가능성이 버그 한다 예외를 생산하는이, 또는 퍼팅 것을 null
모두에서 컬렉션은 나쁜 생각 . 그럼에도 불구하고 equals
그러한 경우에 예외를 던져야 한다고 말하지 않는다면 NullPointerException
특정 상황에서는 필요하지만 다른 상황에서는 필요하지 않다는 것을 기억해야 합니다. ( " 'c'다음을 제외한 NPE 이전의 IAE ...")
new TreeSet<>().containsAll(Arrays.asList((Object) null));
던졌습니다 NPE
(가) 때문에 List
포함 null
.
주관적인 질문으로 이것은 닫혀 있어야하지만 여전히 열려 있습니다.
이것은 이전 직장에서 사용 된 내부 정책의 일부이며 실제로 효과가있었습니다. 이것은 모두 기억에서 나왔으므로 정확한 문구를 기억할 수 없습니다. 그들이 확인 된 예외를 사용하지 않았다는 점은 주목할 가치가 있지만 그것은 질문의 범위를 벗어납니다. 그들이 사용하지 않은 예외는 세 가지 주요 범주로 나뉩니다.
NullPointerException : 의도적으로 던지지 마십시오. NPE는 null 참조를 역 참조 할 때 VM에서만 발생합니다. 이것들이 절대로 던져지지 않도록 가능한 모든 노력을 기울여야합니다. 이러한 오류를 찾으려면 @Nullable 및 @NotNull을 코드 분석 도구와 함께 사용해야합니다.
IllegalArgumentException : 함수에 대한 인수가 공개 문서를 준수하지 않아 전달 된 인수로 오류를 식별하고 설명 할 수있을 때 발생합니다. OP의 상황은이 범주에 속합니다.
IllegalStateException : 함수가 호출되고 인수가 전달 될 때 예상치 못한 인수이거나 메소드가 속한 오브젝트의 상태와 호환되지 않는 경우 발생합니다.
예를 들어, 길이가있는 것들에 사용 된 IndexOutOfBoundsException의 두 가지 내부 버전이있었습니다. 색인이 길이보다 큰 경우 사용되는 IllegalStateException의 서브 클래스 중 하나입니다. 인덱스가 음수 인 경우 사용되는 IllegalArgumentException의 다른 하위 클래스입니다. 객체에 더 많은 항목을 추가 할 수 있고 인수는 유효하지만 음수가 유효하지 않기 때문입니다.
내가 말했듯이,이 시스템은 정말 잘 작동하며, 왜 그 차이가 있는지 설명하는 누군가가 필요했습니다. 무엇이 잘못되었는지 파악하여 오류를 잡아야 할 위치를 파악하고 추가 디버깅 정보를 만들 수 있습니다. "
NullPointerException : NPE가 처리되지 않도록 Null 케이스를 처리하거나 어설 션을 넣습니다. 어설 션을 입력하면 다른 두 가지 유형 중 하나 일뿐입니다. 가능하면 어설 션이 처음에있는 것처럼 디버깅을 계속하십시오.
IllegalArgumentException : 콜 사이트에 문제가 있습니다. 전달되는 값이 다른 함수에서 온 것이라면 왜 잘못된 값을 받는지 알아보십시오. 인수 중 하나를 전달하면 예상 한 결과를 반환하지 않는 함수를 찾을 때까지 오류가 호출 스택을 검사합니다.
IllegalStateException : 함수를 올바른 순서로 호출하지 않았습니다. 인수 중 하나를 사용하는 경우 인수를 확인하고 문제를 설명하는 IllegalArgumentException을 발생시킵니다. 그런 다음 문제를 찾을 때까지 뺨을 스택에 전파 할 수 있습니다.
어쨌든 그의 요점은 IllegalArgumentAssertions 만 스택에 복사 할 수 있다는 것입니다. IllegalStateExceptions 또는 NullPointerExceptions가 함수와 관련이 있기 때문에 스택에 전파 할 수있는 방법이 없습니다.
일반적으로 개발자는 NullPointerException을 발생 시키지 않아야합니다 . 이 예외는 코드에서 값이 null 인 변수를 역 참조하려고 할 때 런타임에 발생합니다. 따라서 null 값이 NullPointerException을 발생시키는 것과 달리 메서드가 null을 명시 적으로 허용하지 않으려면 IllegalArgumentException을 발생시켜야합니다.
다른 잘못된 인수에서 Null 인수를 선택하고 싶기 때문에 IAE에서 NullArgumentException이라는 예외를 파생했습니다. 예외 메시지를 읽을 필요조차없이 null 인수가 메서드에 전달되었음을 알고 메시지를 읽음으로써 어떤 인수가 null인지 알 수 있습니다. 나는 여전히 IAE 처리기로 NullArgumentException을 포착하지만 내 로그에서 차이점을 빠르게 볼 수 있습니다.
이분법은 ... 겹치지 않나요? 전체의 겹치지 않는 부분 만 이분법을 만들 수 있습니다. 내가 본대로 :
throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));
NullPointerException
가 아무것도하지 않기 때문에 실제로 도움이되지 않습니다. 도움이 될 수있는 유일한 것은입니다 IllegalNullPointerArgumentException extends IllegalArgumentException, NullPointerException
. 그러나 다중 상속이 없습니다.
위의 두 예외에 대한 링크의 정의는 IllegalArgumentException입니다. 메소드에 부적절하거나 부적절한 인수가 전달되었음을 표시하기 위해 발생합니다. NullPointerException : 객체가 필요한 경우에 응용 프로그램에서 null을 사용하려고하면 발생합니다.
여기서 큰 차이점은 메서드에 대한 인수가 유효한지 확인할 때 IllegalArgumentException이 사용된다는 것입니다. NullPointerException은 개체가 null 일 때 개체를 "사용"할 때마다 사용됩니다.
나는 그것이 두 가지 관점에 도움이되기를 바랍니다.
프로그래머가 잘못된 것을 한 것이 분명해 지므로 IllegalArgumentException을 발생시켜야합니다. 개발자들은 VM에 의해 던져진 NPE를 보는 데 익숙해 져 프로그래머가 즉시 자신의 오류를 인식하지 못하고 무작위로 또는 더 나쁘게 둘러보기 시작하여 코드가 '버기'되었다고 비난합니다.
이 경우, IllegalArgumentException은 API를 사용하여 "널이 아니어야합니다"라는 명확한 정보를 사용자에게 전달합니다. 다른 포럼 사용자가 지적했듯이 API를 사용하여 사용자에게 올바른 정보를 전달하기를 원한다면 NPE를 사용할 수 있습니다.
GaryF와 tweakt는 NPE 사용을 권장하는 "Effective Java"(내가 맹세 한) 참조를 삭제했다. 그리고 다른 좋은 API가 어떻게 구성되는지 보는 것이 API를 구성하는 방법을 보는 가장 좋은 방법입니다.
또 다른 좋은 예는 Spring API를 보는 것입니다. 예를 들어, org.springframework.beans.BeanUtils.instantiateClass (Constructor ctor, Object [] args)에는 Assert.notNull (ctor, "Constructor는 null이 아니어야합니다") 행이 있습니다. org.springframework.util.Assert.notNull (Object object, String message) 메소드는 전달 된 인수 (객체)가 null인지 확인하고 새로운 IllegalArgumentException (message)을 발생시키는 지 확인합니다. springframework.beans.BeanUtils.instantiateClass (...) 메소드.
NPE를 던지려고 선택하고 메소드에서 인수를 사용하는 경우 널을 명시 적으로 검사하는 것이 중복되고 비용이 많이들 수 있습니다. VM이 이미 그렇게한다고 생각합니다.
NPE
하지만 프로그래머는 IAE
원하는 경우 VM보다 먼저 말을 합니다.