Alternatives to returning NULL

2020-02-24 12:02发布

   /**
     * Returns the foo with the matching id in this list
     * 
     * @param id the id of the foo to return
     * @return the foo with the matching id in this list
     */
    public Foo getFoo(int id)
    {
        for (Foo foo : list)
        {
            if (foo.getID() == id)
            {
                return foo;
            }
        }

        return null;
    }

Instead of returning null when foo is not found, should I throw an exception? Does it matter, and is there a "best practices" idiom on the subject? By the way, I know my example is a bit contrived, but I hope you get the idea...

Thanks.

EDIT

Changed code to get Foo based on id to better illustrate a real-world scenario.

15条回答
劫难
2楼-- · 2020-02-24 12:30

Returning null is not only more simple to handle, performs better too. The exceptions must be used to handle exceptional cases.

查看更多
太酷不给撩
3楼-- · 2020-02-24 12:32

It's best to avoid exceptions if you can, but sometimes you just can't. In this case, what if you had stored null in the list? You can't tell the difference between 'found null' and 'could not find what you wanted'.

There is a pattern, it's called Option Types and it's used a lot in Scala. You either return a container with the item, or a container of a class that says 'I'm empty'. The wiki article will give a better picture.

You could also have a 'does this exist in the collection?' method which returns a bool, then throw an exception from the above code for if you didn't check first.


And just a comment completely unrelated to your actual question. If you implement equals, it should only return true if the two objects are actually considered equal. Therefore the above code must always return the object you pass into it!

查看更多
欢心
4楼-- · 2020-02-24 12:32

Another point of view I haven't read in the other answers is the following:

Does the list contain null's of Foo? If this is the case, one would not know whether the id was found, or whether it was associated with null. In this case:

  • Throw an exception that the list is not found;
  • Wrap the result in another object (e.g. a SearchResult, which tells you if the object was found, it's associative id, it's result, or no result if it was not found);
  • Create the method existsFoo(int id).

Each solution has it's own problems, and it depends on the case which to use:

  • As others noted, Exceptions are exceptional;
  • A wrapper, SearchResult, has to be allocated each time you'd like to retry a search. The wrapper can be made mutable, but this introduces a lot of new difficulties and problems;
  • existsFoo has to search the list which doubles the cost of knowing whether the key exists or not.

Generally I can say:

  • Is an ID not being found exceptional? Use IllegalArgumentException;
  • Is the result passed to other classes, used as an object? Use a wrapper, e.g. SearchResult;
  • Is with getFoo only checked whether it's null or not (it exists or not)? Use another method, existsFoo.
查看更多
该账号已被封号
5楼-- · 2020-02-24 12:33

While I agree that coding for null is simple and easy boilerplate programmer conditioning, it adds little value for the complexity introduced. Always assuming non-null references makes for cleaner logic with slightly less code -- you still have to test for failure.

The annotation excerpt below will help you to not fall into the old ways...

Use @Nullable

To eliminate NullPointerExceptions in your codebase, you must be disciplined about null references. We've been successful at this by following and enforcing a simple rule:

Every parameter is non-null unless explicitly specified.

The Guava: Google Core Libraries for Java and JSR-305 have simple APIs to get a nulls under control. Preconditions.checkNotNull can be used to fast-fail if a null reference is found, and @Nullable can be used to annotate a parameter that permits the null value:

import static com.google.common.base.Preconditions.checkNotNull;
import static javax.annotation.Nullable;

public class Person {
  ...

  public Person(String firstName, String lastName, @Nullable Phone phone) {
    this.firstName = checkNotNull(firstName, "firstName");
    this.lastName = checkNotNull(lastName, "lastName");
    this.phone = phone;
  }

If null is permissible by your class, you can annotate the field or parameter with @Nullable ... using any @Nullable annotation, like edu.umd.cs.findbugs.annotations.Nullable or javax.annotation.Nullable.

查看更多
狗以群分
6楼-- · 2020-02-24 12:37

In this case, since you're defining an accessor, it should return null. If it were another method where this method should guarantee a non-null response, an exception would be more appropriate.

As a side note though, rather than calling the sample method a getter it might be more appropriate to name it something like Foo findFoo(Foo f) since you're searching rather than just getting.

查看更多
Emotional °昔
7楼-- · 2020-02-24 12:38

Returning null is fine, if it is documented as a valid result.

Another option is the null-object pattern. That is - an instance of Foo that doesn't have any data:

public class Foo {
    public static final Foo NULL_FOO = new Foo();
}

and return it instead.

查看更多
登录 后发表回答