문제

나는 사용한다 object != null 피해야 할 것이 많다 NullPointerException.

이것에 대한 좋은 대안이 있습니까?

예를 들어:

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

이는 다음을 방지합니다. NullPointerException, 객체가 무엇인지 알 수 없는 경우 null 아니면.

허용되는 답변이 최신이 아닐 수 있습니다. https://stackoverflow.com/a/2386013/12943 보다 최근의 접근 방식을 위해.

도움이 되었습니까?

해결책

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

다르게 말하면 null 검사가 발생하는 두 가지 경우가 있습니다.

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

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

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

assert <condition>

또는

assert <condition> : <object>

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

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을 반환하지 않고 대신 다음을 사용하는 것입니다. 널 객체 패턴:

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() 메소드가 의미 있는 오류 메시지와 함께 Exception을 발생시키는 것이 아마도 전적으로 적절할 것입니다. 특히 사용자 입력에 의존하는 이 경우에는 더욱 그렇습니다.설명 없이 간단한 NullPointerException을 발생시키는 호출 메소드보다 findAction 메소드가 예외를 발생시키는 것이 훨씬 더 좋습니다.

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

또는 try/catch 메커니즘이 너무 추악하다고 생각되면 아무것도 하지 않는 대신 기본 작업이 사용자에게 피드백을 제공해야 합니다.

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);
        }
    }
}

다른 팁

Java Ide를 사용하거나 사용하려는 경우 Jetbrains Intellij 아이디어, 또는 Netbeans 또는 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);
    }
}

이제 Intellij 아이디어 컴파일러는 수표가 쓸모가 없다고 말할 것입니다. helloWorld() 기능은 반환되지 않습니다 null, 항상.

매개 변수 사용

void someMethod(@NotNull someParameter) { }

다음과 같은 글을 쓰면

someMethod(null);

이것은 컴파일하지 않습니다.

마지막 예제 사용 @Nullable

@Nullable iWantToDestroyEverything() { return null; }

이것을하고 있습니다

iWantToDestroyEverything().something();

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

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

Intellij Idea 10.5에서 그들은 다른 어떤 것에 대한 지원을 추가했습니다. @Nullable @NotNull 구현.

블로그 게시물을 참조하십시오 보다 유연하고 구성 가능한 @nullable/ @notnull 주석.

널 값이 허용되지 않는 경우

메소드가 외부로 호출되면 다음과 같은 것으로 시작하십시오.

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

그러면 그 방법의 나머지 부분에서는 object 무효가 아닙니다.

그것이 내부 방법 (API의 일부가 아닌)이라면 널가 될 수 없다는 것을 문서화하십시오.

예시:

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

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

NULL이 허용되는 경우

이것은 정말로 달려 있습니다. 내가 종종 다음과 같은 일을한다면 :

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

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


실제로 관용구를 사용하는 것은 드문 일입니다. "if (object != null && ...".

일반적으로 관용구를 사용하는 위치의 예를 표시하면 예제를 제공하는 것이 더 쉬울 수 있습니다.

와우, 나는 우리가 57 가지 다른 방법을 추천 할 때 다른 대답을 추가하는 것을 거의 싫어합니다. NullObject pattern, 그러나이 질문에 관심이있는 사람들은 Java 7이 추가 할 제안이 있다는 것을 알고 싶어 할 것입니다. "널 안전 처리"-if-not-null logic의 간소화 된 구문.

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

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

그만큼 ?. 왼쪽 식별자가 null이 아닌 경우 왼쪽 식별자 만 제거하는 것을 의미합니다. 그렇지 않으면 표현식의 나머지 부분을 다음과 같이 평가합니다. null. Java Posse 회원 Dick Wall 및 Devoxx의 유권자 이 제안을 정말 좋아하지만 실제로 더 많은 사용을 장려 할 것이라는 근거로 야당도 있습니다. null 센티넬 가치로.


업데이트: an 공식 제안 Java 7의 Null-Safe 운영자는 아래에서 제출되었습니다. 프로젝트 코인. 구문은 위의 예와 약간 다르지만 같은 개념입니다.


업데이트: Null-Safe 운영자 제안은 프로젝트 코인으로 만들지 않았습니다. 따라서 Java 7 에서이 구문을 보지 못할 것입니다.

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

잠재적 인 널 dereferencing에 대해 경고하기 위해 IDE를 구성 할 수 있습니다. 예 : 일식에서 기본 설정> Java> 컴파일러> 오류/경고/널 분석.

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

정의되지 않은 값이 이해되는 새 API를 정의하려면, 사용 옵션 패턴 (기능적 언어에 익숙 할 수 있습니다). 다음과 같은 장점이 있습니다.

  • 입력 또는 출력이 존재하는지 여부는 API에 명시 적으로 명시되어 있습니다.
  • 컴파일러는 "정의되지 않은"케이스를 처리하도록 강요합니다.
  • 옵션은 모나드입니다, 따라서 Verbose Null Checking이 필요하지 않습니다. Map/Foreach/Getorelse 또는 유사한 조합을 사용하여 값을 안전하게 사용하십시오. (예시).

Java 8에는 내장되어 있습니다 Optional 수업 (추천); 이전 버전의 경우 라이브러리 대안이 있습니다. 구아바'에스 Optional 또는 기능적 자바'에스 Option. 그러나 많은 기능 스타일 패턴과 마찬가지로 Java (8)로 옵션을 사용하면 상당히 상용구가 발생하여 덜 장황한 JVM 언어, 예를 들어 Scala 또는 Xtend를 사용하여 줄일 수 있습니다.

Nulls를 반환 할 수있는 API를 처리 해야하는 경우, 당신은 Java에서는 많이 할 수 없습니다. Xtend와 Groovy가 있습니다 엘비스 운영자 ?: 그리고 NULL-SAFE DEREFERENCE 연산자 ?., 그러나 이것은 NULL 참조의 경우 NULL을 반환하므로 NULL의 적절한 처리를 "DEFER"합니다.

이 상황에 대해서만 -

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

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

a NullPointerException 만약에 foo 존재하지 않습니다.

비교하면 피할 수 있습니다 StringS처럼 :

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

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) 특정 Fruit 인스턴스에 대해:

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/빈 값에 대한 확인은 여전히 ​​필요하지만 적어도 개발자는 값이 비어 있을 수 있고 확인을 잊어버릴 위험이 제한적이라는 점을 인식하고 있습니다.

다음을 사용하여 처음부터 구축된 API에서 Optional 반환 값이 비어 있을 수 있을 때마다, 비어 있을 수 없는 경우에만 일반 객체를 반환합니다. null (관습) 클라이언트 코드는 단순 객체 반환 값에 대한 null 검사를 포기할 수 있습니다.

물론 Optional 메소드 인수로 사용될 수도 있습니다. 어떤 경우에는 5개 또는 10개의 오버로딩 메소드보다 선택적 인수를 나타내는 더 나은 방법일 수 있습니다.

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

이 기사(이 답변을 작성하는 주요 출처)를 읽어보시기 바랍니다. NullPointerException (그리고 일반적으로 널 포인터) 문제가 있을 뿐만 아니라 (부분) 해결책도 있습니다. Optional 잘 설명되어 있습니다 : Java 선택적 개체.

어떤 종류의 물체에 따라, 당신이 당신이 당신이 당신이 당신이 당신이 당신이 당신이 당신이 당신이 당신이 당신이 당신이 당신이 당신이 당신이 당신이 당신이 다음과 같은 Apache Commons의 일부 클래스를 사용할 수 있을지에 따라 다음과 같은 것입니다. Apache Commons Lang 그리고 아파치 커먼즈 컬렉션

예시:

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

또는 (확인 해야하는 것에 따라) :

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

StringUtils 클래스는 많은 사람들 중 하나 일뿐입니다. 공통점에는 안전한 안전 조작을하는 좋은 수업이 꽤 있습니다.

다음은 Apache Library (Commons-Lang-2.4.jar)를 포함 할 때 Java에서 Null Vallidation을 사용하는 방법에 대한 예를 따릅니다.

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

Spring을 사용하는 경우 Spring은 패키지에 동일한 기능을 가지고 있습니다. 라이브러리 (Spring-2.4.6.jar)를 참조하십시오.

스프링 에서이 정적 클래스를 사용하는 방법에 대한 예제 (org.springframework.util.assert)

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");
  • 객체가 null이되어서는 안된다고 생각하는 경우 (또는 버그입니다) Assert를 사용하십시오.
  • 메소드가 허용되지 않으면 NULL PARAM이 Javadoc에서이를 말하고 Assert를 사용합니다.

객체를 확인해야합니다! = 객체가 널이 될 수있는 케이스를 처리하려는 경우에만 NULL ...

null / notnull params를 돕기 위해 Java7에 새로운 주석을 추가하라는 제안이 있습니다.http://tech.puredanger.com/java7/#jsr308

나는 "FASS FAST"코드의 팬입니다. 스스로에게 물어보십시오 - 매개 변수가 null 인 경우에 유용한 일을하고 있습니까? 이 경우 코드가해야 할 일에 대한 명확한 답변이 없다면 ... 즉, 처음에는 무시해서는 안되며 무시하고 NullPointerException을 던지도록 허용하십시오. 호출 코드는 불법적 인 소집과 마찬가지로 NPE를 많이 이해할 수 있지만, 개발자가 코드가 다른 예기치 않은 우발성을 실행하려고 시도하는 대신 NPE가 발생하는 경우 개발자가 디버그하고 무엇이 잘못되었는지 이해하는 것이 더 쉬울 것입니다. 논리 - 궁극적으로 응용 프로그램이 어쨌든 실패합니다.

Google Collections Framework는 Null Check를 달성 할 수있는 훌륭하고 우아한 방법을 제공합니다.

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

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();

때로는 대칭 작업을 정의하는 매개 변수에서 작동하는 방법이 있습니다.

a.f(b); <-> b.f(a);

B가 결코 null이 될 수 없다는 것을 알고 있다면, 그냥 교체 할 수 있습니다. 그것은 평등에 가장 유용합니다 : 대신 foo.equals("bar"); 더 잘합니다 "bar".equals(foo);.

널 객체 패턴이 아니라 널 객체가 버그 인 상황을 고려할 수 있습니다.

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

Java 7에는 새로운 기능이 있습니다 java.util.Objects a가있는 유틸리티 클래스 requireNonNull() 방법. 이 모든 일은 a를 던지는 것입니다 NullPointerException 인수가 null이지만 코드를 약간 정리합니다. 예시:

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

이 방법은 가장 유용합니다 확인 중 생성자에 할당되기 직전에, 각각의 사용은 세 줄의 코드를 저장할 수 있습니다.

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

becomes

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

Null은 '문제'가 아닙니다. a의 필수 부분입니다 완벽한 모델링 도구 세트. 소프트웨어는 세계의 복잡성을 모델링하는 것을 목표로하며 Null은 그 부담을 겪습니다. NULL은 '데이터 없음'또는 '알 수없는'을 나타냅니다. 자바 등으로. 따라서 이러한 목적으로 널을 사용하는 것이 적절합니다. 나는 '널 객체'패턴을 선호하지 않습니다. 나는 그것이 상승하는 것 같아요누가 가디언을 지키게 될 것입니다' 문제.
내 여자 친구의 이름이 무엇인지 물어 보면 여자 친구가 없다고 말해 줄게. Java 언어로는 Null을 반환 할 것입니다. 대안은 의미있는 예외를 던져서 바로 해결할 수 없거나 원하지 않는 일부 문제를 나타내고 스택에서 더 높은 곳에 위임하여 사용자에게 데이터 액세스 오류를 재 시도하거나보고하기 위해 위임하는 것입니다.

  1. '알 수없는 질문'알 수없는 답변 '. (비즈니스 관점에서 올바른 곳에서 Null-Safe가 되십시오) 사용하기 전에 메소드 내부에 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 an의 서브 클래스입니다 Exception. 따라서 그것은 형태입니다 Throwable 이는 합리적인 응용 프로그램이 잡기를 원할 수있는 조건을 나타냅니다 (Javadoc)! 예외의 첫 번째 이점과 '일반'코드에서 별도의 오류 처리 코드를 사용하려면 (Java의 제작자에 따르면) 나를 잡는 것이 적절합니다. NullPointerException.

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

    질문이 발생할 수 있습니다.

    Q. 만약 getPhotoDataSource() NULL을 반환합니까?
    A. 비즈니스 논리에 달려 있습니다. 사진 앨범을 찾지 못하면 사진을 보여 드릴게요. AppContext가 초기화되지 않으면 어떻게됩니까? 이 방법의 비즈니스 논리는 이것을 달성합니다. 동일한 논리가 더 엄격 해야하는 경우 예외를 던지면 비즈니스 논리의 일부이며 NULL에 대한 명시 적 점검을 사용해야합니다 (케이스 3). 그만큼 새로운 Java Null-Safe API는 여기에 더 잘 맞습니다. 프로그래머 오류가 발생할 경우 고정력이 없습니다.

    Q. 중복 코드를 실행할 수 있으며 불필요한 리소스를 잡을 수 있습니다.
    A. 경우 발생할 수 있습니다 getPhotoByName() 데이터베이스 연결을 열고 작성하려고합니다 PreparedStatement 그리고 마침내 사람 이름을 SQL 매개 변수로 사용하십시오. 접근 알 수없는 질문은 알 수없는 답변을 제공합니다 (사례 1) 여기에서 작동합니다. 리소스를 잡기 전에이 방법은 매개 변수를 확인하고 필요한 경우 '알 수없는'결과를 반환해야합니다.

    Q.이 접근법에는 시도 폐쇄 개방으로 인해 성능 페널티가 있습니다.
    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. Downvote에 빠르게 (그리고 문서를 읽는 것이 빠르지 않음) 내 인생에서 null-pointer 예외 (NPE)를 잡은 적이 없다고 말하고 싶습니다. 그러나이 가능성은있었습니다 의도적으로 설계되었습니다 NPE가 서브 클래스이기 때문에 Java 제작자에 의해 Exception. 우리는 언제 Java 역사상 선례를 가지고 있습니다 ThreadDeath 이다 Error 실제로 응용 프로그램 오류이기 때문이 아니라 잡히려고하지 않았기 때문입니다! NPE가 얼마나 적합한 지 Error ~보다 ThreadDeath! 그러나 그렇지 않습니다.

  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.DefaultUncTexceptionHandler (좋아하는 로거 또는 기타 알림 메카이즈를 정의하고 사용하기 위해). 설정하지 않으면 ThreadGroup#uncaughtexception 스택 트레이스를 시스템 오류로 인쇄합니다. 실제로 응용 프로그램 오류 인 각각의 처리되지 않은 예외에 대해 응용 프로그램 오류 로그 및 열린 JIRA 문제를 모니터링해야합니다. 프로그래머는 초기화의 어딘가에 버그를 수정해야합니다.

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

  • Objective-C에서는 메소드를 호출하는 것과 동등한 일을 할 수 있습니다. nil, 그리고 절대적으로 아무 일도 일어나지 않을 것입니다. 이로 인해 대부분의 널 검사는 불필요하지만 진단하기가 훨씬 어려워 질 수 있습니다.
  • ~ 안에 멋진, Java 유래 언어에는 모든 유형의 두 가지 버전이 있습니다 : 잠재적 인 널 버전과 널이 아닌 버전. 널없는 유형에서만 메소드를 호출 할 수 있습니다. NULL 검사를 통해 잠재적으로 널 유형을 널없는 유형으로 변환 할 수 있습니다. 이로 인해 Null Check가 필요한 위치와 그렇지 않은 곳을 훨씬 쉽게 알 수 있습니다.

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

먼저, 이것에 대한 나의 생각 :

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

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

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

먼저이 컨벤션을 따릅니다.

  1. 모든 공개 방법 / API는 항상 NULL에 대한 인수를 확인합니다.
  2. 모든 개인 방법은 통제 된 방법이므로 NULL을 확인하지 않습니다 (위에 처리되지 않은 경우 NullPointer 예외로 죽게하십시오).
  3. NULL을 확인하지 않는 유일한 다른 방법은 유틸리티 방법입니다. 그들은 공개적이지만 어떤 이유로 전화하면 어떤 매개 변수를 전달하는지 알 수 있습니다. 이것은 물을 제공하지 않고 주전자의 물을 끓이는 것과 같습니다 ...

마지막으로, 코드에서 공개 방법의 첫 번째 줄은 다음과 같습니다.

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

AddParam ()은 자체를 반환하여 더 많은 매개 변수를 추가 할 수 있도록하십시오.

방법 validate() 확인을 던질 것입니다 ValidationException 매개 변수 중 하나가 NULL 인 경우 ValidationException 확인).

void validate() throws ValidationException;

예를 들어 "계획"이 null 인 경우 다음 텍스트가 포함됩니다.

"불법 인수 값 NULL은 매개 변수에 나타납니다 [계획"

보시다시피, AddParam () 메소드 (String)의 두 번째 값은 사용자 메시지에 필요합니다. 반사 된 변수 이름을 쉽게 감지 할 수 없기 때문에 (어쨌든이 게시물의 주제가 아님).

그리고 그렇습니다. 우리는이 라인을 넘어서 더 이상 널 값을 만나지 않기 때문에 해당 객체에 대한 방법을 안전하게 호출한다는 것을 알고 있습니다.

이런 식으로 코드는 깨끗하고 쉽게 유지 관리 가능하며 읽을 수 있습니다.

그 질문을하면 오류 처리 전략에 관심이있을 수 있습니다. 팀의 건축가는 작업 오류를 결정해야합니다. 이를 수행하는 방법에는 여러 가지가 있습니다.

  1. 예외를 파열시키는 것을 허용하십시오 - '메인 루프'또는 다른 관리 루틴에서 잡으십시오.

    • 오류 조건을 확인하고 적절하게 처리하십시오

물론 측면 지향적 프로그래밍을 살펴보십시오. 삽입하는 깔끔한 방법이 있습니다. if( o == null ) handleNull() 바이트 코드로.

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

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

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

if (someobject != 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가 아닌 이유를 알 수 있습니다.

Google에서 매우 유용한 핵심 라이브러리 인 Guava는 널을 피할 수있는 멋지고 유용한 API를 가지고 있습니다. 나는 찾았다 andandavoidingnullexplyed 사용 매우 도움이됩니다.

위키에 설명 된 바와 같이 :

Optional<T> Nullable T Reference를 Null 값으로 바꾸는 방법입니다. 선택 사항에는 Null T 참조가 포함되어있을 수 있습니다 (이 경우 참조가 "현재"라고 함) 또는 아무것도 포함하지 않을 수 있습니다 (이 경우 참조가 "결석"이라고합니다). "널 포함"라고 말한 적이 없습니다.

용법:

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

이것은 모든 Java 개발자에게 매우 일반적인 문제입니다. 따라서 Java 8에는 이러한 문제가 혼란스럽지 않고 해결하기위한 공식적인 지원이 있습니다.

Java 8이 소개되었습니다 java.util.Optional<T>. 널 값이 아닌 값을 보유하거나 보유하지 않을 수도있는 컨테이너입니다. Java 8은 일부 사례에서 값이 무효 일 수있는 물체를 처리 할 수있는 안전한 방법을 제공했습니다. 그것은 아이디어에서 영감을 받았습니다 Haskell 그리고 스칼라.

간단히 말해서, 선택적 클래스에는 값이 존재하거나없는 경우를 명시 적으로 처리하는 방법이 포함되어 있습니다. 그러나 NULL 참조와 비교 한 장점은 선택 사항입니다.u003CT> 클래스는 가치가 없을 때 사건에 대해 생각하게합니다. 결과적으로 의도하지 않은 널 포인터 예외를 방지 할 수 있습니다.

위의 예에는 가정에서 이용 가능한 여러 기기에 핸들을 반환하는 홈 서비스 공장이 있습니다. 그러나 이러한 서비스는 이용 가능하거나 기능하지 않을 수 있습니다. 이는 NullPointerException을 초래할 수 있음을 의미합니다. 널을 추가하는 대신 if 서비스를 사용하기 전에 조건 옵션으로 래핑합시다.u003CService> .

옵션으로 포장u003CT>

공장에서 서비스를 참조하는 방법을 고려해 봅시다. 서비스 참조를 반환하는 대신 옵션으로 마무리하십시오. API 사용자에게 반환 된 서비스가 사용 가능하거나 사용하지 않을 수도 있고 방어 적으로 사용하십시오.

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

보시다시피 Optional.ofNullable() 참조를 랩핑하는 쉬운 방법을 제공합니다. 선택 사항을 참조하는 다른 방법이 있습니다. Optional.empty() & Optional.of(). 하나는 널을 재조정하는 대신 빈 객체를 반환하고 다른 하나는 널리킹 할 수없는 물체를 각각 감싸기 위해 각각.

그렇다면 널 점검을 피하는 것이 정확히 어떻게 도움이됩니까?

참조 객체를 래핑 한 후에는 옵션이 NPE없이 랩핑 된 참조에서 메소드를 호출하는 많은 유용한 방법을 제공합니다.

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

옵션. ifpresent는 널 값이 아닌 값인 경우 주어진 소비자를 참조하여 호출합니다. 그렇지 않으면 아무것도하지 않습니다.

@FunctionalInterface
public interface Consumer<T>

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

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

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

이제 homeservices.get ()도 같은 일을하지만 더 나은 방법으로 수행합니다. 서비스가 이미 초기화되어 있는지 확인합니다. 그렇다면 동일하게 반환하거나 새 서비스를 작성하십시오. 선택 과목u003CT> .ORELSE (t)는 기본값을 반환하는 데 도움이됩니다.

마지막으로, NUL 확인 코드뿐만 아니라 NPE도 있습니다.

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 Check-Free Code… 정말로?.

나는 Nat Pryce의 기사를 좋아합니다. 다음은 링크입니다.

기사에는 흥미로운 자바 유형에 대한 git 저장소에 대한 링크가 있지만, 단독으로 확인 코드 블로트를 줄일 수 있다고 생각하지 않습니다. 인터넷에 대한 조사를 한 후 ! = null 신중한 디자인으로 주로 코드 블로트를 줄일 수 있습니다.

나는 시도했다 NullObjectPattern 그러나 나에게 항상 가장 좋은 방법은 아닙니다. 때때로 "조치 없음"이 적절하지 않은 경우가 있습니다.

NullPointerException a 런타임 예외 즉, 개발자의 결함이라는 것을 의미하며 충분한 경험을 통해 오류가 어디에 있는지 정확히 알 수 있습니다.

이제 답에 :

모든 속성과 액세서를 가능한 한 개인적으로 만들거나 고객에게 전혀 노출하지 않도록하십시오. 물론 생성자에 인수 값을 가질 수 있지만 범위를 줄임으로써 클라이언트 클래스가 무효 값을 전달하지 못하게합니다. 값을 수정 해야하는 경우 언제든지 새를 만들 수 있습니다. object. 생성자의 값 만 확인합니다 한 번 그리고 나머지 방법에서는 값이 무효가 아니라고 확신 할 수 있습니다.

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

바이트!

아마도 Java 8 또는 Newer의 가장 좋은 대안은 Optional 수업.

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

이것은 가능한 널 값의 긴 체인에 특히 편리합니다. 예시:

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

NULL에서 예외를 던지는 방법에 대한 예 :

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

Java 7은 다음을 소개했습니다 Objects.requireNonNull 널이 아닌 것을 확인해야 할 때 편리 할 수있는 방법. 예시:

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

더 일반적으로 대답하시기 바랍니다!

우리 대개 메소드가 우리가 예상하지 못한 방식으로 매개 변수를 얻을 때이 문제에 직면하십시오 (잘못된 메소드 호출은 프로그래머의 결함입니다). 예를 들어 : 당신은 객체를 얻을 것으로 예상하고 대신 널을 얻습니다. 당신은 하나 이상의 문자로 문자열을 얻을 것으로 예상하고 대신 빈 줄을 얻습니다 ...

따라서 다음 사이에는 차이가 없습니다.

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

}

또는

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

둘 다 다른 기능을 수행하기 전에 유효한 매개 변수를 받았는지 확인하려고합니다.

다른 답변에서 언급했듯이 위의 문제를 피하기 위해 계약에 의한 디자인 무늬. 참조하십시오 http://en.wikipedia.org/wiki/design_by_contract.

Java 에서이 패턴을 구현하려면 Core Java 주석을 사용할 수 있습니다. javax.annotation.notnull 또는보다 정교한 라이브러리를 사용하십시오 최대 절전 모드 유효성 검사기.

그냥 샘플 :

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

이제 입력 매개 변수를 확인하지 않고도 메소드의 핵심 기능을 안전하게 개발할 수 있으며 예기치 않은 매개 변수로부터 메소드를 보호 할 수 있습니다.

한 걸음 더 나아가서 응용 프로그램에서 유효한 Pojos 만 생성 할 수 있는지 확인할 수 있습니다. (Hibernate Validator 사이트의 샘플)

public class Car {

   @NotNull
   private String manufacturer;

   @NotNull
   @Size(min = 2, max = 14)
   private String licensePlate;

   @Min(2)
   private int seatCount;

   // ...
}

나는 모든 상황에서 null 객체를 사용하는 것을 제안하는 답을 무시합니다. 이 패턴은 계약을 중단하고 계약 문제를 해결하는 대신 더 깊고 깊어 지면서도 부적절하게 사용하면 향후 유지 보수가 필요한 다른 보일러 플레이트 코드 더미를 생성 할 것이라고는 언급하지 않습니다.

실제로 메소드에서 반환 된 무언가가 Null이 될 수 있고 호출 코드가 이에 대한 결정을 내려야하는 경우, 주를 보장하는 초기 호출이 있어야합니다.

또한 신경 쓰지 않고 사용하면 널 객체 패턴이 메모리 배가 고프다는 점을 명심하십시오. 이를 위해 - NullObject의 인스턴스는 소유자간에 공유되어야하며, 각각에 대해 미확인 인스턴스가되어서는 안됩니다.

또한 유형이 스칼라가 아닌 수학적 엔티티와 같은 원시 유형 표현이라는이 패턴을 사용하지 않는 것이 좋습니다. 자바 내장 유형의 형태로. 후자의 경우 임의의 결과로 getter 방법을 호출하게됩니다. 예를 들어 nullperson.getName () 메소드는 무엇을 반환해야합니까?

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

  1. 변수를 null로 초기화하지 마십시오.
  2. (1)가 불가능한 경우 모든 컬렉션과 어레이를 빈 컬렉션/어레이로 초기화하십시오.

이 작업을 자신의 코드로 수행하면 피할 수 있습니다! = Null Checks.

대부분의 경우 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의 가치가 있습니다.

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

우리는 이것을 처리하는 방법이 많이 있습니다.

Approach 1:

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

notnull (개체 객체, 문자열 메시지)

Approach 2:

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

접근 3 : :

@isNull @Nullable  // using annotation based validation

Approach 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;
}
public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top