[java] 避免!=空語句


Answers

如果您使用(或計劃使用)Java IDE(如JetBrains IntelliJ IDEA ,Eclipse或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 IDEA編譯器會告訴你這個檢查是無用的,因為helloWorld()函數不會返回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來避免NullPointerException

有沒有一個很好的選擇呢?

例如:

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

這可以避免NullPointerException ,如果該對象為null或未知,則不會發生。

請注意,接受的答案可能已過時,請參閱https://.com/a/2386013/12943以獲取更新的方法。




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.




哇,當我們有57種不同的方式來推薦NullObject pattern時,我幾乎不願意添加另一個答案,但我認為對這個問題感興趣的一些人可能想知道在表7中有一個提議將“null安全處理“ - 為if-not-equal-null邏輯簡化了語法。

Alex Miller給出的例子如下所示:

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

這個?. 意味著只有在左標識符不為空時才去引用它,否則將其餘表達式評估為null 。 一些人,如Java Posse成員迪克沃爾和Devoxx選民確實喜歡這個提議,但也有人反對,理由是它實際上會鼓勵更多地使用null作為定位值。

更新: Java 7中的空安全運算符的proposed已在Project Coin下提交 語法與上面的例子有點不同,但它是相同的概念。

更新:無效運營商提案沒有將其納入項目投幣。 所以,你將不會在Java 7中看到這種語法。




我是“快速失敗”代碼的粉絲。 問問自己 - 在參數為空的情況下,你是否正在做一些有用的事情? 如果您在這種情況下沒有明確的答案,那麼您的代碼應該做什麼......也就是說,它不應該為空,然後忽略它並允許引發NullPointerException。 調用代碼與NPE一樣,會產生IllegalArgumentException異常,但開發人員可以更容易地調試和理解如果拋出NPE而不是您的代碼嘗試執行其他意外的應急事件邏輯 - 最終導致應用程序失敗。




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.




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.




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?




Java 7有一個新的java.util.Objects實用程序類,其中有一個requireNonNull()方法。 如果它的參數為null,所有這些都會拋出一個NullPointerException ,但會清除代碼。 例:

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



  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.




僅適用於這種情況 - 避免在字符串比較之前檢查null:

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

如果foo不存在,將導致NullPointerException

你可以避免,如果你比較你的String是這樣的:

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



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



Google集合框架提供了一個非常好的方法來實現空檢查。

在這樣的庫類中有一個方法:

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



根據您檢查的對像類型,您可能可以使用apache commons中的某些類,例如: apache commons langapache commons collections

例:

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

或(取決於您需要檢查的內容):

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

StringUtils類只是其中的一個; 在公共場合中有相當多的好幾類做無效安全操作。

下面是一個例子,說明當你包含apache庫(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的包中也有相同的功能,請參閱library(spring-2.4.6.jar)

有關如何從spring中使用此靜態類的示例(org.springframework.util.Assert)

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



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!




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.





Related