[java] ! = null 문 피하기

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

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

예를 들어 자주 사용합니다.

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

A에 대한이 확인 NullPointerException에 대한 someobject위의 코드 조각의 객체입니다.

허용되는 답변이 최신 정보가 아닐 수 있습니다 . 최신 접근 방식 은 https://stackoverflow.com/a/2386013/12943 을 참조 하십시오 .



답변

이것은 저에게 중급 개발자가 중간 시점에서 직면하는 경향이있는 합리적으로 일반적인 문제처럼 들립니다. 또한 자체 코드를 작성할 때 null을 반환하여 호출자가 null을 확인 해야하는 것을 나타내는 경향이 있습니다.

다른 방법으로 null 검사가 나타나는 두 가지 경우가 있습니다.

  1. 계약에있어서 유효한 응답이 null 인 경우 과

  2. 올바른 응답이 아닌 곳.

(2) 쉽다. 어느 사용 assert또는 진술 (주장)은 (예를 들어, 실패 할 수 NullPointerException이 ). 어설 션은 1.4에서 추가 된 잘 사용되지 않는 Java 기능입니다. 구문은 다음과 같습니다.

assert <condition>

또는

assert <condition> : <object>

여기서 <condition>부울 표현식이며 메소드 출력이 오류에 포함 <object>되는 오브젝트입니다 toString().

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

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

(1) 조금 더 어렵다. 호출하는 코드를 제어 할 수 없으면 문제가 발생한 것입니다. null이 유효한 응답 인 경우 확인해야합니다.

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

컬렉션이 아닌 경우 어려울 수 있습니다. 이러한 인터페이스를 예로 들면 다음과 같이 고려하십시오.

public interface Action {
  void doSomething();
}

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

파서는 원시 사용자 입력을 취하고 무언가에 대한 명령 행 인터페이스를 구현하는 경우해야 할 일을 찾습니다. 적절한 조치가 없으면 계약이 널을 리턴하도록 만들 수 있습니다. 그것은 당신이 말하는 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 () 메소드가 의미있는 오류 메시지 (특히이 경우 사용자 입력에 의존하는 경우)와 함께 예외를 발생시키는 것이 전적으로 적합 할 것입니다. findAction 메소드가 설명없이 간단한 NullPointerException으로 날아가는 것보다 Exception을 던지는 것이 훨씬 좋습니다.

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

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

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


답변

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

이제 IntelliJ IDEA 컴파일러는 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("...");
  }

그런 다음 나머지 방법에서 이것이 objectnull이 아님을 알 수 있습니다.

내부 메소드 (API의 일부가 아닌) 인 경우 null이 될 수 없다는 것을 문서화하십시오.

예:

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

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

널이 허용되는 경우

이것은 실제로 달려 있습니다. 내가 종종 이런 식으로 뭔가를 발견하면 :

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

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


관용구 ” if (object != null && ...” 를 사용하는 것은 실제로 드 rare니다 .

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


답변

와우, 나는 우리가 57 가지 다른 방법을 추천 할 때 또 다른 대답을 추가하는 것을 거의 싫어 NullObject pattern하지만,이 질문에 관심이있는 사람들은 Java 7에 대해 “null-safe” 를 추가하라는 제안이 있다는 것을 알고 싶어 할 것입니다 handling “ — if-nqual-null 논리를위한 간소화 된 구문.

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

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

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


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


업데이트 : null 안전 연산자 제안서가 Project Coin으로 제안되지 않았습니다. 따라서 Java 7에서는이 구문이 표시되지 않습니다.


답변

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

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

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

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

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

Java 8에는 내장 Optional클래스가 있습니다 (권장). 이전 버전, 라이브러리 대안이 있습니다 예를 들어, 구아바Optional또는 FunctionalJavaOption. 그러나 많은 기능적 스타일 패턴과 마찬가지로 Java에서 옵션 (8 개)을 사용하면 상당히 약간의 상용구가 생겨서 Scala 또는 Xtend와 같이 덜 장황한 JVM 언어를 사용하여 줄일 수 있습니다.

null을 반환 할 수 있는 API를 처리해야하는 경우 Java에서 많은 작업을 수행 할 수 없습니다. Xtend와 Groovy는 Elvis 연산자 ?:null 안전 역 참조 연산자 ?. 를 가지고 있지만 null 참조의 경우 null을 반환하므로 null의 적절한 처리를 “정의”합니다.


답변

이 상황에서만-

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

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

A의 발생합니다 NullPointerException경우 foo존재하지 않습니다.

다음 String과 같이 비교하면 피할 수 있습니다 .

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 인스턴스에 대한 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 개의 오버로드 메소드보다 선택적 인수를 나타내는 더 좋은 방법 일 수도 있습니다.

OptionalorElse기본값을 사용 ifPresent하고 람다 식과 함께 작동 하는 것과 같은 다른 편리한 방법을 제공합니다 .

이 기사 (이 답변을 작성하는 주요 소스)를 읽고 NullPointerException문제가 있는 (및 일반적으로 null 포인터) 문제와 (일부) 솔루션에 Optional대해 잘 설명 된 Java Optional Objects 를 읽으십시오 .