There seem to be two cases where developers use this pattern. The first case is the developer learns about action methods for the first time, and is led to believe they must use a PageReference return type for the function to work, since nearly all tutorials seem to do this. The second case is where a developer does this because they want to have the return type already set "just in case they need it later."
The truth is, this is a bad practice, and should be avoided. First, many developers come to rely on the method's return type to quickly figure out what the method's output will be. Seeing a return type of PageReference will trick developers into thinking a possible redirect could occur. This later gets codified into test methods, and so becomes reinforced.
It might not seem like a big deal when there are only five lines of code, but if a method contains two hundred lines of code, it becomes difficult to diagnose when something needs to be fixed. Or, a later developer might break something, assuming the return type is intentional, and changes the null to some PageReference.
There is no valid use for this anti-pattern, and you should never return a value when the result is always null. This also applies to other types of methods; never return a type if you only intend to return null.
Nulls are being rendered in the latest JSON (32.0/33.0). You must explicitly the set the value to null for it to work. Consider the following code:
Account a = new Account(Name='test',Industry=null);
System.debug(LoggingLevel.ERROR, JSON.serialize(a));
Output:
{"attributes":{"type":"Account"},"Name":"test","Industry":null}
If you need every single field, you'll have to do something like:
Account a = new Account();
for(SObjectField f: account.sobjecttype.getdescribe().fields.getmap().values()) {
try { a.put(f, null); } catch(exception e) { }
}
Even better, you could always just use a Map, which avoids the errors of field editability:
Map<String, Object> a = new Map<String, Object>();
SObject b = [SELECT Id, Name FROM Account LIMIT 1];
for(SObjectField f: account.sobjecttype.getdescribe().fields.getmap().values()) {
try { a.put(String.valueOf(f), b.get(f)); }
catch(Exception e) { a.put(String.valueOf(f), null); }
}
System.debug(logginglevel.error, json.serialize(a));
I've just tried this code in executeAnonymous and came up with fully realized JSON. Note that I use a try-catch here because queried SObjects generate errors for missing fields. If you're using a manually constructed SObject, you'll not have to worry about catching errors.
Finally, note that executeAnonymous tends to always run in the latest version. You won't normally see differences in execution contexts because the entire transaction is set to version 32.0 mode when running executeAnonymous. To emulate a lower version, you'd have to write a Visualforce page and set the version of the page to a lower value, and then also set the controller's version to that lower value, etc...
Alternatively, you could write a REST class, and call that REST function. That should also set the version correctly. Since executeAnonymouse is basically an eval(), it tends to behave in the latest version, because it has to be compiled on demand.
Best Answer
The results of a query are never null. An individual record at a given index in the results list will also never be null. Individual fields, however, can be null if they contain no data. If there are no leads the database, the first and second example are basically the same, except that one uses a query towards the governor limit.
Also,
leadList2
is not an "empty string" (this has a specific meaning, namely an Object that is a String with a size of exactly zero). It simply happens to be rendered as an empty list viaString.valueOf
for debugging purposes.leadList1
andleadList2
, in this example, are equal to each other (leadList1 == leadList2
).Edit: It's also not correct to say that you have a null list. A list is never null. The variable might be null, but a list itself is not null. Null is just null, and also has a specific intrinsic meaning. The following code demonstrates that there's no difference between a variable that's an uninitialized List versus an uninitialized Integer.
By casting both variables to a common Object, we can see that null is always null, because it does not have a "type" in the common sense that other objects have types. There's no difference between a "null list" and a "null number".