169

I am looking for a recommendation here. I am struggling with whether it is better to return NULL or an empty value from a method when the return value is not present or cannot be determined.

Take the following two methods as an examples:

string ReverseString(string stringToReverse) // takes a string and reverses it.
Person FindPerson(int personID)    // finds a Person with a matching personID.

In ReverseString(), I would say return an empty string because the return type is string, so the caller is expecting that. Also, this way, the caller would not have to check to see if a NULL was returned.

In FindPerson(), returning NULL seems like a better fit. Regardless of whether or not NULL or an empty Person Object (new Person()) is returned the caller is going to have to check to see if the Person Object is NULL or empty before doing anything to it (like calling UpdateName()). So why not just return NULL here and then the caller only has to check for NULL.

Does anyone else struggle with this? Any help or insight is appreciated.

8
  • 2
    It will vary. You could also argue that the method should stop values which are incorrect up front, for instance your stringToReverse parameter being passed in as empty or null. If you performed that check (threw back an exception), it will always return something other than null. Commented Nov 17, 2011 at 18:42
  • Fowler POEAA - p. 496 Base Patterns - Special Case(null object) Bloch Effective Java, 2nd Edition Item 43: Return empty arrays or collections, not nulls Commented Nov 17, 2011 at 18:45
  • 1
    @Boris I didn't see your comment. I actually just posted Special Case as an answer.
    – Thomas Owens
    Commented Nov 17, 2011 at 18:49
  • @Thomas I don't see any problem in it :). As for the question it's a matter of common sense anyway. Commented Nov 17, 2011 at 18:55
  • 2
    Depends on your team consensus: in the case of mine, we agreed to return null for method that returns a single object indicating a value is not found. For method that return multiple objects (list, enumerable, array), we return empty list of object. It's all about consistency and convention.
    – Dio Phung
    Commented May 16, 2016 at 19:52

18 Answers 18

102

StackOverflow has a good discussion about this exact topic in this Q&A. In the top rated question, kronoz notes:

Returning null is usually the best idea if you intend to indicate that no data is available.

An empty object implies data has been returned, whereas returning null clearly indicates that nothing has been returned.

Additionally, returning a null will result in a null exception if you attempt to access members in the object, which can be useful for highlighting buggy code - attempting to access a member of nothing makes no sense. Accessing members of an empty object will not fail meaning bugs can go undiscovered.

Personally, I like to return empty strings for functions that return strings to minimize the amount of error handling that needs to be put in place. However, you'll need to make sure that the group that your working with will follow the same convention - otherwise the benefits of this decision won't be achieved.

However, as the poster in the SO answer noted, nulls should probably be returned if an object is expected so that there is no doubt about whether data is being returned.

In the end, there's no single best way of doing things. Building a team consensus will ultimately drive your team's best practices.

10
  • 14
    Personally, I like to return empty strings for functions that return strings to minimize the amount of error handling that needs to be put in place. Never understood this argument. The null check is what, at most < 10 chars? Why do we act like this is back bending labor? Commented Nov 17, 2011 at 18:44
  • 28
    Nobody said it was back bending labor. But it is labor. It adds a special case to the code which means one more branch to test. Plus, it disrupts the flow of the code. for x in list_of_things() {...} is arguably quicker to grok then l = list_of_things(); if l != null {...} Commented Nov 17, 2011 at 20:08
  • 8
    @Bryan: there is a big difference between an empty list of values, and an empty string. A string seldom represents a list of characters. Commented Nov 18, 2011 at 4:45
  • 4
    @kevin cline: of course. But in the case of a string, you may want that string to appear in a log whether it's null or not. Having to check if it's null so you can print an empty string obfuscates the real intent. Or perhaps it's something like database field that contains user-contributed content that you want to add to a web page. It's easier to do emit(user.hometown) than if user.hometown == null { emit("") else {emit(user.hometown)} Commented Nov 18, 2011 at 12:11
  • 3
    return optional instead. Commented Nov 18, 2019 at 9:13
102

In all the code I write, I avoid returning null from a function. I read that in Clean Code.

The problem with using null is that the person using the interface doesn't know if null is a possible outcome, and whether they have to check for it, because there's no not null reference type.

In F# you can return an option type, which can be some(Person) or none, so it's obvious to the caller that they have to check.

The analogous C# (anti-)pattern is the Try... method:

public bool TryFindPerson(int personId, out Person result);

Now I know people have said they hate the Try... pattern because having an output parameter breaks the ideas of a pure function, but it's really no different than:

class FindResult<T>
{
   public FindResult(bool found, T result)
   {
       this.Found = found;
       this.Result = result;
   }

   public bool Found { get; private set; }
   // Only valid if Found is true
   public T Result { get; private set;
}

public FindResult<Person> FindPerson(int personId);

...and to be honest you can assume that every .NET programmer knows about the Try... pattern because it's used internally by the .NET framework. That means they don't have to read the documentation to understand what it does, which is more important to me than sticking to some purist's view of functions (understanding that result is an out parameter, not a ref parameter).

So I'd go with TryFindPerson because you seem to indicate it's perfectly normal to be unable to find it.

If, on the other hand, there's no logical reason that the caller would ever provide a personId that didn't exist, I would probably do this:

public Person GetPerson(int personId);

...and then I'd throw an exception if it was invalid. The Get... prefix implies that the caller knows it should succeed.

22
  • 35
    +1, I would answer this question with a reference to Clean Code if you hadn't already done so. I like the mantra: "IF YOUR FUNCTION CANT DO WHAT IT'S NAME SAYS, THEN THROW AN EXCEPTION." Muuuch better than checking for null every dozen lines or so....
    – GHP
    Commented Nov 17, 2011 at 19:45
  • 13
    I've given up assuming anything about the knowledge of people.
    – CaffGeek
    Commented Nov 17, 2011 at 22:02
  • 5
    "The problem with using null is that the person using the interface doesn't know if null is a possible outcome, and whether they have to check for it, because there's no not null reference type." Since reference types can be null, can't you always assume that null is a possible outcome? Commented Nov 18, 2011 at 10:52
  • 8
    "The problem with using null is that the person using the interface doesn't know if null is a possible outcome, and whether they have to check for it, [...]" If a method might return null, it should be explicitly mentioned as part of the API contract. Commented Nov 18, 2011 at 12:22
  • 6
    @Laiv - that's a really naïve thing to say. The reason we follow patterns is to make it easy for people to use our stuff without reading documentation. Writing an API is like designing a user interface, and one of the most popular user interface design books is titled "Don't Make me Think." When possible, make it so nobody has to read the documentation. Commented May 6, 2016 at 10:00
35

You could try Martin Fowler's Special Case pattern, from Paterns of Enterprise Application Architecture:

Nulls are awkward things in object-oriented programs because they defeat polymorphism. Usually you can invoke foo freely on a variable reference of a given type without worrying about whether the item is the exact type or a sub-class. With a strongly typed language you can even have the compiler check that the call is correct. However, since a variable can contain null, you may run into a runtime error by invoking a message on null, which will get you a nice, friendly stack trace.

If it's possible for a variable to be null, you have to remember to surround it with null test code so you'll do the right thing if a null is present. Often the right thing is same in many contexts, so you end up writing similar code in lots of places - committing the sin of code duplication.

Nulls are a common example of such problems and others crop up regularly. In number systems you have to deal with infinity, which has special rules for things like addition that break the usual invariants of real numbers. One of my earliest experiences in business software was with a utility customer who wasn't fully known, referred to as "occupant." All of these imply altering the usual behavior of the type.

Instead of returning null, or some odd value, return a Special Case that has the same interface as what the caller expects.

1
  • I ran into this scenario, but only after the software was released. My test data never triggered it, so it was a bit out of the blue and a pain to debug. Though I didn't solve it with the Special Case pattern, it's good to be aware of it.
    – samus
    Commented Mar 6, 2017 at 18:05
18

I would think ReverseString() would return the reversed string and it would throw an IllegalArgumentException if passed in a Null.

I think FindPerson() should follow the NullObject Pattern or raise an unchecked exception about not finding something if you should always be able to find something.

Having to deal with Null is something that should be avoided. Having Null in languages has been called a Billion Dollar Mistake by it's inventor!

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W).

My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement.

This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

In recent years, a number of program analysers like PREfix and PREfast in Microsoft have been used to check references, and give warnings if there is a risk they may be non-null. More recent programming languages like Spec# have introduced declarations for non-null references. This is the solution, which I rejected in 1965.

Tony Hoare

13

Return an Option. All the benefits of returning a different invalid value (like being able to have empty values in your collections) without any risk of NullPointerException.

3
  • 1
    Interesting. How to implement an option in Java? And in C++?
    – Giorgio
    Commented Nov 18, 2011 at 12:17
  • 1
    @Giorgio, For Java, the Guava libraries, from Google, have a class called Optional. Commented Nov 18, 2011 at 16:30
  • 1
    For C++, there's boost::optional<T>
    – MSalters
    Commented Jan 12, 2012 at 15:33
10

I see both sides of this argument, and I realize some rather influential voices (e.g., Fowler) advocate not returning nulls in order to keep code clean, avoid extra error-handling blocks, etc.

However, I tend to side with proponents of returning null. I find there is an important distinction in invoking a method and it responding with I don't have any data and it responding with I have this empty String.

Since I've seen some of the discussion referencing a Person class, consider the scenario where you attempt to look up an instance of the class. If you pass in some finder attribute (e.g., an ID), a client can immediately check for null to see if no value was found. This is not necessarily exceptional (hence not needing exceptions), but it should also be documented clearly. Yes, this requires some rigor on the part of the client, and no, I don't think that's a bad thing at all.

Now consider the alternative where you return a valid Person object... that has nothing in it. Do you put nulls in all of its values (name, address, favoriteDrink), or do you now go populate those with valid but empty objects? How is your client to now determine that no actual Person was found? Do they need to check if the name is an empty String instead of null? Isn't this sort of thing actually going to lead to as much or more code clutter and conditional statements than if we'd just checked for null and moved on?

Again, there are points on either side of this argument I could agree with, but I find this makes the most sense to the most people (making the code more maintainable).

3
  • 1
    The difference is, "does FindPerson or GetPerson return a null or throw an exception if the key doesn't exist?" As a user of the API I just don't know and I have to check the documentation. On the other hand, bool TryGetPerson(Guid key, out Person person) doesn't require me to check the documentation and I know an exception isn't thrown in what amounts to a rather non-exceptional circumstance. That's the point I'm trying to make in my answer. Commented Feb 26, 2014 at 12:57
  • 4
    I think people got too attached to exceptions. Exceptions are bad and resource consuming. Not to mention people do try and catch statements without resolving anything. Exceptions are clear sign that something went fundamentally wrong. For instance, null references throws an exception, because it is clearly wrong to reference null objects. It is wrong to use it to check if person was found or not. Commented May 13, 2014 at 9:17
  • 2
    @VladimirKocjancic: I totally agree: exceptions should be used for exceptional situation, like software bugs, hardware failures, system misconfiguration. If you are computing a partial function (like findPerson) it is absolutely normal to get back no result. This should not lead to an exception.
    – Giorgio
    Commented May 29, 2016 at 8:12
8

Return null if you need to know if the item exists or not. Otherwise, return the expected data type. This is especially true if you're returning a list of items. It's usually safe to assume if the caller is wanting a list, they'll want to iterate over the list. Many (most? all?) languages fail if you try to iterate over null but not when you iterate over a list that is empty.

I find it frustrating to try and use code like this, only to have it fail:

for thing in get_list_of_things() {
    do_something_clever(thing)
}

I shouldn't have to add a special case for the case when there are no things.

2
  • 8
    In cases where a list or other group of values is expected, I always elect to return an empty list, for exactly this reason. The default action (iterating across an empty list) is almost always right, and if it isn't then the caller can explicitly check to see if the list is empty.
    – TMN
    Commented Nov 17, 2011 at 19:03
  • In that case I return a list containing all items that it should return (which may be none), and null in case of an error.
    – gnasher729
    Commented Jan 7 at 17:41
7

null is the best thing to return if and only if the following following conditions apply:

  • the null result is expected in normal operation. It could be expected that you may not be able to find a person in some reasonable circumstances, so findPerson() returning null is fine. However if it is a genuinely unexpected failure (e.g. in a function called saveMyImportantData()) then you should be throwing an Exception. There's a hint in the name - Exceptions are for exceptional circumstances!
  • null is used to mean "not found / no value". If you mean something else, then return something else! Good examples would be floating point operations returning Infinity or NaN - these are values with specific meanings so it would get very confusing if you returned null here.
  • The function is meant to return a single value, such as findPerson(). If it was designed to return a collection e.g. findAllOldPeople() then an empty collection is best. A corollary of this is that a function which returns a collection should never return null.

In addition, make sure that you document the fact that the function can return null.

If you follow these rules, nulls are mostly harmless. Note that if you forget to check for null, you will normally get a NullPointerException immediately afterwards, which is usually a pretty easy bug to fix. This fail fast approach is much better than having a fake return value (e.g. an empty string) which gets quietly propagated around your system, possibly corrupting data, without throwing an exception.

Finally, if you apply these rules to the two functions listed in the question:

  • FindPerson - it would be appropriate for this function to return null if the person was not found
  • ReverseString - seems like it would never fail to find a result if passed a string (since all strings can be reversed, including the empty string). So it should never return null. If something goes wrong (out of memory?) then it should throw an exception.
6

It depends on the semantics of the method. You could possibly specify, your method accepts only "Not null". In Java you can declare that using some metadata annotations:

string ReverseString(@NotNull String stringToReverse)

You should somehow specify the return value. If you declare, you accept only NotNull values, you are bound to return empty string (if the input was empty string too).

The second case is a little bit complicated in its semantics. If this method is to return some person by it's primary key (and the person is expected to exist), better way is to throw exception.

Person FindPerson(int personID)

If you search person by some guessed id (which seems to me odd), you would better declare that method as @Nullable.

3

I would recommend using the Null Object pattern whenever possible. It simplifies the code when calling your methods, and you don't get to read ugly code like

if (someObject != null && someObject.someMethod () != whateverValue)

For instance, if a method returns a collection of objects who fit some pattern, then returning an empty collection makes more sense than returning null, and iterating over this empty collection will have virtually no performance penalty. Another case would be a method that returns the class instance used to log data, returning a Null object rather than null is preferable in my opinion, as it does not force users to always check if the returned reference is null.

In cases where returning null makes sense (calling the findPerson () method for example), I'd try to at least provide a method that returns if the object is present (personExists (int personId) for example), another example would be the containsKey () method on a Map in Java). It makes callers' code cleaner, as you can easily see that there is a possibility that the desired object might not be available (person does not exist, key is not present in map). Constantly checking if a reference is null obfuscates the code in my opinion.

1

Methods returning collections should return empty but others could return null, because for the collections it might so happen that you will have object but there are no elements in it, so the caller will validate for just size rather both.

1

Adding to what people already said about the Maybe type constructor:

Another big gain, apart from not risking NPEs, is the semantic one. In the functional world, where we deal with pure functions, we like to try to make functions that when applied are exactly equivalent to their return value. Consider the case of String.reverse(): This is a function that given a certain string represents the reversed version of that string. We know that this string exists, because every string can be reversed (strings are basically ordered sets of characters).

Now, what about findCustomer(int id)? This function represents the customer that has the given ID. This is something that may or may not exist. But remember, functions have a single return value, so you can't really say "this function returns a customer with the given ID OR it returns null.

This is my main issue both with returning null and returning a null object. They are misleading. null isn't a customer, and it isn't really "the absence of a customer" either. It's the absence of ANYTHING. It's just a typeless pointer to NOTHING. Very low-level and very ugly and very error-prone. A null object is also pretty misleading here I think. A null customer IS a customer. It's not the absence of one, it's not the customer with the ID asked for, so returning it is simply WRONG. This is NOT the customer I asked for, but still you claim you returned a customer. It has the wrong ID, clearly this is a bug. It breaks the contract suggested by the method name and signature. It requires the client code to assume things about your design, or to read documentation.

Both of these issues are solved by a Maybe Customer. Suddenly, we're not saying "this function represents the customer with the given ID". We're saying "this function represents the customer with the given ID if it exists. It's now very clear and explicit about what it does. If you ask for the customer with a non-existing ID, you will receive Nothing. How is this better than null? Not just for the NPE risk. But also because the type of Nothing isn't just Maybe. It's Maybe Customer. It has semantic meaning. It specifically means "the absence of a customer", indicating that such a customer doesn't exist.

Another problem with null is of course that it is ambiguous. Is it that you didn't find the customer, or was there a db connection error or am I just not allowed to see that customer?

If you have several error cases like this to handle, you could either throw exceptions for those versions or (and I prefer this way) you could return an Either CustomerLoadError Customer, representing either something that went wrong or the returned customer. It has all the advantages of Maybe Customer while also allowing you to specify what can go wrong.

The main thing I'm after is to capture the contract of the function in it's signature. Don't assume things, don't rely on fleeting conventions, be explicit.

1

In my opinion there is a difference between returning NULL, returning some empty result (e.g. the empty string or an empty list), and throwing an exception.

I normally take the following approach. I consider a function or method f(v1, ..., vn) call as the application of a function

f : S x T1 x ... x Tn -> T

where S it the "state of the world" T1, ..., Tn are the types of input parameters, and T is the return type.

I first try to define this function. If the function is partial (i.e. there are some input values for which it is not defined) I return NULL to signal this. This is because I want the computation to terminate normally and tell me that the function I have requested is not defined on the given inputs. Using, e.g., an empty string as return value is ambiguous because it could be that the function is defined on the inputs and the empty string is the correct result.

I think the extra check for a NULL pointer in the calling code is necessary because you are applying a partial function and it is the task of the called method to tell you if the function if not defined for the given input.

I prefer to use exceptions for errors that do not allow to carry out the computation (i.e. it was not possible to find any answer).

For example, suppose I have a class Customer and I want to implement a method

Customer findCustomer(String customerCode)

to search for a customer in the application database by its code. In this method, I would

  • Return an object of class Customer if the query is successful,
  • Return null if the query does not find any customer.
  • Throw an exception if it is not possible to connect to the database.

The extra checks for null, e.g.

Customer customer = findCustomer("...");
if (customer != null && customer.getOrders() > 0)
{
    ...
}

are part of the semantics of what I am doing and I would not just "skip them" in order to make the code read better. I do not think it is a good practice to simplify the semantics of the problem at hand just to simplify the code.

Of course, since the check for null occurs very often is it good if the language supports some special syntax for it.

I would also consider using the Null Object pattern (as suggested by Laf) as long as I can distinguish the null object of a class from all other objects.

0

To me there are two cases here. If you're returning some sort of list you should always return the list no matter what, empty if you don't have anything to put in it.

The only case where I see any debate is when you're returning a single item. I find myself preferring to return null in case of failure in such a situation on the basis of making things fail fast.

If you return a null object and the caller needed a real object they might go ahead and try to use the null object producing unexpected behavior. I think it's better for the routine to go boom if they forget to deal with the situation. If something's wrong I want an exception ASAP. You're less likely to ship a bug this way.

0

1) If semantic of function is that it can return nothing, caller MUST test for it, otherwise he will eg. take your money and give it to no-one.

2) Its good to make functions that semantically always return something (or throw).

With a logger, it make sense to return logger that does not log if no logger was defined. When returning collection, it almost never makes sense (except on "low enough level", where the collection itself is THE data, not what it contains) to return nothing, because an empty set is a set, not nothing.

With a person example, I would go "hibernate" way (get vs load, IIRC, but there it is complicated by proxy objects for lazy loading) of having two functions, one that returns null and second that throws.

0

In my experience it might be better to have empty objects, e.g. Person unknownPerson = new Person(); or UnknownPerson implements Person Not sure though how to implement it exactly. Should it be a separate class with the same interface or add the code to the Person class. Currently I am struggling with a simple equalsTo method. The code looks garbage because I have to check if both parameters are null or they have value where I can call equalsTo. I imagine there are countless similar scenarios. So I would rather add an isEmpty method and allow empty parameters instead of using null. I will still have some garbage code, but it would be concentrated to the optional class. Another problem with this approach, that in some scenarios the parameter can be optional, but in other scenarios it can be mandatory. But it is easy to fix that, in the optional scenarios I use Person type, in the non-optional scenarios I use KnownPerson implements Person. At least I'll refactor my code to this after the next commit is done. It appears to be a much better experience in theory. In practice probably it will give too many new classes. So I guess there is no great solution for this, but if I check code rotting, then there is a lot of repetition currently, which means that the code is in the wrong abstraction level.

-1
  • NULL should be returned if the application expects a data to be available but the data is not available. For example, a service that returns the CITY based on zipcode should return null if the city is not found. The caller can then decide to handle the null or blow up.

  • Empty list should be returned if there are two possibilities. Data available or NO data available. For example a service that returns the CITY(s) if the population is greater than certain number. It can return a empty list if No data that satisfies the given criteria.

-1

Returning NULL is a terrible design, in object-oriented world. In a nutshell, NULL usage leads to:

  • ad-hoc error handling (instead of exceptions)
  • ambiguous semantic
  • slow instead of fast failing
  • computer thinking vs. object thinking
  • mutable and incomplete objects

Check this blog post for a detailed explanation: http://www.yegor256.com/2014/05/13/why-null-is-bad.html

Not the answer you're looking for? Browse other questions tagged or ask your own question.