I agree with what seems to be the consensus here (return null if "not found" is a normal possible outcome, or throw an exception if the semantics of the situation require that the object always be found).
There is, however, a third possibility that might make sense depending on your particular situation. Your method could return a default object of some sort in the "not found" condition, allowing calling code to be assured that it will always receive a valid object without the need for null checking or exception catching.
Cleaner control flow in your calling code. Checking for null injects a conditional branch which is natively handled by try/catch. Checking for null doesn't indicate what it is you're checking for - are you checking for null because you're looking for an error you're expecting, or are you checking for null so you don't pass it further on downchain?
Removes ambiguity of what "null" means. Is null representative of an error or is null what is actually stored in the value? Hard to say when you only have one thing to base that determination off of.
Improved consistency between method behavior in an application. Exceptions are typically exposed in method signatures, so you're more able to understand what edge cases the methods in an application account for, and what information your application can react to in a predictable manner.
As a general rule, if the method should always return an object, then go with the exception. If you anticipate the occasional null and want to handle it in a certain way, go with the null.
Whatever you do, I highly advise against the third option: Returning a string that says "WTF".
Don't think anyone mentioned the overhead in exception handling - takes additional resources to load up and process the exception so unless its a true app killing or process stopping event (going forward would cause more harm than good) I would opt for passing back a value the calling environment could interpret as it sees fit.
If you are using a library or another class which throws an exception, you should rethrow it. Here is an example. Example2.java is like library and Example.java uses it's object. Main.java is an example to handle this Exception. You should show a meaningful message and (if needed) stack trace to the user in the calling side.
Main.java
public class Main {
public static void main(String[] args) {
Example example = new Example();
try {
Example2 obj = example.doExample();
if(obj == null){
System.out.println("Hey object is null!");
}
} catch (Exception e) {
System.out.println("Congratulations, you caught the exception!");
System.out.println("Here is stack trace:");
e.printStackTrace();
}
}
}
Example.java
/**
* Example.java
* @author Seval
* @date 10/22/2014
*/
public class Example {
/**
* Returns Example2 object
* If there is no Example2 object, throws exception
*
* @return obj Example2
* @throws Exception
*/
public Example2 doExample() throws Exception {
try {
// Get the object
Example2 obj = new Example2();
return obj;
} catch (Exception e) {
// Log the exception and rethrow
// Log.logException(e);
throw e;
}
}
}
Example2.java
/**
* Example2.java
* @author Seval
*
*/
public class Example2 {
/**
* Constructor of Example2
* @throws Exception
*/
public Example2() throws Exception{
throw new Exception("Please set the \"obj\"");
}
}
If returning a collection, avoid returning null, return an empty collection which makes enumeration easier to deal with without a null check first.
Several .NET API's use the pattern of a thrownOnError parameter which gives the caller the choice as whether it is really an exceptional situation or not if the object is not found. Type.GetType is an example of this. Another common pattern with BCL is the TryGet pattern where a boolean is returned and the value is passed via an output parameter.
You could also consider the Null Object pattern in some circumstances which can either be a default or a version with no behaviour. The key is avoid null checks throughout the code base. See here for more information http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx
I agree with what seems to be the consensus here (return null if "not found" is a normal possible outcome, or throw an exception if the semantics of the situation require that the object always be found).
There is, however, a third possibility that might make sense depending on your particular situation. Your method could return a default object of some sort in the "not found" condition, allowing calling code to be assured that it will always receive a valid object without the need for null checking or exception catching.
Advantages of throwing an exception:
For more explanation with examples, see: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/
As a general rule, if the method should always return an object, then go with the exception. If you anticipate the occasional null and want to handle it in a certain way, go with the null.
Whatever you do, I highly advise against the third option: Returning a string that says "WTF".
Don't think anyone mentioned the overhead in exception handling - takes additional resources to load up and process the exception so unless its a true app killing or process stopping event (going forward would cause more harm than good) I would opt for passing back a value the calling environment could interpret as it sees fit.
If you are using a library or another class which throws an exception, you should rethrow it. Here is an example. Example2.java is like library and Example.java uses it's object. Main.java is an example to handle this Exception. You should show a meaningful message and (if needed) stack trace to the user in the calling side.
Main.java
Example.java
Example2.java
Here are a couple more suggestions.
If returning a collection, avoid returning null, return an empty collection which makes enumeration easier to deal with without a null check first.
Several .NET API's use the pattern of a thrownOnError parameter which gives the caller the choice as whether it is really an exceptional situation or not if the object is not found. Type.GetType is an example of this. Another common pattern with BCL is the TryGet pattern where a boolean is returned and the value is passed via an output parameter.
You could also consider the Null Object pattern in some circumstances which can either be a default or a version with no behaviour. The key is avoid null checks throughout the code base. See here for more information http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx