NullPointerException으로 인해 실패하는 코드가 있습니다. 객체가 존재하지 않는 객체에서 메소드가 호출되고 있습니다.
그러나 이것은 이것을 해결하는 가장 좋은 방법에 대해 생각하게했습니다. null 포인터 예외에 대한 향후 증거 코드를 보장하기 위해 항상 null을 방어 적으로 코딩합니까, 아니면 null의 원인을 수정하여 다운 스트림에서 발생하지 않도록해야합니다.
당신의 생각은 무엇입니까?
NullPointerException으로 인해 실패하는 코드가 있습니다. 객체가 존재하지 않는 객체에서 메소드가 호출되고 있습니다.
그러나 이것은 이것을 해결하는 가장 좋은 방법에 대해 생각하게했습니다. null 포인터 예외에 대한 향후 증거 코드를 보장하기 위해 항상 null을 방어 적으로 코딩합니까, 아니면 null의 원인을 수정하여 다운 스트림에서 발생하지 않도록해야합니다.
당신의 생각은 무엇입니까?
답변:
널이 메소드에 적합한 입력 매개 변수 인 경우 메소드를 수정하십시오. 그렇지 않은 경우 발신자를 수정하십시오. "합리적"은 유연한 용어이므로 다음 테스트를 제안합니다. 메소드가 어떻게 널 입력을 처리해야합니까? 둘 이상의 가능한 답변을 찾으면 null은 합리적인 입력 이 아닙니다 .
Precondition.checkNotNull(...)
있습니다. stackoverflow.com/questions/3022319/…를
IllegalArgumentException
null이 주어질 때 메서드가 throw되도록 할 수도 있습니다 . 이는 메소드 호출자에게 버그가 메소드 자체가 아니라 코드에 있음을 나타냅니다.
null을 사용하지 말고 옵션을 사용하십시오.
지적했듯이 null
Java에서 가장 큰 문제 중 하나는 모든 곳 에서 또는 적어도 모든 참조 유형에 사용할 수 있다는 것 입니다.
할 수있는 null
것과 할 수없는 것을 말하는 것은 불가능 합니다.
Java 8에는 훨씬 더 나은 패턴이 도입되었습니다 Optional
.
그리고 오라클의 예 :
String version = "UNKNOWN";
if(computer != null) {
Soundcard soundcard = computer.getSoundcard();
if(soundcard != null) {
USB usb = soundcard.getUSB();
if(usb != null) {
version = usb.getVersion();
}
}
}
이들 각각이 성공적인 값을 리턴하거나 리턴하지 않을 경우 API를 Optional
s로 변경할 수 있습니다 .
String name = computer.flatMap(Computer::getSoundcard)
.flatMap(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
유형에서 선택성을 명시 적으로 인코딩하면 인터페이스가 훨씬 좋아지고 코드가 깨끗해집니다.
Java 8을 사용하지 않는 경우 com.google.common.base.Optional
Google Guava에서 볼 수 있습니다 .
Guava 팀의 좋은 설명 : https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained
여러 언어의 예를 포함하여 null에 대한 단점에 대한 더 일반적인 설명 : https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/
@Nonnull, @Nullable
Java 8은 이러한 주석을 추가하여 IDE와 같은 코드 검사 도구가 문제를 포착하는 데 도움을줍니다. 그들은 효과가 상당히 제한적입니다.
말이되는지 확인
특히 코드에서 null
값으로 수행 할 수있는 작업이없는 경우 50 %의 null 검사 코드를 작성하지 마십시오 .
반면에, null
사용될 수 있고 의미가 있다면 그것을 사용하십시오.
궁극적 null
으로 Java에서 제거 할 수는 없습니다 . Optional
가능 하면 추상화를 대체하고 null
합리적인 시간에 다른 것을 할 수 있는지 확인 하는 것이 좋습니다 .
NullPointerException
습니까? A는 NullPointerException
그대로 일어날 수 있습니다 때마다 당신은 자바에서 인스턴스 메서드를 호출합니다. 당신은 것 throws NullPointerException
이제까지 거의 모든 하나의 방법이다.
이를 처리하는 여러 가지 방법이 있으며 코드를 페퍼 링하는 if (obj != null) {}
것은 이상적이지 않으며, 지저분하며, 유지 보수주기 동안 코드를 읽을 때 노이즈를 추가 하고이 보일러 플레이트 래핑을 잊어 버릴 수 있기 때문에 오류가 발생하기 쉽습니다.
코드가 자동으로 계속 실행되거나 실패하는지 여부에 따라 다릅니다. 는 IS null
오류 또는 예상되는 상태.
널이란?
모든 정의와 사례에서 Null 은 데이터의 절대적 부족을 나타냅니다. 데이터베이스의 널은 해당 열에 대한 값이 없음을 나타냅니다. 널은 String
빈과 동일하지 않습니다 String
널은, int
이론적으로, ZERO과 같은 것은 아니다. 실제로는 "의존한다". Empty String
는 비즈니스 로직에 의존 Null Object
하기 Integer
때문에 String 클래스에 대한 좋은 구현을 만들 수 있습니다 .
대안은 다음과 같습니다.
Null Object
패턴. null
상태 를 나타내는 객체의 인스턴스 를 만들고 Null
구현에 대한 참조로 해당 유형에 대한 모든 참조를 초기화하십시오 . 이는 유효한 상태 일 수도 있고 null
예상되는 다른 객체에 대한 참조가 많지 않은 단순 값 유형 객체에 유용합니다 null
.
Aspect Oriented 도구를 사용 Null Checker
하여 매개 변수가 널이되는 것을 방지 하는 aspect로 메소드를 짜십시오 . 이 경우에 인 null
오류가 발생합니다.
사용 assert()
하지 훨씬 더보다는 if (obj != null){}
하지만, 적은 소음.
Contracts For Java 와 같은 Contract Enforcement 도구를 사용하십시오 . AspectJ와 같은 유스 케이스이지만 최신 버전이며 외부 구성 파일 대신 주석을 사용합니다. Aspects와 Asserts의 두 작품 중 최고입니다.
1은 들어오는 데이터가 알려져 있고 null
일부 기본값으로 대체해야 할 때 이상적인 솔루션으로 , 업스트림 소비자가 모든 null 점검 상용구 코드를 처리 할 필요가 없습니다. 알려진 기본값을 확인하는 것이 더욱 표현력이 좋습니다.
2, 3 및 4는 편리한 대체 예외 생성기 NullPointerException
입니다.
결국
null
Java에서 거의 모든 경우에 논리 오류입니다. 의 근본 원인을 제거하기 위해 항상 노력해야합니다 NullPointerExceptions
. null
조건을 비즈니스 로직으로 사용하지 않도록 노력해야합니다 . if (x == null) { i = someDefault; }
기본 오브젝트 인스턴스에 초기 어설 션을 작성하십시오.
null == null
(PHP에서도), 그러나 데이터베이스에서는 데이터베이스에서 "아무것도 아닌" 알 수없는 값을 null != null
나타 내기 때문에 데이터베이스에서는 그렇지 않습니다. 두 개의 미지수는 반드시 동일하지는 않지만 두 개의 미지수는 동일하지 않습니다.
null 검사를 추가하면 테스트에 문제가 발생할 수 있습니다. 이 위대한 강의를 참조하십시오 ...
Google Tech 강의 강의 : "깨끗한 코드 강의 – 사물을 찾지 마십시오!" 그는 24 분쯤에 그것에 대해 이야기합니다
http://www.youtube.com/watch?v=RlfLCWKxHJ0&list=PL693EFD059797C21E
편집증 프로그래밍은 모든 곳에서 널 검사를 추가하는 것을 포함합니다. 그러나 처음에는 테스트 관점에서 좋은 아이디어처럼 보이므로 null 검사 유형 테스트를 처리하기가 어렵습니다.
또한 다음과 같은 일부 객체의 존재에 대한 전제 조건을 만들 때
class House(Door door){
.. null check here and throw exception if Door is NULL
this.door = door
}
예외가 발생하므로 하우스를 만들 수 없습니다. 테스트 케이스가 Door 이외의 것을 테스트하기 위해 모의 객체를 생성한다고 가정하면 문이 필요하기 때문에이 작업을 수행 할 수 없습니다
모의 창조 지옥을 겪은 사람들은 이러한 유형의 성가심을 잘 알고 있습니다.
요약하면, 테스트 스위트는 문, 집, 지붕 등을 편집 할 필요없이 테스트 할 수있을 정도로 견고해야합니다. 놀랍게도 테스트에서 특정 객체에 대해 null check 테스트를 추가하는 것이 얼마나 어려운가 :)
작동하는 것이 아니라 여러 가지 테스트가 있기 때문에 항상 작동하는 응용 프로그램을 선호해야합니다.
tl; dr- 예상치 못한 null
s를 확인하는 것이 좋지만 응용 프로그램이 제대로 작동하도록하려면 BAD입니다.
세부
null
메소드에 대한 유효한 입력 또는 출력이있는 상황 과 그렇지 않은 상황이 있습니다.
규칙 # 1 :
null
매개 변수 를 허용 하거나null
값을 리턴 하는 메소드의 javadoc 은이 를 명확하게 문서화하고null
의미를 설명해야합니다 .
규칙 # 2 :
null
적절한 이유 가없는 한 API 메소드를 승인하거나 리턴하는 것으로 지정해서는 안됩니다 .
메소드의 "계약"에 대한 명확한 스펙이 주어지면, 원하지 않는 곳 을 전달하거나 반환하는 null
것은 프로그래밍 오류null
입니다.
규칙 # 3 :
응용 프로그램은 "좋은"프로그래밍 오류를 시도해서는 안됩니다.
메소드 null
가 존재하지 않아야 하는 것을 감지하면 다른 것으로 바꾸어 문제를 해결하려고 시도해서는 안됩니다. 그것은 프로그래머로부터 문제를 숨 깁니다. 대신 NPE가 발생하고 장애를 유발하여 프로그래머가 근본 원인을 파악하고 해결할 수 있도록해야합니다. 테스트 중에 실패가 발견되기를 바랍니다. 그렇지 않다면 테스트 방법론에 대해 이야기합니다.
규칙 # 4 :
가능한 경우 코드를 작성하여 프로그래밍 오류를 조기에 감지하십시오.
코드에 NPE가 많이 발생하는 버그가있는 경우 가장 어려운 점은 null
값의 출처를 알아낼 수 있습니다 . 진단을보다 쉽게하는 한 가지 방법은 코드를 작성하여 null
가능한 빨리 감지 되도록하는 것 입니다. 종종 다른 검사와 함께이 작업을 수행 할 수 있습니다. 예 :
public setName(String name) {
// This also detects `null` as an (intended) side-effect
if (name.length() == 0) {
throw new IllegalArgumentException("empty name");
}
}
(규칙 3과 4가 현실적으로 강화되어야하는 경우가 있습니다. 예를 들어 (규칙 3), 일부 종류의 응용 프로그램 은 아마도 프로그래밍 오류를 감지 한 후에 계속 시도 해야 합니다. (규칙 4) 잘못된 매개 변수를 너무 많이 검사하면 성능 영향.)
방어적인 방법으로 수정하는 것이 좋습니다. 예를 들어 :
String go(String s){
return s.toString();
}
이 줄을 따라야합니다.
String go(String s){
if(s == null){
return "";
}
return s.toString();
}
나는 이것이 절대적으로 사소한 것을 알고 있지만, 호출자가 객체를 기대하면 null을 전달하지 않는 기본 객체를 제공하십시오.
new String()
합니다.
null
s를 자동으로 수정 하는 것이 NPE를 던지는 것보다 최악의 가능한 옵션입니다.
null에 대한 다음과 같은 일반적인 규칙은 지금까지 많은 도움이되었습니다.
데이터가 제어 시스템 외부에서 오는 경우, 체계적으로 널 (null)을 점검하고 적절하게 작동하십시오. 이것은 함수에 의미가있는 예외를 던지는 것을 의미합니다 (체크 또는 체크되지 않음, 예외의 이름이 정확히 무슨 일인지 알려줍니다). 그러나 잠재적으로 놀라움을 줄 수있는 시스템의 가치를 잃어 버리지 마십시오.
Null이 데이터 모델에 적합한 값의 도메인 내에 있으면 적절하게 처리하십시오.
값을 반환 할 때 가능하면 null을 반환하지 마십시오. 항상 빈 목록, 빈 문자열, Null 개체 패턴을 선호합니다. 주어진 유스 케이스에 대해 가능한 최상의 데이터 표현 인 경우 널을 리턴 값으로 유지하십시오.
아마도 가장 중요한 것은 ... 테스트, 테스트 및 다시 테스트하십시오. 코드를 테스트 할 때 코드를 코더로 테스트하지 마십시오. Nazi psychopath 지배자로 테스트하고 해당 코드에서 지옥을 고문하는 모든 종류의 방법을 상상해보십시오.
이것은 널과 관련하여 편집증 측면에서 약간의 경향이 있으며 종종 시스템을 외부 세계와 인터페이스하고 내부의 값을 풍부한 중복으로 엄격하게 제어하는 외관 및 프록시로 이어집니다. 외부 세계는 내가 직접 코딩하지 않은 모든 것을 의미합니다. 비용 런타임을 부담하지만 지금까지 코드의 "널 안전 섹션"을 생성하여이를 최적화 할 필요는 거의 없었습니다. 나는 건강 관리를 위해 오래 실행되는 시스템을 주로 만들고 있다고 말해야합니다. 마지막으로 원하는 것은 다른 시스템의 누군가가 이름을 알 수 없기 때문에 예기치 않은 널 포인터로 인해 요오드 알레르기를 CT 스캐너에 전달하는 인터페이스 하위 시스템입니다 아포스트로피 또는 但 耒耨。와 같은 문자를 포함
어쨌든 .. 내 2 센트
기능적 언어의 Option / Some / None 패턴 사용을 제안합니다. Java 전문가는 아니지만 C # 프로젝트에서이 패턴을 직접 구현하여 Java 세계로 변환 할 수 있다고 확신합니다.
이 패턴의 기본 개념은 다음과 같습니다. 논리적으로 값이 없을 가능성이있는 상황 (예 : id를 데이터베이스에서 검색 할 때)이있는 경우 Option [T] 유형의 오브젝트를 제공합니다. 여기서 T는 가능한 값입니다. . None [T] 클래스의 값 객체가 없으면 값을 포함하는 값-Some [T]의 객체가 반환 된 경우 반환됩니다.
이 경우 가치 부재 가능성을 처리 해야하며 코드 검토를 수행하면 잘못 처리 한 장소를 쉽게 찾을 수 있습니다. C # 언어 구현에서 영감을 얻으려면 내 비트 버킷 저장소 https://bitbucket.org/mikegirkin/optionsomenone을 참조하십시오.
널값을 리턴하고 논리적으로 오류와 같거나 (예 : 파일이 없거나 연결할 수없는 경우) 예외를 발생 시키거나 다른 오류 처리 패턴을 사용해야합니다. 이 뒤에 숨겨진 아이디어 는 가치 결여 상황을 처리 해야 하고 코드에서 잘못된 처리 위치를 쉽게 찾을 수있을 때 솔루션으로 끝납니다 .
Apache Commons의 lang 라이브러리는 널값을 처리하는 방법을 제공합니다
ObjectUtils 클래스의 defaultIfNull 메소드를 사용하면 전달 된 오브젝트가 널인 경우 기본값을 리턴 할 수 있습니다
선택적인 유형이 아니라면 선택적 유형을 사용하지 마십시오. 옵션으로 null을 기대하지 않았고 정기적으로 버그가있는 코드를 작성하지 않기 때문에 종료는 예외로 처리하는 것이 좋습니다.
구글의 기사가 지적했듯이 문제는 그것이 사용하는 유형으로 null이 아닙니다. 문제는 널 (null)을 점검하고 처리해야한다는 것입니다. 종종 정상적으로 종료 될 수 있습니다.
프로그램의 일상적인 작업 이외의 영역 (유효하지 않은 사용자 입력, 데이터베이스 문제, 네트워크 장애, 파일 누락, 데이터 손상)에서 유효하지 않은 조건을 나타내는 다수의 null 경우가 있습니다. 로그 만하면됩니다.
예외 처리는 선택과 같은 유형과 달리 JVM에서 다른 작동 우선 순위와 특권이 허용됩니다. 처리기의 메모리에 우선 순위가 지정된 지연로드를 조기에 지원하는 것을 포함하여 발생의 예외적 인 특성에 적합합니다. 항상 매달려 있어야합니다.
널 핸들러를 어디서나 작성할 필요는 없으며, 잠재적으로 신뢰할 수없는 데이터 서비스에 액세스 할 수있는 곳에서만 발생할 수 있으며, 대부분 쉽게 추상화 할 수있는 몇 가지 일반적인 패턴에 속하므로 실제로 필요한 것만 필요합니다 드문 경우를 제외하고 핸들러 호출
따라서 내 대답은 확인 된 예외로 감싸서 처리하거나 신뢰할 수없는 코드가 기능 범위 내에 있으면 수정하는 것 같습니다.