java 치환 체크 - 피하기! = null 문





15 Answers

JetBrains IntelliJ IDEA , Eclipse 또는 Netbeans 또는 findbugs와 같은 Java IDE를 사용하거나 사용하려는 경우 특수 효과를 사용하여이 문제를 해결할 수 있습니다.

기본적으로 @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 반환하지 않으므로 검사가 쓸모 없다고 알려 null .

매개 변수 사용

void someMethod(@NotNull someParameter) { }

당신이 다음과 같은 것을 쓰면 :

someMethod(null);

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

@Nullable 사용한 마지막 예제

@Nullable iWantToDestroyEverything() { return null; }

이렇게

iWantToDestroyEverything().something();

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

컴파일러가 일반적으로하는 것보다 더 많은 것을 검사하게하고 계약이 강해지도록하는 좋은 방법입니다. 불행히도 모든 컴파일러에서 지원하지는 않습니다.

IntelliJ IDEA 10.5 이상에서는 @Nullable @NotNull 구현을 지원합니다.

블로그 게시물 보기 더 유연하고 구성 가능한 @ Nullable / @ NotNull 주석 .

hashmap 자바 공백

나는 object != null 사용 object != null NullPointerException 을 피하기 위해 많은 object != null .

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

예 :

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

이렇게하면 객체가 null 인지 아닌지를 알 수 없을 때 NullPointerException 피할 수 있습니다.

수락 된 답변의 유효 기간이 지났을 수 있습니다 ( https://.com/a/2386013/12943 .




와우, NullObject pattern 을 추천하는 57 가지 방법이있을 때 다른 답변을 추가하는 것이 거의 싫지만이 질문에 관심있는 사람들은 Java 7에 대한 제안이 "null" 을 추가한다는 것을 알고 싶어한다고 생각합니다. -safe handling " - if-not-equal-null 로직에 대한 간소화 된 구문.

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

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

?. 왼쪽 식별자가 null이 아닌 경우에만 참조 해제를 의미하고, 그렇지 않으면 표현식의 나머지를 null로 평가합니다. 자바 보스 (Java Posse) 회원 인 딕 월 (Dick Wall)과 Devoxx유권자 와 같은 사람들은이 제안을 정말 좋아하지만 실제로는 null 을 센티널 가치로 더 많이 사용하도록 장려하고 있습니다.

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

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




이 상황에 대해서만 -

equals 메서드를 호출하기 전에 변수가 null인지 검사하지 않습니다 (아래 문자열 비교 예제 참조).

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

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

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

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



어떤 종류의 객체를 검사 하느냐에 따라 다음과 같이 아파치 공유의 일부 클래스를 사용할 수 있습니다 : apache commons langapache commons collections

예:

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

또는 (확인할 필요에 따라) :

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

StringUtils 클래스는 많은 클래스 중 하나입니다. 커넬에는 null 안전한 조작을하는 꽤 좋은 클래스가 있습니다.

다음은 아파치 라이브러리 (commons-lang-2.4.jar)를 포함시킬 때 JAVA에서 널 vallidation을 사용하는 방법의 예입니다.

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)

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

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



저는 "실패 빠른"코드의 팬입니다. 자신에게 물어보십시오. 매개 변수가 null 인 경우 유용하게 사용할 수 있습니까? 이 경우에 코드에서 수행해야 할 작업에 대한 명확한 답이없는 경우 ... 즉, 처음에는 null이 아니어야하며 무시한 다음 NullPointerException을 throw 할 수 있습니다. 호출 코드는 IllegalArgumentException만큼이나 NPE를 이해할 수 있지만, 예기치 않은 다른 우발적 사건을 실행하려고 시도하는 코드가 아니라 NPE가 발생하면 개발자가 디버그하고 이해하기 쉽습니다. 논리 - 궁극적으로 어쨌든 응용 프로그램이 실패하게됩니다.




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

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

b가 null이 될 수 없다는 것을 안다면, 그냥 바꿀 수 있습니다. 그것은 equals에 가장 유용합니다 : foo.equals("bar"); 대신 foo.equals("bar"); 더 나은 "bar".equals(foo); .




Java 7에는 requireNonNull() 메소드가있는 새로운 java.util.Objects 유틸리티 클래스가 있습니다. 이 메소드는, 인수가 null의 경우는 NullPointerException throw하지만, 코드를 조금 클린 업합니다. 예:

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

이 메서드는 생성자에서 할당하기 직전에 checking 데 가장 유용합니다. 생성자를 사용하면 코드 세 줄을 절약 할 수 있습니다.

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

된다

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



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

  • Objective-C에서는 메소드를 호출하는 것과 동등한 작업을 수행 할 수 있으며 nil아무 일도 일어나지 않을 것입니다. 이렇게하면 대부분의 null 검사가 불필요하지만 오류를 진단하기가 훨씬 더 어려워 질 수 있습니다.
  • 에서 Nice 잠재적 널 버전과-null이 아닌 버전 : 자바에서 파생 된 언어, 모든 유형의 두 가지 버전이있다. Null이 아닌 유형에 대해서만 메소드를 호출 할 수 있습니다. null가 될 가능성이있는 형은, null를 명시 적으로 체크하는 것으로 써, null가 아닌 형태로 변환 할 수 있습니다. 따라서 널 확인이 필요한 곳과 그렇지 않은 곳을 훨씬 쉽게 알 수 있습니다.



이 질문을하는 것은 오류 처리 전략에 관심이있을 수 있음을 지적합니다. 팀의 설계자는 오류 작업 방법을 결정해야합니다. 이를 수행하는 방법에는 여러 가지가 있습니다.

  1. 예외가 파급되도록 허용하십시오 - '메인 루프'또는 다른 관리 루틴에서 그들을 잡으십시오.

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

물론 Aspect Oriented Programming을 살펴 봐도 if( o == null ) handleNull()바이트 코드에 깔끔하게 삽입 할 수 있습니다.




절대 null을 사용하지 마십시오. 그것을 허용하지 마십시오.

내 수업에서는 대부분의 필드와 지역 변수가 null이 아닌 기본값을 가지고 있으며 코드에서 도처에 계약 서술문 (always-on asserts)을 추가하여 코드가 강제 적용되도록합니다 (간결하고 더 자세하게 표현하기 때문에 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가 아닌지 파악해야합니다.




이것은 모든 Java 개발자에게 매우 공통적 인 문제입니다. 따라서 자바 8에서는 공식 코드가 없어도 이러한 문제를 해결할 수 있습니다.

Java 8이 도입되었습니다 java.util.Optional<T>. null 이외의 값을 보관 유지하는 컨테이너일지도 모릅니다. Java 8은 값의 일부가 null 일 수있는 객체를보다 안전하게 처리 할 수있는 방법을 제공합니다. HaskellScala 의 아이디어에서 영감을 얻었습니다 .

간단히 말해, Optional 클래스는 값이 존재하거나 존재하지 않는 경우를 명시 적으로 처리하는 메소드를 포함합니다. 그러나 null 참조에 비해 이점은 옵션 <T> 클래스가 값이없는 경우에 대해 생각하도록합니다. 따라서 의도하지 않은 널 포인터 예외를 방지 할 수 있습니다.

위의 예에서 우리는 집에서 사용할 수있는 여러 기기에 대한 핸들을 반환하는 집 서비스 팩토리를 가지고 있습니다. 그러나 이러한 서비스는 사용 가능할 수도 있고 기능이 없을 수도 있습니다. NullPointerException이 발생할 수 있음을 의미합니다. if서비스를 사용하기 전에 null 조건 을 추가하는 대신 Optional <Service>로 다시 감싸 웁니다.

옵션으로 포장하기 <T>

공장에서 서비스에 대한 참조를 얻는 방법을 생각해 봅시다. 서비스 참조를 반환하는 대신 선택 사항으로 묶습니다. API 사용자는 반환 된 서비스가 사용 가능하거나 사용 가능하지 않을 수도 있음을 알게하고, 방어 적으로 사용합니다

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

보시다시피 참조를 Optional.ofNullable()쉽게 얻을 수있는 방법을 제공합니다. Optional.empty()&를 참조 할 수있는 또 다른 방법이 있습니다 Optional.of(). 하나는 널 (null)을 리턴하는 대신 빈 오브젝트를 리턴하고 다른 하나는 널 (null)이 아닌 오브젝트를 랩하기위한 것입니다.

그래서 그것은 정확하게 NULL 체크를 피하는 데 얼마나 도움이됩니까?

일단 참조 객체를 래핑하면, Optional은 NPE없이 래핑 된 참조에서 메소드를 호출하는 많은 유용한 메소드를 제공합니다.

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

Optional.ifPresent는 null이 아닌 값인 경우 해당 Consumer를 참조로 호출합니다. 그렇지 않으면 아무것도 수행하지 않습니다.

@FunctionalInterface
public interface Consumer<T>

단일 입력 인수를 받아들이고 결과를 반환하지 않는 연산을 나타냅니다. 다른 대부분의 기능 인터페이스와 달리 소비자는 부작용을 통해 작동해야합니다. 그것은 매우 깨끗하고 이해하기 쉽습니다. 위의 코드 예제 HomeService.switchOn(Service)에서 Optional Holding 참조가 null이 아닌 경우 호출됩니다.

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

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

이제 HomeServices.get ()은 똑같은 일을하지만 더 좋은 방법입니다. 서비스가 이미 초기화되었는지 여부를 확인합니다. 그런 다음 동일한 경우 반환하거나 새 새 서비스를 만듭니다. 선택적 <T>. orElse (T)는 기본값을 반환하는 데 도움이됩니다.

마지막으로 NPE와 null check-free 코드가 있습니다.

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 체크 프리 코드입니다 ... 정말요? .




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

NullPointerException개발자의 실수라는 것을 의미 하는 런타임 예외 이며, 충분한 경험을 통해 오류의 정확한 위치를 알려줍니다.

답변 :

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

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

바이트!




좀 더 일반적으로 대답 해주세요!

우리는 보통 방법이 우리가 기대하지 않는 방법으로 매개 변수를 얻을 때이 문제에 직면 (나쁜 메서드 호출 프로그래머의 잘못이다). 예를 들어, 객체를 얻으 려한다면 null을 얻습니다. 적어도 하나의 문자가있는 문자열을 얻으려는 대신 빈 문자열을 얻습니다.

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

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

그냥 샘플 :

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

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

한 단계 더 나아가 애플리케이션에서 유효한 pojos 만 만들 수 있는지 확인하십시오. (최대 절전 유효성 검사기 사이트의 샘플)

public class Car {

   @NotNull
   private String manufacturer;

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

   @Min(2)
   private int seatCount;

   // ...
}



  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에 대한 가치가 있습니다.




public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}



Related