11

I'm in a bit of a disagreement with a more experienced developer on this issue, and wondering what others think about it; our environment is Java, EJB 3, services, etc.

The code I wrote calls a service to get things and to create things. The problem I ran into was that I got null pointer exceptions that didn't make sense. For example, when I ask the service to create an object, I get null back; when I try to look up an object with a known valid ID, I get null back. I spent some time trying to figure out what was wrong in my code; since I'm less experienced I usually assume I've done something wrong, but it turns out the reason for the null returns was security. If the user principal using my service didn't have the right permissions for the target service, then it simply returns null. Most other services here aren't documented very well either, so apparently this is just something you have to know.

This is rather confusing as a developer writing code that interacts with the service. It would make much more sense to me if the service thew an exception that would tell me that the user didn't have the proper permissions to load this thing or to create that thing; I would then immediately know why my service wasn't working as expected.

The more experienced developer who wrote the service argued that asking for the data is not an error condition, and that exceptions should only be thrown in an error condition, not when the user doesn't have access to the data. This data is often looked up in a GUI, and for those users without the right permissions, these things simply "do not exist". So, in short: asking is not wrong, hence no exception. Get methods return null because to those users those things "don't exist". Create methods return null when the user wasn't allowed to create that thing.

Is this normal and/or good practice? I prefer using exceptions because I find it much easier to know what's going on. So I would for example also prefer to throw a NotFoundException if you asked for an object with an invalid ID, rather than returning null.

7
  • 6
  • @ChrisF: 1) is about people shunning null references, which I don't. In many cases they are appropriate, I just don't think they are in this one. 2) is about checking parameters, and wouldn't an assert sort of result in the same as throwing an exception? 3) exceptions vs error codes is also a different issue as they are both ways of "showing" what went wrong. Error codes are appropriate if for example you need to notify a system which doesn't support exceptions or if you don't want the end-user to see anything else than a code.
    – Svish
    Nov 24, 2011 at 15:09
  • The issue I ask about here is about "pretending something doesn't exist or didn't happen" vs "telling why something doesn't exist or didn't happen".
    – Svish
    Nov 24, 2011 at 15:10
  • 3
    I didn't suggest they were duplicates - just that they might have useful information for you.
    – ChrisF
    Nov 24, 2011 at 15:15
  • True, sorry about that! Took it as a "possible duplicates" comment for some reason... probably because of lack of sleep, hehe.
    – Svish
    Nov 24, 2011 at 15:27

10 Answers 10

19

Exceptions should only be thrown when there is an error and asking for a thing is not an error.

Asking for a thing may not be an error, but not having permissions to something you asked for is surely some sort of error. Exceptions are an alternative way of reporting exceptional conditions, to be used instead of special return values (such as null, which, as you wrote, is of absolutely no help if there are > 1 possible reasons why things could go awry (even if there is exactly 1 possible reason now, there could be 2 possible reasons in the next version, so using null as a return value indicating failure would be painting yourself into corner)). If the service doesn't report in any way why it won't do what you asked for, then it's definitely bad design.

Whether to use a special return value (e.g. negative integers are useful for functions that normally return a nonnegative integer), an exception, a global error handler or logger etc., is an implementation detail in the end. The choice depends on the language, on the situation, on conventions, and is also a question of taste. The main point is that there should be some direct way of finding out why something doesn't work. Otherwise your only option is to trash around with different options and whatever to find out what correlates with the black box's behavior, and it's waste of time.

String.substring() throws an IndexOutOfBoundsException if the index is out of bounds. I can't think of any advantages to returning null instead, even though - philosophically - one could argue that a String doesn't contain anything outside its bounds, so null would be a logical return value then. Being logical-philosophical and being practical are obviously two different animals.

7
  • If substring() is going to return a value for out-of-bounds indexes, it should return the part of the string between the indexes, possibly empty. That could save a test in some calling code. Nov 24, 2011 at 16:49
  • 2
    Yes, there's this never-ending "empty value" vs. null -discussion: should the substring for out-of-bound indexes be null, or an empty string? I don't know, both are effectively "nothing" (well, maybe null is "more nothing" than an empty string?), but neither gives the amount of information that an exception does. Nov 25, 2011 at 7:24
  • @kevincline: Unless one is using a framework where a null reference is an idiomatic means of indicating an empty string, I don't see any basis for substring to return a null reference. IMHO, there should be two separate functions--one of which promises to either return the requested number of characters or throw an exception, and one of which returns as much as it can. Each method would be substantially superior to the other in some contexts.
    – supercat
    Jan 8, 2013 at 18:22
  • @supercat: I didn't say anything about returning null. I said 'return ... the part ... possibly empty'. An empty string is not null, except to Oracle. Jan 8, 2013 at 23:41
  • @JoonasPulakka: I should have pinged you to my previous comment.
    – supercat
    Jan 9, 2013 at 1:22
5

It comes down to what the contract is. If your contract says you can request something that doesn't exist, it should say what happens (null, or null object).

On the other hand, if your contract says you should call a different method first (DoesSomethingExist()) and then call the Get method, then your contract might say that you can only get things that do exist, and throw an exception if they don't. The exception message could say something like, "Make sure to call DoesSomethingExist() first" which is a useful error message.

1
  • In this case I would say it's not normal to ask for something which doesn't exist, as you probably would not ask for an id which doesn't exist. Usually you would have first gotten a list of things and then look up a particular one of those for more details. So if there was a findAllThings method, then I would say it is appropriate to return an empty list or a subset if there are some or all things you are not allowed to see. In the same way I might on a blog only list posts for editing belonging to the current user. But if that user then tried to tweak the url and edit a different post...
    – Svish
    Nov 24, 2011 at 15:15
4

There is no single one-size-fits-all answer to the question. Whether to use exceptions or return null depends on the situation.

Instead of looking at this purely from a dogmatic point of view, look at the interface as a user interface. User interfaces should be usable. So regardless of your own opinions on the "right" way to do something, pick the method that is the most usable from the perspective of someone using your interface.

If the caller needs to know why an object isn't being returned, an exception is appropriate. If, however, the general concept is "if you don't have permission, it doesn't exist", the null is acceptable.

Specifically in your case, I'd say nulls are perfectly acceptable for looking up an item if the caller is first required to log in or connect to the server. That is when you would be told that you do or don't have permission. Once you get past the gate it's reasonable that when you search for something you don't have permission to see (or even know it exists), you should get a null.

If, on the other hand, you have no initial connection or login step, an exception makes sense. If the caller knows an item exists and they aren't getting it back, the API isn't being helpful to just return a null.

For creating an item, however, that's a different story. Presumably there could be a lot of reasons for that to fail -- no permissions, bad parameters, server out of memory, etc. If the developer is given a null for all those conditions, they have no way to determine a proper course of action.

So, to answer the question, ask yourself what the most usable solution is from the perspective of someone using the service. It may be that the way you are using it is atypical, and for the most common case a null is the right answer.

So, don't get into a religious war over this, decide what's right for this particular problem.

3
  • Not planning on putting on battle gear over this, hehe. Was just curious to know if I was completely wrong in thinking what I was thinking or not. I want to learn, but I don't like to jump to something just because one person says so. And especially not if it goes against my own experience and logic (no matter how small). Anyways, I totally agree that if this was an end-user interface then that could indeed make sense. However, since this is a bean which, as far as I know, can only be accessed by code, I would say that I, as a developer, is the user.
    – Svish
    Nov 24, 2011 at 14:49
  • 1
    And as a developer I do care about why something is wrong, irregardless of what the end-user should get to know about it.
    – Svish
    Nov 24, 2011 at 14:54
  • Fully agree with Bryan. Even develpers are users, ie of consuming some other developers code. Descisions of throw or null is a kind of interface/gui that should be helpful for the specific task. Not just by the general term of logic or philosophy. Nov 24, 2011 at 16:43
3

I definitely think it is a bad design. Null-pointer is not a valid answer to me and it can be tricky to manage.

If the user tries to connect a service without the proper credential, I should reply with a clear and concise answer. The answer could be an exception or a special object but not null.

You should leave the null answer when the network link is broken or other unexpected critical malfunction.

Furthermore, the time you spend understanding why you got a null is a strong argument. Any piece of code should be easy to understand and use. Having a null value is not the case.

6
  • By your last sentence, do you mean "You should return null only when the network link is broken etc." or "You should stop returning null when the network link is broken etc." ? Nov 24, 2011 at 14:03
  • @Péter Török: I do not recommend the explicit use of "return null;". However when a major breakdown happens, it is acceptable for some service to return null.
    – Amine
    Nov 24, 2011 at 14:32
  • Wouldn't an exception be more appropriate if an unexpected critical malfunction happened?
    – Svish
    Nov 24, 2011 at 14:57
  • 2
    @Amine: I'd say that that's the least appropriate case for which to return null. Nov 24, 2011 at 14:58
  • @Svish: if you can detect the major breakdown, of course an exception will be great.
    – Amine
    Nov 24, 2011 at 14:59
3

Bearing good software design in mind, you should think about the life of your project.
By returning null, as it has been said, you do not give any information to the client. Look what happend to you, at first you did not realize where the problem was. Moreover, if no documentation is given, this is a mess.

By throwing an exception, you can tell what went wrong. You can even customize the displayed text to be more specific if you want to.

On the other hand, by returning null you make the client investigate what it is going on.

Furthermore, you realized that there was a problem because you got elsewhere a NullPointerException. Now imagine you do not store the return of that function... You will be forced to surround each call to that function with an if else block...

From my point of view, returning null is a bad practice.

2

The more experienced developer who wrote the service argued that asking for the data is not an error condition, and that exceptions should only be thrown in an error condition, not when the user doesn't have access to the data.

From my point of view, this makes no sense.

Querying for data without permission should result in an exception, because it is an unexpected result - to get no result - without proper access.

Analogy: The responsecode for a GET without authorization is not 200 ok with no data, it's actually 401 Unauthorized.

1

Returning null isn't great. It tells you nothing. To take your example, if an app is trying to look something up and the response is null for both security problems and if the item doesn't exist, then how do you tell the difference between the two?

A meaningful response may allow the application to make logical choices about what to do next or how to resolve problems.

3
  • You ask how do you tell the difference between an object not there, and you lacking permission to see it. Maybe the design of the system requires that you don't know. I don't think we have enough information to answer in this specific case, and there is no answer that works in all cases. There are perfectly valid use cases where, if you can't see it it's effectively not there. And, there are use cases where if you can't see it you should be given an exception to say why you cannot. Nov 24, 2011 at 14:07
  • What do you mean by "the design of the system requires that you don't know"? What kind of design could that be?
    – Svish
    Nov 24, 2011 at 14:55
  • 2
    If the security policy says you're not allowed to see it, then in most cases you shouldn't be able to know that it exists, either. That makes returning "not found" perfectly acceptable.
    – Blrfl
    Nov 24, 2011 at 15:27
1

If the root cause is an unauthenticated user then I prefer a hard HTTP 401 response perhaps with a redirect to a pretty-message-page (and a notification to someone that cares). Authorization-related causes are more case-by-case; there are arguments for returning HTTP errors (403, say) and arguments for returning special well-formed codes/messages in the service response.

Exceptions should only be used in exceptional cirumstances and mean that something has gone wrong. I disagree that they should be overloaded to mean "not allowed". (The same is true for the null return value: I disagree that it should be used to mean "not allowed".)

2
  • Well, in the GUI you could do this, but as for the bean implementing the service which does things behind the scenes you only have exceptions and special return values at your disposal. I of course don't mean that the user should get the exception, but the exception could for example be caught in the web service/servlet/whatever and then do what's appropriate. Redirect to somewhere, hard http 4xx page, or something else.
    – Svish
    Nov 24, 2011 at 14:41
  • Good point, but you could employ a paradigm like AOP to capture these cases. The Aspect could test for the privilege to call a given operation and redirect/allow processing to continue as appropriate.
    – Mark
    Nov 24, 2011 at 15:22
0

To play devils advocate I will attempt to take the side of returning null.

In my opinion there is just one situation where this kind of response is nearly acceptable and that is, as in this case, when security is involved.

It is very easy to accidentally give away details of your system that unauthorized people should not know about. This should be avoided.

Take, for example, a user name and password checker. Returning a "User name not found" error and a "Wrong password" error as separate error codes would obviously open you up to serious security issues as someone could first look for a valid user name and then look for a password. Returning a generic "Invalid username/password" would be a better option.

Thus, In this particular case I would say that it is almost ok to return null but I agree, it would be very unpleasant to work with.

4
  • Yeah, I would disagree. The proper response there would in my opinion be an exception, but the same one for both username not found and wrong password. FailedToLogin, InvalidCredentials, whatever.
    – Svish
    Nov 30, 2011 at 10:13
  • @Svish - But if you are trying to give no hints at all as to the reason for the the failure then returning null is exactly the least helpful response. Almost anything else could potentially be used to discover something about the system. The reason OP complained was because not only did the null return explain nothing it was even unhelpful. That is the deliberate aim ... to say absolutely nothing and to be unhelpful. Mission accomplished in my view. Nov 30, 2011 at 10:44
  • Well, that might be so, but I'd still say that doing that is bad. At least inside a system. On the edges where the end-user see things, then sure, I may agree. But inside the system, we developers are the users, and why in the world would we want to make things more confusing for ourselves? As if developing software isn't hard enough already...
    – Svish
    Nov 30, 2011 at 11:03
  • 1
    And with the login example, I'd say it's bad for the user experience to not at least say something about why nothing seemed to happened when they (thought they) entered their credentials. If the page just refreshes and it seemed like it just ignored my attempt to log in, I will assume something is wrong with the system, not that what I entered was wrong.
    – Svish
    Nov 30, 2011 at 11:04
-2

I think return null is unfriendly, when the client invoke this method and return null, the client do not know what happened and why it returned null. So we should be throw execption which is make sense and provide a documentation to descrip this execption.

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