En mi opinión, hay una diferencia entre devolver NULL, devolver un resultado vacío (por ejemplo, la cadena vacía o una lista vacía) y lanzar una excepción.
Normalmente tomo el siguiente enfoque. Considero una función o método f (v1, ..., vn) llamada como la aplicación de una función
f : S x T1 x ... x Tn -> T
donde S es el "estado del mundo" T1, ..., Tn son los tipos de parámetros de entrada y T es el tipo de retorno.
Primero intento definir esta función. Si la función es parcial (es decir, hay algunos valores de entrada para los cuales no está definida) Devuelvo NULL para señalar esto. Esto se debe a que quiero que el cómputo finalice normalmente y me diga que la función que he solicitado no está definida en las entradas proporcionadas. Usar, por ejemplo, una cadena vacía como valor de retorno es ambiguo porque podría ser que la función esté definida en las entradas y la cadena vacía sea el resultado correcto.
Creo que la comprobación adicional para un puntero NULO en el código de llamada es necesaria porque está aplicando una función parcial y es la tarea del método llamado informarle si la función no está definida para la entrada dada.
Prefiero usar excepciones para los errores que no permiten realizar el cálculo (es decir, no fue posible encontrar ninguna respuesta).
Por ejemplo, supongamos que tengo un cliente de clase y quiero implementar un método
Customer findCustomer(String customerCode)
para buscar un cliente en la base de datos de la aplicación por su código.
En este método, me gustaría
- Devuelva un objeto de la clase Cliente si la consulta es exitosa,
- Devuelve nulo si la consulta no encuentra ningún cliente.
- Lanzar una excepción si no es posible conectarse a la base de datos.
Los controles adicionales para nulos, por ejemplo,
Customer customer = findCustomer("...");
if (customer != null && customer.getOrders() > 0)
{
...
}
son parte de la semántica de lo que estoy haciendo y no me limitaría a "omitirlos" para que el código se lea mejor. No creo que sea una buena práctica simplificar la semántica del problema en cuestión solo para simplificar el código.
Por supuesto, dado que la comprobación de nulos ocurre con mucha frecuencia, es bueno si el lenguaje admite alguna sintaxis especial para él.
También consideraría usar el patrón de objeto nulo (como lo sugiere Laf) siempre que pueda distinguir el objeto nulo de una clase de todos los demás objetos.