- 37. Do not shadow or obscure identifiers in subscopes
- 38. Do not declare more than one variable per declaration
- 39. Use meaningful symbolic constants to represent literal values in program logic
- 40. Properly encode relationships in constant definitions
- 41. Return an empty array or collection instead of a null value for methods that return an array or collection
- 42. Use exceptions only for exceptional conditions
- 43. Use a try-with-resources statement to safely handle closeable resources
- 44. Do not use assertions to verify the absence of runtime errors
- 45. Use the same type for the second and third operands in conditional expressions
- 46. Do not serialize direct handles to system resources
- 47. Prefer using iterators over enumerations
- 48. Do not use direct buffers for short-lived, infrequently used objects
- 49. Remove short-lived objects from long-lived container objects
41. Return an empty array or collection instead of a null value for methods that return an array or collection
Some APIs intentionally return a null reference to indicate that instances are unavailable. This practice can lead to denial-of-service vulnerabilities when the client code fails to explicitly handle the null return value case. A null return value is an example of an in-band error indicator, which is discouraged by Guideline 52, “Avoid in-band error indicators.” For methods that return a set of values using an array or collection, returning an empty array or collection is an excellent alternative to returning a null value, as most callers are better equipped to handle an empty set than a null value.
Noncompliant Code Example
This noncompliant code example returns a null ArrayList when the size of the Array-List is 0. The class Inventory contains a getStock() method that constructs a list of items that have 0 inventory and returns the list of items to the caller.
class Inventory { private final Hashtable<String, Integer> items; public Inventory() { items = new Hashtable<String, Integer>(); } public List<String> getStock() { List<String> stock = new ArrayList<String>(); Enumeration itemKeys = items.keys(); while (itemKeys.hasMoreElements()) { Object value = itemKeys.nextElement(); if ((items.get(value)) == 0) { stock.add((String)value); } } if (items.size() == 0) { return null; } else { return stock; } } } public class Client { public static void main(String[] args) { Inventory inv = new Inventory(); List<String> items = inv.getStock(); System.out.println(items.size()); } }
When the size of this list is 0, a null value is returned with the assumption that the client will install the necessary checks. In this code example, the client lacks any null value check, causing a NullPointerException at runtime.
Compliant Solution
Instead of returning a null value, this compliant solution simply returns the List, even when it is empty.
class Inventory { private final Hashtable<String, Integer> items; public Inventory() { items = new Hashtable<String, Integer>(); } public List<String> getStock() { List<String> stock = new ArrayList<String>(); Integer noOfItems; // Number of items left in the inventory Enumeration itemKeys = items.keys(); while (itemKeys.hasMoreElements()) { Object value = itemKeys.nextElement(); if ((noOfItems = items.get(value)) == 0) { stock.add((String)value); } } return stock; // Return list (possibly zero-length) } } public class Client { public static void main(String[] args) { Inventory inv = new Inventory(); List<String> items = inv.getStock(); System.out.println(items.size()); } }
The client can handle this situation effectively without being interrupted by runtime exceptions. When returning arrays rather than collections, ensure that the client avoids attempts to access individual elements of a zero-length array. This prevents an ArrayIndexOutOfBoundsException from being thrown.
Compliant Solution
This compliant solution returns an explicit empty list, which is an equivalent permissible technique.
public List<String> getStock() { List<String> stock = new ArrayList<String>(); Integer noOfItems; // Number of items left in the inventory Enumeration itemKeys = items.keys(); while (itemKeys.hasMoreElements()) { Object value = itemKeys.nextElement(); if ((noOfItems = items.get(value)) == 0) { stock.add((String)value); } } if (l.isEmpty()) { return Collections.EMPTY_LIST; // Always zero-length } else { return stock; // Return list } } // Class Client ...
Applicability
Returning a null value rather than a zero-length array or collection may lead to denial-of-service vulnerabilities when the client code fails to handle null return values properly.
Automatic detection is straightforward; fixing the problem typically requires programmer intervention.
Bibliography
[Bloch 2008] |
Item 43, “Return Empty Arrays or Collections, Not Nulls” |