try traducir sale practices porque pointer handling custom catch best exception error-handling null

traducir - porque sale null pointer exception



¿Debería un método de recuperación devolver ''nulo'' o lanzar una excepción cuando no puede producir el valor de retorno? (30)

Tengo un método que se supone que devuelve un objeto si se encuentra.

Si no se encuentra, debo:

  1. retorno nulo
  2. lanzar una excepción
  3. otro

Aquí hay un par de sugerencias más.

Si devuelve una colección, evite devolver un valor nulo, devuelva una colección vacía, lo que hace que la enumeración sea más fácil de manejar sin un control nulo primero.

Varias API de .NET utilizan el patrón de un parámetro thrownOnError que le da a la persona que llama la opción de si realmente es una situación excepcional o no si no se encuentra el objeto. Type.GetType es un ejemplo de esto. Otro patrón común con BCL es el patrón TryGet donde se devuelve un valor booleano y el valor se pasa a través de un parámetro de salida.

También puede considerar el patrón de Objeto nulo en algunas circunstancias, que puede ser un valor predeterminado o una versión sin comportamiento. La clave es evitar las comprobaciones nulas en todo el código base. Consulte aquí para obtener más información http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx


Como regla general, si el método siempre debe devolver un objeto, vaya con la excepción. Si anticipa el nulo ocasional y quiere manejarlo de cierta manera, vaya con el nulo.

Hagas lo que hagas, te recomiendo que no realices la tercera opción: devolver una cadena que diga "WTF".


Depende de lo que signifique que no se encuentra el objeto.

Si es un estado normal de cosas, devuelve nulo. Esto es algo que puede suceder de vez en cuando, y las personas que llaman deben buscarlo.

Si es un error, entonces lance una excepción, las personas que llaman deben decidir qué hacer con la condición de error del objeto faltante.

En última instancia, cualquiera funcionaría, aunque la mayoría de las personas generalmente considera una buena práctica usar solo Excepciones cuando algo, bueno, Excepcional ha ocurrido.


Desafortunadamente, JDK es inconsistente, si intenta acceder a una clave no existente en el paquete de recursos, no obtiene una excepción y cuando solicita un valor del mapa, obtiene un valor nulo si no existe. Así que cambiaría la respuesta del ganador a la siguiente, si el valor encontrado puede ser nulo, luego generar una excepción cuando no se encuentre, de lo contrario, devuelva nulo. Entonces, siga la regla con una excepción, si necesita saber por qué no se encuentra el valor, siempre genere la excepción, o ...


Devuelva un nulo en lugar de lanzar una excepción y documente claramente la posibilidad de un valor de retorno nulo en la documentación de la API. Si el código de llamada no respeta la API y busca el caso nulo, lo más probable es que resulte en algún tipo de "excepción de puntero nulo" de todos modos :)

En C ++, puedo pensar en 3 tipos diferentes de configuración de un método que encuentra un objeto.

Opción A

Object *findObject(Key &key);

Devuelve nulo cuando no se puede encontrar un objeto. Agradable y sencillo. Yo iría con este. Los enfoques alternativos a continuación son para las personas que no odian a los extraños.

Opción B

void findObject(Key &key, Object &found);

Pase una referencia a la variable que recibirá el objeto. El método arrojó una excepción cuando no se puede encontrar un objeto. Esta convención probablemente sea más adecuada si realmente no se espera que no se encuentre un objeto; por lo tanto, se lanza una excepción para indicar que se trata de un caso inesperado.

Opción C

bool findObject(Key &key, Object &found);

El método devuelve false cuando no se puede encontrar un objeto. La ventaja de esto sobre la opción A es que puede verificar el caso de error en un paso claro:

if (!findObject(myKey, myObj)) { ...


Devuelve un valor nulo, las excepciones son exactamente eso: algo que tu código hace que no se espera.


En algunas funciones agrego un parámetro:

..., bool verify = true)

Verdadero significa lanzar, falso significa devolver algún valor de error de retorno. De esta manera, quien use esta función tiene ambas opciones. El valor predeterminado debe ser verdadero, para el beneficio de aquellos que se olvidan del manejo de errores.


En general, debe devolver nulo. El código que llama al método debe decidir si lanzar una excepción o intentar algo más.


Eso realmente depende de si esperas encontrar el objeto, o no. Si sigue la escuela de pensamiento que deben usarse excepciones para indicar algo, bueno, err, excepcional ha ocurrido entonces:

  • Objeto encontrado devolver objeto
  • Objeto no encontrado; lanzar excepción

De lo contrario, devuelve nulo.


Estoy de acuerdo con lo que parece ser el consenso aquí (devolver un valor nulo si "no se encuentra" es un posible resultado normal, o lanzar una excepción si la semántica de la situación requiere que el objeto siempre se encuentre).

Sin embargo, existe una tercera posibilidad que podría tener sentido dependiendo de su situación particular. Su método podría devolver un objeto predeterminado de algún tipo en la condición "no encontrado", permitiendo que el código de llamada tenga la seguridad de que siempre recibirá un objeto válido sin la necesidad de verificación nula o captura de excepción.


Las excepciones deben ser excepcionales . Devuelve nulo si es válido devolver un nulo .


Las excepciones están relacionadas con el diseño por contrato.

La interfaz de un objeto es en realidad un contrato entre dos objetos, la persona que llama debe cumplir el contrato o el receptor puede fallar con una excepción. Hay dos posibles contratos.

1) todas las entradas del método son válidas, en cuyo caso debe devolver un valor nulo cuando no se encuentra el objeto.

2) solo una entrada es válida, es decir, la que resulta en un objeto encontrado. En cuyo caso, DEBE ofrecer un segundo método que permita a la persona que llama determinar si su entrada será correcta. Por ejemplo

is_present(key) find(key) throws Exception

¡SI Y SOLAMENTE SI proporciona ambos métodos del segundo contrato, puede lanzar una excepción si no se encuentra nada!


No piense que nadie mencionó la sobrecarga en el manejo de excepciones: requiere recursos adicionales para cargar y procesar la excepción, por lo que, a menos que sea un evento de detención de la aplicación o de detención del proceso real (seguir adelante causaría más daño que bien) optaría por devolver una Valorar el entorno que llama podría interpretar como mejor le parezca.


O devolver una opción

Una opción es básicamente una clase de contenedor que obliga al cliente a manejar los casos de stand. Scala tiene este concepto, busca su API.

Luego tiene métodos como T getOrElse (T valueIfNull) en este objeto para devolver el objeto encontrado o una alternativa a las especificaciones del cliente.


Prefiero devolver solo un valor nulo y confiar en la persona que llama para manejarlo adecuadamente. La excepción (por falta de una palabra mejor) es si estoy absolutamente "seguro" de que este método devolverá un objeto. En ese caso un fallo es un excepcional debe y debe tirar.


Prefiero volver nulo -

Si la persona que llama lo usa sin verificar, la excepción ocurre allí mismo de todos modos.

Si la persona que llama realmente no lo usa, no le cobres impuestos por un bloque try / catch


Sea consistente con la API (s) que está utilizando.


Si el método devuelve una colección, devuelva una colección vacía (como se dijo anteriormente). Pero por favor, no colecciones.EMPTY_LIST o tal! (en caso de Java)

Si el método recupera un solo objeto, entonces tiene algunas opciones.

  1. Si el método siempre debe encontrar el resultado y es un caso de excepción real no encontrar el objeto, entonces debe lanzar una excepción (en Java: por favor, una Excepción no verificada)
  2. (Solo Java) Si puede tolerar que el método arroje una excepción marcada, lance una excepción ObjectNotFoundException específica del proyecto o similar. En este caso, el compilador le dice si olvida manejar la excepción. (Este es mi manejo preferido de cosas no encontradas en Java).
  3. Si dice que está realmente bien, si el objeto no se encuentra y su nombre de Método es como findBookForAuthorOrReturnNull (..), entonces puede devolver el valor nulo. En este caso, se recomienda encarecidamente utilizar algún tipo de comprobación estática o compilación, que evite la desreferenciación del resultado sin una comprobación nula. En el caso de Java puede ser por ejemplo. FindBugs (vea DefaultAnnotation en http://findbugs.sourceforge.net/manual/annotations.html ) o IntelliJ-Checking.

Ten cuidado, si decides devolver un nulo. Si no es el único programador en el proyecto, obtendrá NullPointerExceptions (en Java o lo que sea en otros idiomas) en tiempo de ejecución. Así que no devuelvas valores nulos que no se verifican en el momento de la compilación.


Si es importante que el código del cliente sepa la diferencia entre lo que se encuentra y lo que no se encuentra y se supone que este es un comportamiento de rutina, entonces es mejor devolver el valor nulo. El código del cliente puede decidir qué hacer.


Si está utilizando una biblioteca u otra clase que lanza una excepción, debe volver a lanzarla . Aquí hay un ejemplo. Example2.java es como una biblioteca y Example.java usa su objeto. Main.java es un ejemplo para manejar esta excepción. Debe mostrar un mensaje significativo y (si es necesario) un seguimiento de la pila para el usuario en el lado de la llamada.

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(); } } }

Ejemplo.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; } } }

Ejemplo2.java

/** * Example2.java * @author Seval * */ public class Example2 { /** * Constructor of Example2 * @throws Exception */ public Example2() throws Exception{ throw new Exception("Please set the /"obj/""); } }


Si null nunca indica un error, simplemente devuelve null.

Si nulo siempre es un error, entonces lanza una excepción.

Si nulo es a veces una excepción, codifique dos rutinas. Una rutina lanza una excepción y la otra es una rutina de prueba booleana que devuelve el objeto en un parámetro de salida y la rutina devuelve un falso si no se encontró el objeto.

Es difícil hacer mal uso de una rutina de prueba. Es muy fácil olvidarse de comprobar si hay null.

Así que cuando nulo es un error simplemente escribes

object o = FindObject();

Cuando el nulo no es un error puedes codificar algo como

if (TryFindObject(out object o) // Do something with o else // o was not found


Si siempre está esperando encontrar un valor, lance la excepción si falta. La excepción significaría que había un problema.

Si el valor puede faltar o estar presente y ambos son válidos para la lógica de la aplicación, devuelva un valor nulo.

Más importante: ¿Qué haces en otros lugares en el código? La consistencia es importante.


Siempre que se suponga que devuelva una referencia al objeto, devolver un valor NULL debería ser bueno.

Sin embargo, si está devolviendo todo el asunto sangriento (como en C ++ si lo hace: ''return blah;'' en lugar de ''return & blah;'' (o ''blah'' es un puntero), entonces no puede devolver un NULL, porque es No es del tipo ''objeto''. En ese caso, lanzar una excepción o devolver un objeto en blanco que no tenga un conjunto de indicadores de éxito es la forma en que abordaría el problema.


Solo lanza una excepción si es realmente un error. Si es el comportamiento esperado para que el objeto no exista, devuelva el nulo.

De lo contrario es una cuestión de preferencia.


Solo pregúntese: "¿es un caso excepcional que el objeto no se encuentra"? Si se espera que suceda en el curso normal de su programa, probablemente no debería generar una excepción (ya que no es un comportamiento excepcional).

Versión corta: use excepciones para manejar el comportamiento excepcional, no para manejar el flujo normal de control en su programa.

-Alan


Solo quería recapitular las opciones mencionadas anteriormente, lanzando algunas nuevas en:

  1. retorno nulo
  2. lanzar una excepción
  3. utilizar el patrón de objeto nulo
  4. proporcione un parámetro booleano a su método, para que la persona que llama pueda elegir si desea que lance una excepción
  5. proporcione un parámetro adicional, de modo que el llamante pueda establecer un valor que recupere si no se encuentra ningún valor

O podrías combinar estas opciones:

Proporcione varias versiones sobrecargadas de su receptor, para que la persona que llama pueda decidir qué camino tomar. En la mayoría de los casos, solo el primero tiene una implementación del algoritmo de búsqueda, y los otros simplemente envuelven el primero:

Object findObjectOrNull(String key); Object findObjectOrThrow(String key) throws SomeException; Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject); Object findObjectOrDefault(String key, Object defaultReturnValue);

Incluso si elige proporcionar solo una implementación, es posible que desee utilizar una convención de nomenclatura como esa para aclarar su contrato, y le ayuda si alguna vez decide agregar otras implementaciones también.

No debe abusar de él, pero puede ser útil, especialmente cuando escribe una clase auxiliar que usará en cientos de aplicaciones diferentes con muchas convenciones diferentes de manejo de errores.


Use el patrón de objeto nulo o lance una excepción.


Ventajas de lanzar una excepción:

  1. Flujo de control más limpio en su código de llamada. La comprobación de nula inyecta una rama condicional que se maneja de forma nativa mediante try / catch. La comprobación de nulo no indica qué es lo que está comprobando; está comprobando si está buscando un error que está esperando, o está comprobando si está nulo, por lo que no lo pasa más allá en el downchain ?
  2. Elimina la ambigüedad de lo que significa "nulo". ¿Es nulo representativo de un error o es nulo lo que realmente se almacena en el valor? Es difícil decirlo cuando solo tienes una cosa para basar esa determinación.
  3. Mejor consistencia entre el comportamiento del método en una aplicación. Las excepciones suelen estar expuestas en las firmas de métodos, por lo que es más capaz de comprender en qué casos de borde los métodos de una cuenta de aplicación y a qué información puede reaccionar su aplicación de manera predecible.

Para obtener más explicaciones con ejemplos, consulte: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/


depende de si su lenguaje y código promueven: LBYL (vea antes de saltar) o EAFP (más fácil pedir perdón que permiso)

LBYL dice que debes verificar los valores (devuelve un valor nulo)
EAFP dice que solo intente la operación y vea si falla (lance una excepción)

aunque estoy de acuerdo con lo anterior ... las excepciones deben usarse para condiciones de error / excepcionales, y devolver un nulo es mejor cuando se usan cheques.

EAFP vs. LBYL en Python:
http://mail.python.org/pipermail/python-list/2003-May/205182.html ( archivo web )


refiriéndome solo al caso en el que null no se considera un comportamiento excepcional, estoy definitivamente a favor del método try, está claro, no hay necesidad de "leer el libro" o "mirar antes de saltar" como se dijo aquí

así que básicamente:

bool TryFindObject(RequestParam request, out ResponseParam response)

Y esto significa que el código del usuario también estará claro.

... if(TryFindObject(request, out response) { handleSuccess(response) } else { handleFailure() } ...