Why is this an issue?

Returning null instead of an actual array, collection or map forces callers of the method to explicitly test for nullity, making them more complex and less readable.

Moreover, in many cases, null is used as a synonym for empty.

Noncompliant code example

public static List<Result> getAllResults() {
  return null;                             // Noncompliant
}

public static Result[] getResults() {
  return null;                             // Noncompliant
}

public static Map<String, Object> getValues() {
  return null;                             // Noncompliant
}

public static void main(String[] args) {
  Result[] results = getResults();
  if (results != null) {                   // Nullity test required to prevent NPE
    for (Result result: results) {
      /* ... */
    }
  }

  List<Result> allResults = getAllResults();
  if (allResults != null) {                // Nullity test required to prevent NPE
    for (Result result: allResults) {
      /* ... */
    }
  }

  Map<String, Object> values = getValues();
  if (values != null) {                   // Nullity test required to prevent NPE
    values.forEach((k, v) -> doSomething(k, v));
  }
}

Compliant solution

public static List<Result> getAllResults() {
  return Collections.emptyList();          // Compliant
}

public static Result[] getResults() {
  return new Result[0];                    // Compliant
}

public static Map<String, Object> getValues() {
  return Collections.emptyMap();           // Compliant
}

public static void main(String[] args) {
  for (Result result: getAllResults()) {
    /* ... */
  }

  for (Result result: getResults()) {
    /* ... */
  }

  getValues().forEach((k, v) -> doSomething(k, v));
}

Resources