Tengo un método que se supone que devuelve un objeto si se encuentra.
Si no se encuentra, debería:
- volver nulo
- lanzar una excepción
- otro
Tengo un método que se supone que devuelve un objeto si se encuentra.
Si no se encuentra, debería:
Respuestas:
Si siempre espera encontrar un valor, arroje la excepción si falta. La excepción significaría que hubo 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 del código? La consistencia es importante.
GetPersonById(25)
arrojaría si esa persona ha sido eliminada, pero GetPeopleByHairColor("red")
devolvería un resultado vacío. Entonces, creo que los parámetros dicen algo sobre las expectativas.
Solo lanza una excepción si realmente es un error. Si se espera que el comportamiento del objeto no exista, devuelva el valor nulo.
De lo contrario, es una cuestión de preferencia.
Como regla general, si el método siempre debe devolver un objeto, entonces vaya con la excepción. Si anticipa un nulo ocasional y desea manejarlo de una manera determinada, vaya con el nulo.
Hagas lo que hagas, desaconsejo la tercera opción: devolver una cadena que dice "WTF".
Si nulo nunca indica un error, simplemente devuelva nulo.
Si nulo es siempre un error, arroje una excepción.
Si nulo es a veces una excepción, codifique dos rutinas. Una rutina arroja 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 un mal uso de una rutina de prueba. Es muy fácil olvidarse de verificar nulo.
Entonces, cuando nulo es un error, simplemente escribes
object o = FindObject();
Cuando el nulo no es un error, puede codificar algo como
if (TryFindObject(out object o)
// Do something with o
else
// o was not found
find
y findOrFail
de Laravel Eloquent
TryFindObject
método? Las tuplas parecen más un paradigma vago para los programadores que no quieren tomarse el tiempo para definir un objeto que encapsula múltiples valores. Eso es esencialmente todas las tuplas están en el núcleo de todos modos.
Solo quería recapitular las opciones mencionadas anteriormente, agregando algunas nuevas en:
O puede combinar estas opciones:
Proporcione varias versiones sobrecargadas de su captador, 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 usarlo en exceso, pero puede ser útil, especialmente al escribir una clase auxiliar que usará en cientos de aplicaciones diferentes con muchas convenciones de manejo de errores diferentes.
Expected<T> findObject(String)
donde Expected<T>
tiene las funciones orNull()
, orThrow()
, orSupplied(Supplier<T> supplier)
, orDefault(T default)
. Esto abstrae la obtención de los datos del manejo de errores
Utilice el patrón de objeto nulo o arroje una excepción.
Person somePerson = personRepository.find("does-not-exist");
supongamos que este método devuelve un objeto nulo para ID does-not-exist
. ¿Cuál sería entonces el comportamiento correcto somePerson.getAge()
? En este momento, todavía no estoy convencido de que el patrón de objeto nulo sea la solución correcta para las búsquedas de entidades.
Ventajas de lanzar una excepción:
Para obtener más explicaciones con ejemplos, consulte: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/
depende si tu idioma y código promueven: LBYL (mira antes de saltar) o EAFP (es más fácil pedir perdón que permiso)
LBYL dice que debe verificar los valores (así que devuelva un valor nulo)
EAFP dice que simplemente intente la operación y vea si falla (arroje una excepción)
aunque estoy de acuerdo con lo anterior ... las excepciones deben usarse para condiciones excepcionales / de error, y devolver un valor 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 )
Simplemente pregúntese: "¿es un caso excepcional que no se encuentre el objeto"? 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 un comportamiento excepcional, no para manejar el flujo normal de control en su programa.
-Alan.
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 con 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 nulo cuando no se encuentra el objeto.
2) solo alguna entrada es válida, es decir, la que da como resultado un objeto encontrado. En ese 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 SOLO SI proporciona ambos métodos del segundo contrato, puede lanzar una excepción, ¡no se encuentra nada!
Prefiero simplemente devolver un valor nulo y confiar en que la persona que llama lo maneje 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, una falla es un deber excepcional y debe arrojar.
Depende de lo que significa que el objeto no se encuentra.
Si se trata de una situación normal, devuelva nulo. Esto es algo que puede suceder de vez en cuando, y las personas que llaman deben verificarlo.
Si se trata de un error, arroje 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 consideran una buena práctica usar Excepciones solo cuando algo, bueno, Excepcional ha sucedido.
Aquí hay un par de sugerencias más.
Si devuelve una colección, evite devolver nulo, devuelva una colección vacía, lo que hace que la enumeración sea más fácil de tratar sin una verificación nula primero.
Varias API de .NET usan 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 Objeto nulo en algunas circunstancias, que puede ser una versión predeterminada o una versión sin comportamiento. La clave es evitar verificaciones nulas en toda la base del código. Consulte aquí para obtener más información http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx
En algunas funciones agrego un parámetro:
..., bool verify = true)
Verdadero significa tirar, falso significa devolver algún valor de retorno de error. De esta manera, quien usa esta función tiene ambas opciones. El valor predeterminado debe ser verdadero, para beneficio de aquellos que se olvidan del manejo de errores.
Devuelva un valor 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 verifica 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 configurar un método que encuentre un objeto.
Opcion A
Object *findObject(Key &key);
Devuelve nulo cuando no se puede encontrar un objeto. Agradable y simple Yo iría con este. Los enfoques alternativos a continuación son para personas que no odian a los paramáticos.
Opcion 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, lanza una excepción para indicar que es un caso inesperado.
Opcion C
bool findObject(Key &key, Object &found);
El método devuelve falso 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)) { ...
refiriéndome solo al caso donde nulo no se considera un comportamiento excepcional, definitivamente estoy para el método de prueba, está claro, no es necesario "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 será claro
...
if(TryFindObject(request, out response)
{
handleSuccess(response)
}
else
{
handleFailure()
}
...
En general, debe devolver nulo. El código que llama al método debería decidir si lanzar una excepción o intentar otra cosa.
O devolver una opción
Una opción es básicamente una clase de contenedor que obliga al cliente a manejar casos de cabina. Scala tiene este concepto, busque su API.
Luego, tiene métodos como T getOrElse (T valueIfNull) en este objeto que devuelve el objeto encontrado o una alternativa que el cliente especifica.
Desafortunadamente, JDK es inconsistente, si intentas acceder a una clave no existente en el paquete de recursos, no obtienes una excepción y cuando solicitas valor del mapa, obtienes un valor nulo si no existe. Entonces, cambiaría la respuesta ganadora a lo siguiente, si el valor encontrado puede ser nulo, luego generaría una excepción cuando no se encuentre, de lo contrario, devolvería nulo. Así que siga la regla con una excepción, si necesita saber por qué no se encuentra el valor, siempre genere una excepción, o ...
Mientras se suponga que devuelve una referencia al objeto, devolver un NULL debería ser bueno.
Sin embargo, si devuelve todo lo 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 del tipo 'objeto'. En ese caso, lanzar una excepción o devolver un objeto en blanco que no tenga un indicador de éxito establecido es cómo abordaría el problema.
No piense que nadie mencionó los gastos generales en el manejo de excepciones: se necesitan recursos adicionales para cargar y procesar la excepción, por lo que, a menos que sea un verdadero evento de cierre de la aplicación o de detención del proceso (en adelante, causaría más daño que bien) optaría por devolver un valorar el entorno de llamada podría interpretar como mejor le parezca.
Estoy de acuerdo con lo que parece ser el consenso aquí (devolver nulo si "no encontrado" es un resultado normal posible, o lanzar una excepción si la semántica de la situación requiere que siempre se encuentre el objeto).
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", lo que permite asegurar que el código de llamada siempre recibirá un objeto válido sin la necesidad de una comprobación nula o captura de excepciones.
Las excepciones deben ser excepcionales . Devuelve nulo si es válido devolver un valor nulo .
Si el método devuelve una colección, devuelva una colección vacía (como se dijo anteriormente). ¡Pero por favor no Collections.EMPTY_LIST o tal! (en el caso de Java)
Si el método recupera un solo objeto, entonces tiene algunas opciones.
Tenga cuidado, si decide devolver un valor 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. Por lo tanto, no devuelva valores nulos que no se verifican en tiempo de compilación.
null
. Vea la respuesta más votada para más.
Si está utilizando una biblioteca u otra clase que arroja una excepción, debe volver a lanzar a . Aquí hay un ejemplo. Example2.java es como la 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) el seguimiento de la pila al 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();
}
}
}
Example.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;
}
}
}
Example2.java
/**
* Example2.java
* @author Seval
*
*/
public class Example2 {
/**
* Constructor of Example2
* @throws Exception
*/
public Example2() throws Exception{
throw new Exception("Please set the \"obj\"");
}
}
Eso realmente depende de si espera encontrar el objeto, o no. Si sigue la escuela de pensamiento de que las excepciones deben usarse para indicar algo, bueno, err, excepcional ha ocurrido entonces:
De lo contrario, devuelva nulo.