etc./StackOverFlow

Java에서 NullPointerException 방지

청렴결백한 만능 재주꾼 2021. 9. 26. 10:52
반응형

질문자 :Community Wiki


NullPointerException 을 피하기 위해 object != null 을 많이 사용합니다.

다음의 대안은 무엇입니까?

 if (someobject != null) { someobject.doCalc(); }


답변자 : Community Wiki


나에게 이것은 중급 개발자가 어느 시점에서 직면하는 경향이 있는 합리적으로 일반적인 문제처럼 들립니다. 그들은 참여하고 있는 계약을 모르거나 신뢰하지 않고 방어적으로 null에 대해 과잉 검사합니다. 또한 자체 코드를 작성할 때 null을 반환하여 무언가를 나타내므로 호출자가 null을 확인해야 하는 경향이 있습니다.

다시 말해서 null 검사가 발생하는 두 가지 경우가 있습니다.

  1. null이 계약에 따라 유효한 응답인 경우 그리고

  2. 유효한 응답이 아닌 경우.

(2) 쉽습니다. assert 문(어설션)을 사용하거나 실패를 허용합니다(예: NullPointerException ). 어설션은 1.4에 추가된 많이 사용되지 않는 Java 기능입니다. 구문은 다음과 같습니다.

 assert <condition>

또는

 assert <condition> : <object>

여기서 <condition> 은 부울 표현식이고 <object> toString() 메서드의 출력이 오류에 포함될 객체입니다.

조건이 true가 아닌 경우 assert 문은 Error ( AssertionError 기본적으로 Java는 어설션을 무시합니다. -ea 옵션을 JVM에 전달하여 어설션을 활성화할 수 있습니다. 개별 클래스 및 패키지에 대해 어설션을 활성화 및 비활성화할 수 있습니다. 즉, 내 테스트에서 어설션이 성능에 거의 영향을 미치지 않는 것으로 나타났지만 개발 및 테스트하는 동안 어설션으로 코드의 유효성을 검사하고 프로덕션 환경에서 비활성화할 수 있습니다.

이 경우 어설션을 사용하지 않는 것은 괜찮습니다. 어설션을 사용하면 코드가 실패하기 때문입니다. 유일한 차이점은 어설션을 사용하면 더 빨리, 더 의미 있는 방식으로, 추가 정보를 통해 발생할 수 있다는 점입니다. 이는 예상하지 못한 경우 발생한 이유를 파악하는 데 도움이 될 수 있다는 것입니다.

(1) 조금 어렵다. 호출하는 코드를 제어할 수 없다면 막힌 것입니다. null이 유효한 응답이면 확인해야 합니다.

그러나 제어하는 것이 코드라면(그리고 종종 이런 경우도 있음) 이야기가 다릅니다. null을 응답으로 사용하지 마십시오. 컬렉션을 반환하는 메서드를 사용하면 쉽습니다. 거의 항상 null 대신 빈 컬렉션(또는 배열)을 반환합니다.

컬렉션이 아닌 경우 더 어려울 수 있습니다. 다음과 같은 인터페이스가 있는 경우 다음을 예로 고려하십시오.

 public interface Action { void doSomething(); } public interface Parser { Action findAction(String userInput); }

여기서 Parser는 원시 사용자 입력을 받아 수행할 작업을 찾습니다. 아마도 무언가에 대한 명령줄 인터페이스를 구현하는 경우일 수 있습니다. 이제 적절한 조치가 없으면 null을 반환하는 계약을 만들 수 있습니다. 그것은 당신이 말하는 null 검사로 이어집니다.

대체 솔루션은 null을 반환하지 않고 대신 Null Object 패턴을 사용하는 것입니다.

 public class MyParser implements Parser { private static Action DO_NOTHING = new Action() { public void doSomething() { /* do nothing */ } }; public Action findAction(String userInput) { // ... if ( /* we can't find any actions */ ) { return DO_NOTHING; } } }

비교하다:

 Parser parser = ParserFactory.getParser(); if (parser == null) { // now what? // this would be an example of where null isn't (or shouldn't be) a valid response } Action action = parser.findAction(someInput); if (action == null) { // do nothing } else { action.doSomething(); }

에게

 ParserFactory.getParser().findAction(someInput).doSomething();

더 간결한 코드로 이어지기 때문에 훨씬 더 나은 디자인입니다.

즉, findAction() 메서드가 의미 있는 오류 메시지와 함께 예외를 throw하는 것이 완전히 적절할 수 있습니다. 특히 이 경우 사용자 입력에 의존합니다. 호출하는 메서드가 설명 없이 간단한 NullPointerException으로 폭발하는 것보다 findAction 메서드가 Exception을 throw하는 것이 훨씬 낫습니다.

 try { ParserFactory.getParser().findAction(someInput).doSomething(); } catch(ActionNotFoundException anfe) { userConsole.err(anfe.getMessage()); }

또는 try/catch 메커니즘이 너무 추하다고 생각되면 Do Nothing보다 기본 작업이 사용자에게 피드백을 제공해야 합니다.

 public Action findAction(final String userInput) { /* Code to return requested Action if found */ return new Action() { public void doSomething() { userConsole.err("Action not found: " + userInput); } } }


답변자 : Community Wiki


JetBrains IntelliJ IDEA , Eclipse 또는 Netbeans 와 같은 Java IDE 또는 findbugs와 같은 도구를 사용하거나 사용할 계획이라면 주석을 사용하여 이 문제를 해결할 수 있습니다.

기본적으로 @Nullable@NotNull 있습니다.

다음과 같이 메서드 및 매개변수에서 사용할 수 있습니다.

 @NotNull public static String helloWorld() { return "Hello World"; }

또는

 @Nullable public static String helloWorld() { return "Hello World"; }

두 번째 예제는 IntelliJ IDEA에서 컴파일되지 않습니다.

다른 코드에서 helloWorld() 함수를 사용할 때:

 public static void main(String[] args) { String result = helloWorld(); if(result != null) { System.out.println(result); } }

helloWorld() null 반환하지 않기 때문에 검사가 쓸모없다고 알려줄 것입니다.

매개변수 사용

 void someMethod(@NotNull someParameter) { }

다음과 같이 작성하면

 someMethod(null);

컴파일되지 않습니다.

@Nullable 사용한 마지막 예

 @Nullable iWantToDestroyEverything() { return null; }

이렇게

 iWantToDestroyEverything().something();

그리고 당신은 이것이 일어나지 않을 것이라고 확신할 수 있습니다. :)

컴파일러가 일반적으로 수행하는 것보다 더 많은 것을 확인하고 계약을 더 강력하게 적용할 수 있는 좋은 방법입니다. 불행히도 모든 컴파일러에서 지원하는 것은 아닙니다.

IntelliJ IDEA 10.5 이상에서는 다른 @Nullable @NotNull 구현에 대한 지원을 추가했습니다.

더 유연하고 구성 가능한 @Nullable/@NotNull 주석 블로그 게시물을 참조하세요.



답변자 : Community Wiki


null 값이 허용되지 않는 경우

메서드가 외부에서 호출되는 경우 다음과 같이 시작합니다.

 public void method(Object object) { if (object == null) { throw new IllegalArgumentException("..."); }

그런 다음 해당 메서드의 나머지 부분에서 object 가 null이 아님을 알 수 있습니다.

API의 일부가 아닌 내부 메서드인 경우 null이 될 수 없음을 문서화하면 됩니다.

예시:

 public String getFirst3Chars(String text) { return text.subString(0, 3); }

그러나 메서드가 값을 전달하고 다음 메서드가 값을 전달하면 문제가 발생할 수 있습니다. 이 경우 위와 같이 인수를 확인할 수 있습니다.

null이 허용되는 경우

이것은 정말로 달려 있습니다. 내가 자주 다음과 같은 일을 하는 것을 발견하면:

 if (object == null) { // something } else { // something else }

그래서 저는 분기를 하고 완전히 다른 두 가지 일을 합니다. 데이터에 따라 두 가지 다른 작업을 수행해야 하기 때문에 추한 코드 조각이 없습니다. 예를 들어, 입력에 대해 작업해야 합니까, 아니면 좋은 기본값을 계산해야 합니까?


if (object != null && ... ") 관용구를 사용하는 경우는 드뭅니다.

일반적으로 관용구를 사용하는 위치에 대한 예를 보여주면 예를 제공하는 것이 더 쉬울 수 있습니다.



답변자 : Community Wiki


NullObject pattern 을 추천하는 57가지 다른 방법이 있을 때 다른 답변을 추가하는 것을 거의 싫어하지만, 이 질문에 관심이 있는 일부 사람들은 "null -안전 처리" —if -not-equal-null 논리를 위한 간소화된 구문입니다.

Alex Miller가 제공한 예는 다음과 같습니다.

 public String getPostcode(Person person) { return person?.getAddress()?.getPostcode(); }

?. 오직 디 레퍼런스가 널이 아닌 경우 좌측 식별자 수단은 그렇지 같은 식의 나머지 평가 null . Java Posse 회원인 Dick Wall과 Devoxx 의 유권자와 같은 일부 사람들은 이 제안을 정말 좋아하지만 실제로는 센티넬 값 null 을 더 많이 사용하도록 권장한다는 이유로 반대도 있습니다.


업데이트: Java 7의 null-safe 연산자에 대한 공식 제안 이 Project Coin에 제출되었습니다. 구문은 위의 예와 약간 다르지만 동일한 개념입니다.


업데이트: null-safe 연산자 제안이 프로젝트 코인에 포함되지 않았습니다. 따라서 Java 7에서는 이 구문을 볼 수 없습니다.



답변자 : Community Wiki


정의되지 않은 값이 허용되지 않는 경우:

잠재적인 null 역참조에 대해 경고하도록 IDE를 구성할 수 있습니다. 예를 들어 Eclipse에서 기본 설정 > Java > 컴파일러 > 오류/경고/널 분석을 참조하십시오 .

정의되지 않은 값이 허용되는 경우:

정의되지 않은 값이 의미가 있는 새 API를 정의 하려면 옵션 패턴을 사용하십시오(함수형 언어에 익숙할 수 있음). 다음과 같은 장점이 있습니다.

  • 입력 또는 출력의 존재 여부는 API에 명시적으로 명시되어 있습니다.
  • 컴파일러는 "정의되지 않은" 경우를 처리하도록 강제합니다.
  • Option 은 모나드 이므로 자세한 null 검사가 필요하지 않습니다. map/foreach/getOrElse 또는 유사한 조합기를 사용하여 값 (예제) 을 안전하게 사용하십시오.

Optional 클래스가 내장되어 있습니다(권장). 이전 버전의 경우 GuavaOptional 또는 FunctionalJavaOption 과 같은 대체 라이브러리가 있습니다. 그러나 많은 기능적 스타일 패턴과 마찬가지로 Java에서 Option을 사용하면(심지어 8개) Scala 또는 Xtend와 같은 덜 장황한 JVM 언어를 사용하여 줄일 수 있는 꽤 많은 상용구가 생깁니다.

null을 반환할 수 있는 API를 처리해야 하는 경우 Java에서는 많은 작업을 수행할 수 없습니다. Xtend와 Groovy에는 Elvis 연산자 ?:null-safe 역참조 연산자 ?. 그러나 이것은 null 참조의 경우 null을 반환하므로 null의 적절한 처리를 "지연"합니다.



답변자 : Community Wiki


이 상황에 대해서만 -

equals 메서드를 호출하기 전에 변수가 null인지 확인하지 않음(아래 문자열 비교 예):

 if ( foo.equals("bar") ) { // ... }

foo 가 존재하지 않으면 NullPointerException 이 발생합니다.

String 을 비교하면 이를 피할 수 있습니다.

 if ( "bar".equals(foo) ) { // ... }


답변자 : Community Wiki


Java 8에는 문제의 일부를 틀림없이 해결 java.util.Optional 적어도 코드의 가독성이 향상되고 공용 API의 경우 API의 계약이 클라이언트 개발자에게 더 명확해 진다고 말할 수 있습니다.

그들은 다음과 같이 작동합니다.

주어진 유형에 대한 선택적 객체( Fruit )는 메소드의 리턴 유형으로 생성됩니다. Fruit 개체를 포함할 수 있습니다.

 public static Optional<Fruit> find(String name, List<Fruit> fruits) { for (Fruit fruit : fruits) { if (fruit.getName().equals(name)) { return Optional.of(fruit); } } return Optional.empty(); }

이제 주어진 과일 인스턴스에 대한 Fruit ( fruits ) 목록을 검색하는 이 코드를 보십시오.

 Optional<Fruit> found = find("lemon", fruits); if (found.isPresent()) { Fruit fruit = found.get(); String name = fruit.getName(); }

map() 연산자를 사용하여 선택적 객체에서 계산을 수행하거나 값을 추출할 수 있습니다. orElse() 사용하면 누락된 값에 대한 대체를 제공할 수 있습니다.

 String nameOrNull = find("lemon", fruits) .map(f -> f.getName()) .orElse("empty-name");

물론 null/empty 값에 대한 확인은 여전히 필요하지만 적어도 개발자는 값이 비어 있을 수 있고 확인을 잊어버릴 위험이 제한적이라는 것을 알고 있습니다.

Optional 사용하여 처음부터 빌드되고 null 될 수 없는 경우에만 일반 개체를 반환하는 API(관례)에서 클라이언트 코드는 단순 개체 반환 값에 대한 null 검사를 포기할 수 있습니다...

물론 Optional 은 메서드 인수로 사용할 수도 있으며, 경우에 따라 5개 또는 10개의 오버로드 메서드보다 선택적 인수를 나타내는 더 좋은 방법일 수 있습니다.

Optional 은 기본값 사용을 허용하는 ifPresent 및 람다 식과 함께 작동 orElse 와 같은 다른 편리한 방법을 제공합니다.

NullPointerException (및 일반적으로 null 포인터) 문제와 Optional 이 가져온 (부분) 솔루션에 대해 잘 설명되어 있는 이 기사(이 답변을 작성하기 위한 주요 출처)를 읽어보시기 바랍니다 . Java Optional Objects .



답변자 : Community Wiki


검사하는 객체의 종류에 따라 apache commons langapache commons 컬렉션 과 같은 apache commons의 일부 클래스를 사용할 수 있습니다.

예시:

 String foo; ... if( StringUtils.isBlank( foo ) ) { ///do something }

또는 (확인해야 할 사항에 따라):

 String foo; ... if( StringUtils.isEmpty( foo ) ) { ///do something }

StringUtils 클래스는 많은 것 중 하나일 뿐입니다. null 안전 조작을 수행하는 꽤 좋은 클래스가 커먼즈에 있습니다.

다음은 Apache 라이브러리(commons-lang-2.4.jar)를 포함할 때 JAVA에서 null 유효성 검사를 사용하는 방법의 예입니다.

 public DOCUMENT read(String xml, ValidationEventHandler validationEventHandler) { Validate.notNull(validationEventHandler,"ValidationHandler not Injected"); return read(new StringReader(xml), true, validationEventHandler); }

그리고 Spring을 사용한다면 Spring도 패키지에 동일한 기능을 가지고 있습니다. library(spring-2.4.6.jar)를 참조하세요.

spring(org.springframework.util.Assert)에서 이 정적 classf를 사용하는 방법에 대한 예

 Assert.notNull(validationEventHandler,"ValidationHandler not Injected");


답변자 : Community Wiki


  • 객체가 null이 아니어야 한다고 생각하는 경우(또는 버그인 경우) assert를 사용하세요.
  • 메소드가 널 매개변수를 허용하지 않는 경우 javadoc에서 말하고 어설션을 사용하십시오.

객체가 null일 수 있는 경우를 처리하려는 경우에만 객체 != null을 확인해야 합니다...

null / notnull 매개변수를 지원하기 위해 Java7에 새 주석을 추가하는 제안이 있습니다. http://tech.puredanger.com/java7/#jsr308



답변자 : Community Wiki


저는 "빠른 실패" 코드의 팬입니다. 자신에게 물어보십시오. 매개변수가 null인 경우 유용한 작업을 수행하고 있습니까? 이 경우 코드가 수행해야 하는 작업에 대한 명확한 대답이 없는 경우... 즉, 처음부터 null이 아니어야 하며, 이를 무시하고 NullPointerException이 throw되도록 허용합니다. 호출 코드는 IllegalArgumentException만큼 NPE를 이해하지만, 개발자가 다른 예기치 않은 상황을 실행하려고 시도하는 것보다 NPE가 발생하면 무엇이 잘못되었는지 디버그하고 이해하는 것이 더 쉬울 것입니다. 논리 - 결국 응용 프로그램이 어쨌든 실패하게 됩니다.



답변자 : Community Wiki


용도가 있는 Null 개체 패턴 대신 null 개체가 버그인 상황을 고려할 수 있습니다.

예외가 발생하면 스택 추적을 검사하고 버그를 해결하십시오.



답변자 : Community Wiki


Google 컬렉션 프레임워크는 null 검사를 수행하는 훌륭하고 우아한 방법을 제공합니다.

라이브러리 클래스에는 다음과 같은 메소드가 있습니다.

 static <T> T checkNotNull(T e) { if (e == null) { throw new NullPointerException(); } return e; }

그리고 사용법은 ( import static ) 다음과 같습니다.

 ... void foo(int a, Person p) { if (checkNotNull(p).getAge() > a) { ... } else { ... } } ...

또는 귀하의 예에서 :

 checkNotNull(someobject).doCalc();


답변자 : Community Wiki


때로는 대칭 작업을 정의하는 매개변수에 대해 작동하는 메서드가 있습니다.

 af(b); <-> bf(a);

b가 결코 null이 될 수 없다는 것을 알고 있다면 그것을 바꿀 수 있습니다. equals에 가장 유용합니다. foo.equals("bar"); "bar".equals(foo); .



답변자 : Community Wiki


Null은 '문제'가 아닙니다. 이것은 완전한 모델링 도구 세트의 필수적인 부분입니다. 소프트웨어는 세상의 복잡성을 모델링하는 것을 목표로 하며 null은 그 부담을 부담합니다. Null은 Java 등에서 '데이터 없음' 또는 '알 수 없음'을 나타냅니다. 따라서 이러한 목적으로 null을 사용하는 것이 적절합니다. 나는 'Null object' 패턴을 선호하지 않는다. '수호자를 누가 지킨다 '는 문제가 대두되는 것 같아요.
내 여자 친구의 이름이 뭐냐고 묻는다면 나는 여자 친구가 없다고 대답할 것이다. Java 언어에서는 null을 반환합니다. 대안은 바로 해결할 수 없는(또는 해결하고 싶지 않은) 일부 문제를 나타내기 위해 의미 있는 예외를 throw하고 스택의 상위 위치에 위임하여 재시도하거나 데이터 액세스 오류를 사용자에게 보고하는 것입니다.

  1. '알 수 없는 질문'의 경우 '알 수 없는 답변'을 입력하세요. (비즈니스 관점에서 이것이 올바른 경우 null 안전) 사용하기 전에 메서드 내에서 null 인수를 한 번 확인하면 여러 호출자가 호출 전에 인수를 확인하지 않아도 됩니다.

     public Photo getPhotoOfThePerson(Person person) { if (person == null) return null; // Grabbing some resources or intensive calculation // using person object anyhow. }

    이전은 내 사진 라이브러리에서 존재하지 않는 여자 친구의 사진을 가져오지 않는 정상적인 논리 흐름으로 이어집니다.

     getPhotoOfThePerson(me.getGirlfriend())

    그리고 그것은 새로운 Java API에 적합합니다(앞으로)

     getPhotoByName(me.getGirlfriend()?.getName())

    누군가를 위해 DB에 저장된 사진을 찾지 않는 것이 오히려 '일반적인 비즈니스 흐름'이지만 다른 경우에는 아래와 같은 쌍을 사용했습니다.

     public static MyEnum parseMyEnum(String value); // throws IllegalArgumentException public static MyEnum parseMyEnumOrNull(String value);

    <alt> + <shift> + <j> (Eclipse에서 javadoc 생성)를 입력하고 공개 API에 대해 세 단어를 추가로 작성하는 것을 싫어하지 마십시오. 이것은 문서를 읽지 않는 사람들을 제외한 모든 사람들에게 충분할 것입니다.

     /** * @return photo or null */

    또는

     /** * @return photo, never null */
  2. 이것은 다소 이론적 인 경우이며 대부분의 경우 Java null safe API를 선호해야하지만 (10 년 후에 릴리스 될 경우) NullPointerException Exception 하위 클래스입니다. 따라서 합리적인 응용 프로그램이 포착하려는 조건을 나타내는 Throwable 형식입니다 ( javadoc )! 예외의 첫 번째 장점을 사용하고 '일반' 코드에서 오류 처리 코드를 분리하려면( Java 작성자에 NullPointerException 을 잡는 것이 적절합니다.

     public Photo getGirlfriendPhoto() { try { return appContext.getPhotoDataSource().getPhotoByName(me.getGirlfriend().getName()); } catch (NullPointerException e) { return null; } }

    다음과 같은 질문이 발생할 수 있습니다.

    getPhotoDataSource() 가 null을 반환하면 어떻게 됩니까?
    A. 비즈니스 로직에 달려 있습니다. 사진 앨범을 찾지 못하면 사진을 표시하지 않겠습니다. appContext가 초기화되지 않으면 어떻게 됩니까? 이 방법의 비즈니스 논리가 이를 견뎌냅니다. 동일한 논리가 더 엄격해야 예외가 발생하는 경우 이는 비즈니스 논리의 일부이며 null에 대한 명시적 검사를 사용해야 합니다(사례 3). 새로운 Java Null-safe API는 프로그래머 오류의 경우 페일-패스트 로 초기화되는 것을 의미하고 의미하지 않는 것을 선택적으로 지정하는 데 더 적합합니다.

    Q. 중복 코드가 실행되어 불필요한 리소스를 잡아먹을 수 있습니다.
    getPhotoByName() 이 데이터베이스 연결을 열고 PreparedStatement 생성하고 사람 이름을 SQL 매개변수로 마지막에 사용하려고 하면 발생할 수 있습니다. 알 수 없는 질문에 대한 접근 방식 은 알 수 없는 답변을 제공합니다 (사례 1). 리소스를 가져오기 전에 메서드는 매개변수를 확인하고 필요한 경우 '알 수 없는' 결과를 반환해야 합니다.

    Q. 이 접근 방식은 try 클로저 열기로 인해 성능이 저하됩니다.
    A. 소프트웨어는 먼저 이해하기 쉽고 수정하기 쉬워야 합니다. 이 후에야 성능에 대해 생각할 수 있으며 필요한 경우에만! 그리고 필요한 곳에! ( 출처 ) 및 기타 여러 가지).

    추신. 이 접근 방식은 "일반" 코드 원칙에서 분리된 오류 처리 코드 가 어떤 곳에서 사용하기에 합당한 만큼 사용하기에 합당합니다. 다음 예를 고려하십시오.

     public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) { try { Result1 result1 = performSomeCalculation(predicate); Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty()); Result3 result3 = performThirdCalculation(result2.getSomeProperty()); Result4 result4 = performLastCalculation(result3.getSomeProperty()); return result4.getSomeProperty(); } catch (NullPointerException e) { return null; } } public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) { SomeValue result = null; if (predicate != null) { Result1 result1 = performSomeCalculation(predicate); if (result1 != null && result1.getSomeProperty() != null) { Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty()); if (result2 != null && result2.getSomeProperty() != null) { Result3 result3 = performThirdCalculation(result2.getSomeProperty()); if (result3 != null && result3.getSomeProperty() != null) { Result4 result4 = performLastCalculation(result3.getSomeProperty()); if (result4 != null) { result = result4.getSomeProperty(); } } } } } return result; }

    PPS. 다운보팅이 빠른 사람들(그리고 문서를 읽는 속도가 그리 빠르지 않은 사람들)을 위해 저는 제 인생에서 널 포인터 예외(NPE)를 만난 적이 없다고 말하고 싶습니다. 그러나 이 가능성은 Exception 의 하위 클래스이기 때문에 Java 작성자 가 의도적으로 설계 한 것입니다. Java 역사에서 ThreadDeathError 경우 실제로 응용 프로그램 오류가 아니라 단지 catch할 의도가 없었기 때문에 발생하는 선례가 있습니다! 얼마나 많은 NPE가 ThreadDeath Error 적합합니까! 하지만 그렇지 않습니다.

  3. 비즈니스 로직이 암시하는 경우에만 '데이터 없음'을 확인하십시오.

     public void updatePersonPhoneNumber(Long personId, String phoneNumber) { if (personId == null) return; DataSource dataSource = appContext.getStuffDataSource(); Person person = dataSource.getPersonById(personId); if (person != null) { person.setPhoneNumber(phoneNumber); dataSource.updatePerson(person); } else { Person = new Person(personId); person.setPhoneNumber(phoneNumber); dataSource.insertPerson(person); } }

    그리고

     public void updatePersonPhoneNumber(Long personId, String phoneNumber) { if (personId == null) return; DataSource dataSource = appContext.getStuffDataSource(); Person person = dataSource.getPersonById(personId); if (person == null) throw new SomeReasonableUserException("What are you thinking about ???"); person.setPhoneNumber(phoneNumber); dataSource.updatePerson(person); }

    appContext 또는 dataSource가 초기화되지 않은 경우 처리되지 않은 런타임 NullPointerException은 현재 스레드를 종료하고 Thread.defaultUncaughtExceptionHandler에 의해 처리됩니다(좋아하는 로거 또는 기타 알림 메커니즘을 정의하고 사용하기 위해). 설정하지 않으면 ThreadGroup#uncaughtException 은 시스템 오류에 스택 추적을 인쇄합니다. 애플리케이션 오류 로그를 모니터링하고 실제로 애플리케이션 오류인 처리되지 않은 각 예외에 대해 Jira 문제를 열어야 합니다. 프로그래머는 초기화 항목의 어딘가에서 버그를 수정해야 합니다.



답변자 : Community Wiki


Java 7에는 requireNonNull() java.util.Objects 유틸리티 클래스가 있습니다. 이 모든 작업은 NullPointerException throw하지만 코드를 약간 정리합니다. 예시:

 Objects.requireNonNull(someObject); someObject.doCalc();

이 방법은 생성자에서 할당 직전에 확인하는 데 가장 유용하며, 이를 사용할 때마다 세 줄의 코드를 저장할 수 있습니다.

 Parent(Child child) { if (child == null) { throw new NullPointerException("child"); } this.child = child; }

된다

 Parent(Child child) { this.child = Objects.requireNonNull(child, "child"); }


답변자 : Community Wiki


궁극적으로 이 문제를 완전히 해결하는 유일한 방법은 다른 프로그래밍 언어를 사용하는 것입니다.

  • nil 대한 메서드를 호출하는 것과 동일한 작업을 수행할 수 있으며 절대 아무 일도 일어나지 않습니다. 이렇게 하면 대부분의 null 검사가 필요하지 않지만 오류를 진단하기가 훨씬 더 어려워질 수 있습니다.
  • Java 파생 언어인 Nice 에는 모든 유형의 두 가지 버전, 즉 잠재적으로 널 버전과 널이 아닌 버전이 있습니다. null이 아닌 형식에서만 메서드를 호출할 수 있습니다. null 가능성이 있는 형식은 null에 대한 명시적 검사를 통해 null이 아닌 형식으로 변환할 수 있습니다. 이렇게 하면 null 검사가 필요한 곳과 그렇지 않은 곳을 훨씬 쉽게 알 수 있습니다.


답변자 : Community Wiki


실제로 Java의 일반적인 "문제"입니다.

먼저 이에 대한 제 생각은 다음과 같습니다.

NULL이 유효한 값이 아닌 곳에 NULL이 전달되었을 때 무언가를 "먹는" 것은 나쁘다고 생각합니다. 어떤 종류의 오류로 메소드를 종료하지 않는다면 이는 사실이 아닌 메소드에 아무 문제가 없다는 것을 의미합니다. 그런 다음이 경우 null을 반환하고 수신 방법에서 null을 다시 확인하고 끝나지 않고 "if != null"등으로 끝납니다.

따라서 IMHO, null은 추가 실행을 방지하는 심각한 오류여야 합니다(즉, null이 유효한 값이 아닌 경우).

이 문제를 해결하는 방법은 다음과 같습니다.

먼저 다음 규칙을 따릅니다.

  1. 모든 공개 메서드/API는 항상 null에 대한 인수를 확인합니다.
  2. 모든 개인 메서드는 제어되는 메서드이기 때문에 null을 확인하지 않습니다(위에서 처리되지 않은 경우 nullpointer 예외로 죽게 두십시오).
  3. null을 확인하지 않는 유일한 다른 메소드는 유틸리티 메소드입니다. 그들은 공개되어 있지만 어떤 이유로 호출하면 전달하는 매개 변수를 알 수 있습니다. 이것은 물을 제공하지 않고 주전자에 물을 끓이려고 하는 것과 같습니다...

마지막으로 코드에서 public 메서드의 첫 번째 줄은 다음과 같습니다.

 ValidationUtils.getNullValidator().addParam(plans, "plans").addParam(persons, "persons").validate();

addParam()은 self를 반환하므로 확인할 매개변수를 더 추가할 수 있습니다.

validate() 메서드는 확인된 ValidationException 을 throw합니다(선택 또는 선택하지 않은 것은 디자인/맛 문제에 더 가깝지만 내 ValidationException 이 확인됨).

 void validate() throws ValidationException;

예를 들어 "plans"가 null인 경우 메시지에는 다음 텍스트가 포함됩니다.

" 매개변수 [계획]에 대해 잘못된 인수 값 null이 발견되었습니다. "

보시다시피 addParam() 메서드(문자열)의 두 번째 값은 사용자 메시지에 필요합니다. 왜냐하면 리플렉션을 사용하더라도 전달된 변수 이름을 쉽게 감지할 수 없기 때문입니다(어쨌든 이 게시물의 주제가 아닙니다...).

그리고 예, 우리는 이 줄을 넘어서는 더 이상 null 값을 만나지 않을 것이라는 것을 알고 있으므로 해당 객체에 대한 메서드를 안전하게 호출합니다.

이렇게 하면 코드가 깨끗하고 유지 관리가 쉽고 읽기 쉽습니다.



답변자 : Community Wiki


이 질문을 하면 오류 처리 전략에 관심이 있을 수 있음을 알 수 있습니다. 오류를 처리하는 방법과 위치는 만연한 아키텍처 문제입니다. 이를 수행하는 방법에는 여러 가지가 있습니다.

내가 가장 좋아하는 것: 예외가 계속 퍼지도록 허용 - '메인 루프' 또는 적절한 책임이 있는 다른 기능에서 예외를 포착합니다. 오류 상태를 확인하고 적절하게 처리하는 것은 전문적인 책임으로 볼 수 있습니다.

물론 Aspect Oriented Programming도 살펴보십시오. 바이트 코드에 if( o == null ) handleNull()



답변자 : Community Wiki


assert 를 사용하는 것 외에도 다음을 사용할 수 있습니다.

 if (someobject == null) { // Handle null here then move on. }

이것은 다음보다 약간 낫습니다.

 if (someobject != null) { ..... ..... ..... }


답변자 : Community Wiki


null을 사용하지 마십시오. 허용하지 마세요.

내 클래스에서 대부분의 필드와 지역 변수에는 null이 아닌 기본값이 있으며 코드의 모든 곳에 계약 문(항상 켜짐 어설션)을 추가하여 이것이 적용되고 있는지 확인합니다(허용하는 것보다 더 간결하고 표현력이 높기 때문에 NPE로 나온 다음 줄 번호를 확인해야 하는 등).

이 관행을 채택하고 나면 문제가 저절로 해결되는 것처럼 보였습니다. 개발 프로세스의 훨씬 더 이른 단계에서 우연히 발견하고 약점이 있다는 것을 깨닫게 될 것입니다. 그리고 더 중요한 것은 .. 다른 모듈의 관심사를 캡슐화하는 데 도움이 됩니다. 다른 모듈은 서로 '신뢰'할 수 있으며 더 이상 쓰레기를 버리지 않습니다. if = null else 구문이 있는 코드!

이것은 방어적 프로그래밍이며 장기적으로 훨씬 더 깨끗한 코드를 생성합니다. 예를 들어 엄격한 표준을 적용하여 항상 데이터를 삭제하면 문제가 사라집니다.

 class C { private final MyType mustBeSet; public C(MyType mything) { mustBeSet=Contract.notNull(mything); } private String name = "<unknown>"; public void setName(String s) { name = Contract.notNull(s); } } class Contract { public static <T> T notNull(T t) { if (t == null) { throw new ContractException("argument must be non-null"); return t; } }

계약은 프로덕션 환경에서도 항상 실행되는 미니 단위 테스트와 같으며 일이 실패하면 임의의 NPE가 아니라 어떻게든 알아내야 하는 이유를 알 수 있습니다.



답변자 : Community Wiki


Google의 매우 유용한 핵심 라이브러리인 Guava에는 null을 방지하는 훌륭하고 유용한 API가 있습니다. UsingAndAvoidingNullExplained가 매우 도움이 됩니다.

위키에 설명된 대로:

Optional<T> 는 nullable T 참조를 null이 아닌 값으로 바꾸는 방법입니다. Optional은 null이 아닌 T 참조(이 경우 참조가 "존재"라고 함)를 포함하거나 아무 것도 포함하지 않을 수 있습니다(이 경우 참조가 "부재"라고 함). "null을 포함"한다고 말하지 않습니다.

용법:

 Optional<Integer> possible = Optional.of(5); possible.isPresent(); // returns true possible.get(); // returns 5


답변자 : Community Wiki


이것은 모든 Java 개발자에게 매우 일반적인 문제입니다. 따라서 복잡한 코드 없이 이러한 문제를 해결하기 위한 Java 8의 공식 지원이 있습니다.

Java 8은 java.util.Optional<T> 도입했습니다. null이 아닌 값을 보유하거나 보유하지 않을 수 있는 컨테이너입니다. Java 8은 경우에 따라 값이 null일 수 있는 객체를 처리하는 더 안전한 방법을 제공했습니다. HaskellScala 의 아이디어에서 영감을 받았습니다.

간단히 말해서 Optional 클래스에는 값이 있거나 없는 경우를 명시적으로 처리하는 메서드가 포함되어 있습니다. 그러나 null 참조에 비해 이점은 Optional<T> 클래스를 사용하면 값이 없는 경우에 대해 생각해야 한다는 것입니다. 결과적으로 의도하지 않은 널 포인터 예외를 방지할 수 있습니다.

위의 예에는 가정에서 사용할 수 있는 여러 기기에 대한 핸들을 반환하는 홈 서비스 팩토리가 있습니다. 그러나 이러한 서비스는 사용 가능하거나 작동하지 않을 수 있습니다. NullPointerException이 발생할 수 있음을 의미합니다. if 조건을 추가하는 대신 Optional<Service>로 래핑해 보겠습니다.

옵션<T>에 래핑

공장에서 서비스에 대한 참조를 얻는 방법을 생각해 봅시다. 서비스 참조를 반환하는 대신 Optional로 래핑합니다. API 사용자는 반환된 서비스가 사용 가능하거나 작동하지 않을 수 있음을 알리고 방어적으로 사용합니다.

 public Optional<Service> getRefrigertorControl() { Service s = new RefrigeratorService(); //... return Optional.ofNullable(s); }

보시다시피 Optional.ofNullable() 은 참조를 래핑하는 쉬운 방법을 제공합니다. Optional.empty()Optional.of() 의 참조를 얻는 또 다른 방법이 있습니다. 하나는 null을 반환하는 대신 빈 개체를 반환하고 다른 하나는 nullable이 아닌 개체를 래핑하기 위한 것입니다.

그렇다면 NULL 체크를 피하는 데 정확히 얼마나 도움이 될까요?

참조 개체를 래핑하면 Optional은 NPE 없이 래핑된 참조에서 메서드를 호출하는 데 유용한 여러 메서드를 제공합니다.

 Optional ref = homeServices.getRefrigertorControl(); ref.ifPresent(HomeServices::switchItOn);

Optional.ifPresent는 null이 아닌 값인 경우 참조와 함께 지정된 소비자를 호출합니다. 그렇지 않으면 아무 작업도 수행하지 않습니다.

 @FunctionalInterface public interface Consumer<T>

단일 입력 인수를 받아들이고 결과를 반환하지 않는 작업을 나타냅니다. 대부분의 다른 기능적 인터페이스와 달리 소비자는 부작용을 통해 작동할 것으로 예상됩니다. 너무 깨끗하고 이해하기 쉽습니다. 위의 코드 예제에서 Optional 보유 참조가 null이 아닌 경우 HomeService.switchOn(Service)

우리는 null 조건을 확인하고 대체 값이나 기본값을 반환하기 위해 삼항 연산자를 매우 자주 사용합니다. 선택 사항은 null을 확인하지 않고 동일한 조건을 처리하는 또 다른 방법을 제공합니다. Optional.orElse(defaultObj)는 Optional에 null 값이 있는 경우 defaultObj를 반환합니다. 샘플 코드에서 이것을 사용합시다.

 public static Optional<HomeServices> get() { service = Optional.of(service.orElse(new HomeServices())); return service; }

이제 HomeServices.get()은 같은 일을 하지만 더 나은 방식으로 수행합니다. 서비스가 이미 초기화되어 있지 않은지 확인합니다. 그렇다면 동일하게 반환하거나 새 새 서비스를 만듭니다. Optional<T>.orElse(T)는 기본값을 반환하는 데 도움이 됩니다.

마지막으로 NPE와 null 체크 프리 코드가 있습니다.

 import java.util.Optional; public class HomeServices { private static final int NOW = 0; private static Optional<HomeServices> service; public static Optional<HomeServices> get() { service = Optional.of(service.orElse(new HomeServices())); return service; } public Optional<Service> getRefrigertorControl() { Service s = new RefrigeratorService(); //... return Optional.ofNullable(s); } public static void main(String[] args) { /* Get Home Services handle */ Optional<HomeServices> homeServices = HomeServices.get(); if(homeServices != null) { Optional<Service> refrigertorControl = homeServices.get().getRefrigertorControl(); refrigertorControl.ifPresent(HomeServices::switchItOn); } } public static void switchItOn(Service s){ //... } }

전체 게시물은 NPE뿐만 아니라 Null 체크 프리 코드 ... 정말? .



답변자 : Community Wiki


나는 Nat Pryce의 기사를 좋아합니다. 링크는 다음과 같습니다.

기사에는 흥미로운 Java Maybe Type용 Git 리포지토리에 대한 링크도 있지만 그것만으로는 검사 코드 팽창을 줄일 수 있다고 생각하지 않습니다. 인터넷에서 약간의 조사를 한 후에 != 널 코드 팽창은 주로 신중한 설계에 의해 감소될 수 있다고 생각합니다.



답변자 : Community Wiki


나는 NullObjectPattern 시도했지만 나에게 항상 최선의 방법은 아닙니다. "조치 없음"이 적절하지 않은 경우가 있습니다.

NullPointerException런타임 예외로 개발자의 잘못이며 충분한 경험을 통해 오류가 발생한 위치를 정확히 알려줍니다.

이제 답변으로:

모든 속성과 해당 접근자를 가능한 한 비공개로 만들거나 클라이언트에게 전혀 노출하지 않도록 하세요. 물론 생성자에 인수 값을 가질 수 있지만 범위를 줄임으로써 클라이언트 클래스가 잘못된 값을 전달하지 못하게 할 수 있습니다. 값을 수정해야 하는 경우 언제든지 새 object 만들 수 있습니다. 생성자의 값을 한 번만 확인 하고 나머지 메서드에서는 값이 null이 아님을 거의 확신할 수 있습니다.

물론 경험이 이 제안을 이해하고 적용하는 더 좋은 방법입니다.

바이트!



답변자 : Community Wiki


아마도 Java 8 이상에 대한 가장 좋은 대안은 Optional 클래스를 사용하는 것입니다.

 Optional stringToUse = Optional.of("optional is there"); stringToUse.ifPresent(System.out::println);

이것은 가능한 null 값의 긴 체인에 특히 유용합니다. 예시:

 Optional<Integer> i = Optional.ofNullable(wsObject.getFoo()) .map(f -> f.getBar()) .map(b -> b.getBaz()) .map(b -> b.getInt());

null에서 예외를 throw하는 방법에 대한 예:

 Optional optionalCarNull = Optional.ofNullable(someNull); optionalCarNull.orElseThrow(IllegalStateException::new);

Java 7에서는 null이 아닌지 확인해야 할 때 편리할 수 있는 Objects.requireNonNull 예시:

 String lowerVal = Objects.requireNonNull(someVar, "input cannot be null or empty").toLowerCase();


답변자 : Community Wiki


더 일반적으로 대답 할 수 있습니다!

우리는 일반적으로 메서드가 우리가 예상하지 못한 방식으로 매개변수를 얻을 때 이 문제에 직면합니다(나쁜 메서드 호출은 프로그래머의 잘못입니다). 예를 들어: 객체를 얻을 것으로 예상하고 대신 null을 얻습니다. 하나 이상의 문자가 포함된 문자열을 얻을 것으로 예상하는 대신 빈 문자열을 얻습니다.

따라서 다음과 같은 차이점이 없습니다.

 if(object == null){ //you called my method badly!

}

또는

 if(str.length() == 0){ //you called my method badly again! }

둘 다 다른 기능을 수행하기 전에 유효한 매개변수를 수신했는지 확인하기를 원합니다.

다른 답변에서 언급했듯이 위의 문제를 피하기 위해 Design by Contract 패턴을 따를 수 있습니다. http://en.wikipedia.org/wiki/Design_by_contract 를 참조하십시오.

Java에서 이 패턴을 구현하려면 javax.annotation.NotNull 과 같은 핵심 Java 주석을 사용하거나 Hibernate Validator 와 같은 보다 정교한 라이브러리를 사용할 수 있습니다.

샘플:

 getCustomerAccounts(@NotEmpty String customerId,@Size(min = 1) String accountType)

이제 입력 매개변수를 확인할 필요 없이 분석법의 핵심 기능을 안전하게 개발할 수 있으며 예상치 못한 매개변수로부터 분석법을 보호합니다.

한 단계 더 나아가 애플리케이션에서 유효한 pojo만 생성할 수 있는지 확인할 수 있습니다. (하이버네이트 검증 사이트의 샘플)

 public class Car { @NotNull private String manufacturer; @NotNull @Size(min = 2, max = 14) private String licensePlate; @Min(2) private int seatCount; // ... }


답변자 : Community Wiki


나는 모든 상황에서 null 객체를 사용하도록 제안하는 답변을 매우 무시합니다. 이 패턴은 계약을 깨고 문제를 해결하는 대신 점점 더 깊이 묻을 수 있습니다. 부적절하게 사용하면 향후 유지 관리가 필요한 또 다른 상용구 코드 더미가 생성된다는 점은 언급하지 않습니다.

실제로 메서드에서 반환된 것이 null일 수 있고 호출 코드가 이에 대해 결정을 내려야 하는 경우 상태를 보장하는 이전 호출이 있어야 합니다.

또한 신경 쓰지 않고 사용하면 null 객체 패턴이 메모리가 부족하다는 점을 명심하십시오. 이를 위해 - NullObject의 인스턴스는 소유자 간에 공유되어야 하며 이들 각각에 대한 고유한 인스턴스가 아니어야 합니다.

또한 스칼라가 아닌 수학적 엔티티와 같이 유형이 기본 유형 표현이어야 하는 경우 이 패턴을 사용하지 않는 것이 좋습니다. 벡터, 행렬, 복소수 및 상태를 유지하기 위한 POD(Plain Old Data) 객체 Java 내장 유형의 형태로. 후자의 경우 임의의 결과로 getter 메서드를 호출하게 됩니다. 예를 들어 NullPerson.getName() 메서드는 무엇을 반환해야 합니까?

터무니없는 결과를 피하기 위해 그러한 경우를 고려해 볼 가치가 있습니다.



답변자 : Community Wiki


  1. 변수를 null로 초기화하지 마십시오.
  2. (1)이 불가능하면 모든 컬렉션과 배열을 빈 컬렉션/배열로 초기화합니다.

자신의 코드에서 이 작업을 수행하면 != null 검사를 피할 수 있습니다.

대부분의 경우 null 검사는 컬렉션이나 배열에 대한 루프를 보호하는 것 같으므로 빈 상태로 초기화하면 null 검사가 필요하지 않습니다.

 // Bad ArrayList<String> lemmings; String[] names; void checkLemmings() { if (lemmings != null) for(lemming: lemmings) { // do something } } // Good ArrayList<String> lemmings = new ArrayList<String>(); String[] names = {}; void checkLemmings() { for(lemming: lemmings) { // do something } }

여기에는 약간의 오버헤드가 있지만 더 깨끗한 코드와 더 적은 NullPointerExceptions에 대해서는 그만한 가치가 있습니다.



답변자 : Community Wiki


이것은 대부분의 개발자에게 발생하는 가장 일반적인 오류입니다.

이를 처리할 수 있는 여러 가지 방법이 있습니다.

접근 방식 1:

 org.apache.commons.lang.Validate //using apache framework

notNull(객체 객체, 문자열 메시지)

접근 방식 2:

 if(someObject!=null){ // simply checking against null }

접근 방식 3:

 @isNull @Nullable // using annotation based validation

접근 방식 4:

 // by writing static method and calling it across whereever we needed to check the validation static <T> T isNull(someObject e){ if(e == null){ throw new NullPointerException(); } return e; }


답변자 : Community Wiki


진술을 피하기 위해 전체적으로

 if (object != null) { .... }
  1. Java 7부터 Objects 메소드를 사용할 수 있습니다.

    Objects.isNull(객체)

    Objects.nonNull(객체)

    Objects.requireNonNull(객체)

    Objects.equals(object1, object2)

  2. Java 8부터 선택적 클래스를 사용할 수 있습니다( 사용 시기 )

object.ifPresent(obj -> ...); 자바 8

object.ifPresentOrElse(obj -> ..., () -> ...); 자바 9

  1. 메서드 계약( JSR 305 ) 에 의존하고 버그 찾기를 사용합니다. @javax.annotation.Nullable@javax.annotation.Nonnnul 주석으로 코드를 표시합니다. 또한 전제 조건을 사용할 수 있습니다.

    전제 조건.checkNotNull(객체);

  2. 특별한 경우(예: 문자열 및 컬렉션) apache-commons(또는 Google 구아바) 유틸리티 메서드를 사용할 수 있습니다.

공개 정적 부울 isEmpty(CharSequence cs) // 아파치 CollectionUtils

public static boolean isEmpty(Collection coll) // 아파치 StringUtils

public static boolean isEmpty(지도 지도) // 아파치 MapUtils

공개 정적 부울 isNullOrEmpty(@Nullable 문자열 문자열) // 구아바 문자열

  1. null이 apache commons lang을 사용할 때 기본값을 할당해야 할 때

public static Object defaultIfNull(객체 객체, 객체 defaultValue)



출처 : Here


출처 : http:www.stackoverflow.com/questions/271526/avoiding-nullpointerexception-in-java">

반응형