[java] 피하기! = null 문



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 주석 .

Question

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

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

예 :

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

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

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




어떤 종류의 객체를 검사 하느냐에 따라 다음과 같이 아파치 공유의 일부 클래스를 사용할 수 있습니다 : 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을 확인하는 것을 피하십시오.

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

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

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

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



  1. Never initialise variables to null.
  2. If (1) is not possible, initialise all collections and arrays to empty collections/arrays.

Doing this in your own code and you can avoid != null checks.

Most of the time null checks seem to guard loops over collections or arrays, so just initialise them empty, you won't need any null checks.

// 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
    }
}

There is a tiny overhead in this, but it's worth it for cleaner code and less NullPointerExceptions.




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



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




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



Asking that question points out that you may be interested in error handling strategies. Your team's architect should decide how to work errors. There are several ways to do this:

  1. allow the Exceptions to ripple through - catch them at the 'main loop' or in some other managing routine.

    • check for error conditions and handle them appropriately

Sure do have a look at Aspect Oriented Programming, too - they have neat ways to insert if( o == null ) handleNull() into your bytecode.




와우, 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에서이 구문을 보지 못할 것입니다.




I highly disregard answers that suggest using the null objects in every situation. This pattern may break the contract and bury problems deeper and deeper instead of solving them, not mentioning that used inappropriately will create another pile of boilerplate code that will require future maintenance.

In reality if something returned from a method can be null and the calling code has to make decision upon that, there should an earlier call that ensures the state.

Also keep in mind, that null object pattern will be memory hungry if used without care. For this - the instance of a NullObject should be shared between owners, and not be an unigue instance for each of these.

Also I would not recommend using this pattern where the type is meant to be a primitive type representation - like mathematical entities, that are not scalars: vectors, matrices, complex numbers and POD(Plain Old Data) objects, which are meant to hold state in form of Java built-in types. In the latter case you would end up calling getter methods with arbitrary results. For example what should a NullPerson.getName() method return?

It's worth considering such cases in order to avoid absurd results.




Just don't ever use null. Don't allow it.

In my classes, most fields and local variables have non-null default values, and I add contract statements (always-on asserts) everywhere in the code to make sure this is being enforced (since it's more succinct, and more expressive than letting it come up as an NPE and then having to resolve the line number, etc.).

Once I adopted this practice, I noticed that the problems seemed to fix themselves. You'd catch things much earlier in the development process just by accident and realize you had a weak spot.. and more importantly.. it helps encapsulate different modules' concerns, different modules can 'trust' each other, and no more littering the code with if = null else constructs!

This is defensive programming and results in much cleaner code in the long run. Always sanitize the data, eg here by enforcing rigid standards, and the problems go away.

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

The contracts are like mini-unit tests which are always running, even in production, and when things fail, you know why, rather than a random NPE you have to somehow figure out.




This is a very common problem for every Java developer. So there is official support in Java 8 to address these issues without cluttered code.

Java 8 has introduced java.util.Optional<T> . It is a container that may or may not hold a non-null value. Java 8 has given a safer way to handle an object whose value may be null in some of the cases. It is inspired from the ideas of Haskell and Scala .

In a nutshell, the Optional class includes methods to explicitly deal with the cases where a value is present or absent. However, the advantage compared to null references is that the Optional<T> class forces you to think about the case when the value is not present. As a consequence, you can prevent unintended null pointer exceptions.

In above example we have a home service factory that returns a handle to multiple appliances available in the home. But these services may or may not be available/functional; it means it may result in a NullPointerException. Instead of adding a null if condition before using any service, let's wrap it in to Optional<Service>.

WRAPPING TO OPTION<T>

Let's consider a method to get a reference of a service from a factory. Instead of returning the service reference, wrap it with Optional. It lets the API user know that the returned service may or may not available/functional, use defensively

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

As you see Optional.ofNullable() provides an easy way to get the reference wrapped. There are another ways to get the reference of Optional, either Optional.empty() & Optional.of() . One for returning an empty object instead of retuning null and the other to wrap a non-nullable object, respectively.

SO HOW EXACTLY IT HELPS TO AVOID A NULL CHECK?

Once you have wrapped a reference object, Optional provides many useful methods to invoke methods on a wrapped reference without NPE.

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

Optional.ifPresent invokes the given Consumer with a reference if it is a non-null value. Otherwise, it does nothing.

@FunctionalInterface
public interface Consumer<T>

Represents an operation that accepts a single input argument and returns no result. Unlike most other functional interfaces, Consumer is expected to operate via side-effects. It is so clean and easy to understand. In the above code example, HomeService.switchOn(Service) gets invoked if the Optional holding reference is non-null.

We use the ternary operator very often for checking null condition and return an alternative value or default value. Optional provides another way to handle the same condition without checking null. Optional.orElse(defaultObj) returns defaultObj if the Optional has a null value. Let's use this in our sample code:

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

Now HomeServices.get() does same thing, but in a better way. It checks whether the service is already initialized of not. If it is then return the same or create a new New service. Optional<T>.orElse(T) helps to return a default value.

Finally, here is our NPE as well as null check-free code:

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){
         //...
    }
}

The complete post is NPE as well as Null check-free code … Really? .




Ultimately, the only way to completely solve this problem is by using a different programming language:

  • In Objective-C, you can do the equivalent of invoking a method on nil , and absolutely nothing will happen. This makes most null checks unnecessary, but it can make errors much harder to diagnose.
  • In Nice , a Java-derived language, there are two versions of all types: a potentially-null version and a not-null version. You can only invoke methods on not-null types. Potentially-null types can be converted to not-null types through explicit checking for null. This makes it much easier to know where null checks are necessary and where they aren't.



I've tried the NullObjectPattern but for me is not always the best way to go. There are sometimes when a "no action" is not appropiate.

NullPointerException is a Runtime exception that means it's developers fault and with enough experience it tells you exactly where is the error.

Now to the answer:

Try to make all your attributes and its accessors as private as possible or avoid to expose them to the clients at all. You can have the argument values in the constructor of course, but by reducing the scope you don't let the client class pass an invalid value. If you need to modify the values, you can always create a new object . You check the values in the constructor only once and in the rest of the methods you can be almost sure that the values are not null.

Of course, experience is the better way to understand and apply this suggestion.

Byte!




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



Related