He escuchado algunas voces que dicen que verificar un valor nulo devuelto de los métodos es un mal diseño. Me gustaría escuchar algunas razones para esto.
pseudocódigo:
variable x = object.method()
if (x is null) do something
oop
null
return-value
koen
fuente
fuente
Respuestas:
La razón detrás de no devolver nulo es que no tiene que verificarlo y, por lo tanto, su código no necesita seguir una ruta diferente en función del valor de retorno. Es posible que desee consultar el Patrón de objetos nulos que proporciona más información al respecto.
Por ejemplo, si tuviera que definir un método en Java que devolviera una Colección, normalmente preferiría devolver una colección vacía (es decir
Collections.emptyList()
) en lugar de nula, ya que significa que mi código de cliente está más limpio; p.ej... que es más limpio que:
fuente
null
es un "contenedor", que contiene cero o un puntero a los objetos. (Así es como es modelado explícitamente por Haskell'sMaybe
en esos casos, y es mucho mejor por hacerlo.)Aquí está la razón.
En Clean Code de Robert Martin , escribe que devolver nulo es un mal diseño cuando en su lugar puede devolver, digamos, una matriz vacía. Dado que el resultado esperado es una matriz, ¿por qué no? Le permitirá iterar sobre el resultado sin condiciones adicionales. Si es un número entero, tal vez sea suficiente 0, si es un hash, un hash vacío. etc.
La premisa es no forzar el código de llamada para manejar inmediatamente los problemas. Es posible que el código de llamada no quiera preocuparse por ellos. Por eso, en muchos casos, las excepciones son mejores que nulas.
fuente
Buenos usos de devolver nulo:
Malos usos: tratar de reemplazar u ocultar situaciones excepcionales como:
En esos casos, lanzar una excepción es más adecuado ya que:
Sin embargo, las Excepciones no deben usarse para manejar condiciones normales de operación del programa tales como:
fuente
boolean login(String,String)
parece estar bien y también lo haceAuthenticationContext createAuthContext(String,String) throws AuthenticationException
Sí, devolver NULL es un diseño terrible , en un mundo orientado a objetos. En pocas palabras, el uso NULL conduce a:
Consulte esta publicación de blog para obtener una explicación detallada: http://www.yegor256.com/2014/05/13/why-null-is-bad.html . Más en mi libro Elegant Objects , Sección 4.1.
fuente
bool TryGetBlah(out blah)
orFirstOrNull()
oMatchOrFallback(T fallbackValue)
.isEmpty()
) y solo si es verdadero, llama al método. Las personas argumentan en contra de que el segundo dice que es un rendimiento inferior, pero como dice la filosofía de Unix, "valorar el tiempo humano sobre el tiempo de la máquina" (es decir, el rendimiento trivialmente más lento desperdicia menos tiempo que los desarrolladores que depuran el código que está dando errores espurios).¿Quién dice que este es un mal diseño?
La comprobación de nulos es una práctica común, incluso recomendada, de lo contrario corre el riesgo de NullReferenceExceptions en todas partes. Es mejor manejar el error con gracia que lanzar excepciones cuando no es necesario.
fuente
Según lo que has dicho hasta ahora, creo que no hay suficiente información.
Devolver nulo desde un método CreateWidget () parece malo.
Devolver nulo de un método FindFooInBar () parece estar bien.
fuente
Create...
devuelve una nueva instancia o arroja ;Get...
devuelve una instancia existente esperada o arroja ;GetOrCreate...
devuelve una instancia existente, o una nueva instancia si no existe, o arroja ;Find...
devuelve una instancia existente, si existe, onull
. Para consultas de colección:Get...
siempre devuelve una colección, que está vacía si no se encuentran elementos coincidentes.Su inventor dice que es un error de mil millones de dólares!
fuente
Depende del idioma que estés usando. Si está en un lenguaje como C # donde la forma idiomática de indicar la falta de un valor es devolver nulo, entonces devolver nulo es un buen diseño si no tiene un valor. Alternativamente, en idiomas como Haskell que usan idiomáticamente la mónada tal vez para este caso, entonces devolver nulo sería un mal diseño (si fuera posible).
fuente
null
lenguajes como C # y Java a menudo se sobrecargan y se les da algún significado en el dominio. Si busca lanull
palabra clave en las especificaciones del idioma, simplemente significa "un puntero no válido". Eso probablemente no significa nada en ningún dominio problemático.null
o "no inicializado"null
Si lee todas las respuestas, queda claro que la respuesta a esta pregunta depende del tipo de método.
En primer lugar, cuando ocurre algo excepcional (IOproblem, etc.), lógicamente se lanzan excepciones. Cuando exactamente algo es excepcional es probablemente algo para un tema diferente.
Cuando se espera que un método posiblemente no tenga resultados, hay dos categorías:
Enumables vacíos, cadenas, etc. son buenos ejemplos
Como se mencionó, se supone que el método posiblemente no tenga ningún resultado, por lo que no es excepcional, por lo tanto, no debe arrojar una excepción. No es posible un valor neutral (por ejemplo: 0 no es especialmente un resultado neutral, dependiendo del programa)
Hasta que tengamos una manera oficial de denotar que una función puede o no devolver nulo, trato de tener una convención de nomenclatura para denotarlo.
Al igual que tiene la convención Try Something () para los métodos que se espera que fallen, a menudo llamo a mis métodos Safe Something () cuando el método devuelve un resultado neutral en lugar de nulo.
Todavía no estoy completamente de acuerdo con el nombre, pero no se me ocurrió nada mejor. Así que estoy corriendo con eso por ahora.
fuente
Tengo una convención en esta área que me sirvió bien
Para consultas de un solo artículo:
Create...
devuelve una nueva instancia o arrojaGet...
devuelve una instancia existente esperada o arrojaGetOrCreate...
devuelve una instancia existente, o una nueva instancia si no existe, o arrojaFind...
devuelve una instancia existente, si existe, onull
Para consultas de recopilación:
Get...
siempre devuelve una colección, que está vacía si no se encuentran elementos coincidentes [1][1] dados algunos criterios, explícitos o implícitos, dados en el nombre de la función o como parámetros.
fuente
Get
cuando espero que esté allí, de modo que si no está allí, entonces es un error y arrojo, nunca necesito verificar el valor de retorno. Lo usoFind
si realmente no sé si está ahí o no, entonces necesito verificar el valor de retorno.Las excepciones son por circunstancias excepcionales .
Si su función está destinada a encontrar un atributo asociado con un objeto dado, y ese objeto no tiene dicho atributo, puede ser apropiado devolver nulo. Si el objeto no existe, lanzar una excepción puede ser más apropiado. Si la función está destinada a devolver una lista de atributos, y no hay ninguno a devolver, tiene sentido devolver una lista vacía: está devolviendo todos los atributos cero.
fuente
Está bien devolver nulo si hacerlo es significativo de alguna manera:
En un caso como este, es significativo devolver nulo si la identificación no corresponde a una entidad existente, ya que le permite distinguir el caso en el que no se encontró coincidencia de un error legítimo.
La gente puede pensar que esto es malo porque se puede abusar de él como un valor de retorno "especial" que indica una condición de error, que no es tan buena, un poco como devolver códigos de error de una función pero confuso porque el usuario tiene que verificar el retorno para nulo, en lugar de detectar las excepciones apropiadas, p. ej.
fuente
No es necesariamente un mal diseño, ya que con tantas decisiones de diseño, depende.
Si el resultado del método es algo que no tendría un buen resultado en el uso normal, devolver nulo está bien:
Si realmente siempre debería haber un resultado no nulo, entonces sería mejor lanzar una excepción:
fuente
Optional<>
Para ciertos escenarios, desea notar una falla tan pronto como suceda.
Verificar contra NULL y no afirmar (para errores del programador) o arrojar (para errores del usuario o de la persona que llama) en el caso de falla puede significar que los bloqueos posteriores son más difíciles de rastrear, porque no se encontró el caso impar original.
Además, ignorar los errores puede conducir a vulnerabilidades de seguridad. Quizás la nulidad vino del hecho de que se sobreescribió un búfer o similar. Ahora, usted está no estrellarse, lo que significa que el explotador tiene la oportunidad de ejecutar en el código.
fuente
¿Qué alternativas ves para volver nulo?
Veo dos casos:
En este caso podríamos: Devolver nulo o lanzar una excepción (marcada) (o tal vez crear un artículo y devolverlo)
En este caso, podríamos devolver Null, devolver una lista vacía o lanzar una excepción.
Creo que el retorno nulo puede ser menos bueno que las alternativas porque requiere que el cliente recuerde verificar si hay nulo, los programadores olvidan y codifican
En Java, lanzar una excepción marcada, RecordNotFoundException, permite que el compilador le recuerde al cliente que trate con el caso.
Creo que las búsquedas que devuelven listas vacías pueden ser bastante convenientes: simplemente complete la pantalla con todos los contenidos de la lista, oh, está vacía, el código "simplemente funciona".
fuente
A veces, devolver NULL es lo correcto, pero específicamente cuando se trata de secuencias de diferentes tipos (matrices, listas, cadenas, lo que tienes), probablemente sea mejor devolver una secuencia de longitud cero, ya que conduce a un código más corto y, con suerte, más comprensible, sin tener que escribir mucho más por parte del implementador de la API.
fuente
Haga que llamen a otro método después del hecho para averiguar si la llamada anterior fue nula. ;-) Hey, fue lo suficientemente bueno para JDBC
fuente
La idea básica detrás de este hilo es programar a la defensiva. Es decir, código contra lo inesperado. Hay una variedad de respuestas diferentes:
Adamski sugiere mirar el Patrón de Objetos Nulos, con esa respuesta votada por esa sugerencia.
Michael Valenty también sugiere una convención de nombres para decirle al desarrollador lo que se puede esperar. ZeroConcept sugiere un uso adecuado de Exception, si ese es el motivo del NULL. Y otros.
Si hacemos la "regla" de que siempre queremos hacer una programación defensiva, entonces podemos ver que estas sugerencias son válidas.
Pero tenemos 2 escenarios de desarrollo.
Clases "autorizadas" por un desarrollador: El autor
Clases "consumidas" por otro (quizás) desarrollador: el Desarrollador
Independientemente de si una clase devuelve NULL para métodos con un valor de retorno o no, el desarrollador deberá probar si el objeto es válido.
Si el desarrollador no puede hacer esto, entonces esa Clase / método no es determinista. Es decir, si la "llamada al método" para obtener el objeto no hace lo que "anuncia" (por ejemplo, getEmployee), ha roto el contrato.
Como autor de una clase, siempre quiero ser tan amable y defensivo (y determinista) al crear un método.
Entonces, dado que NULL o NULL OBJECT (p. Ej., Si (employee como NullEmployee.ISVALID)) deben verificarse y eso puede suceder con una colección de Empleados, entonces el enfoque de objeto nulo es el mejor enfoque.
Pero también me gusta la sugerencia de Michael Valenty de nombrar el método que DEBE devolver nulo, por ejemplo, getEmployeeOrNull.
Un autor que lanza una excepción está eliminando la opción para que el desarrollador pruebe la validez del objeto, lo cual es muy malo en una colección de objetos, y obliga al desarrollador a manejar excepciones al bifurcar su código de consumo.
Como desarrollador que consume la clase, espero que el autor me brinde la capacidad de evitar o programar la situación nula a la que se enfrentan sus clases / métodos.
Entonces, como desarrollador, programaría defensivamente contra NULL desde un método. Si el autor me ha dado un contrato que siempre devuelve un objeto (el OBJETO NULO siempre lo hace) y ese objeto tiene un método / propiedad por el cual probar la validez del objeto, entonces usaría ese método / propiedad para continuar usando el objeto de lo contrario, el objeto no es válido y no puedo usarlo.
La conclusión es que el Autor de la Clase / Métodos debe proporcionar mecanismos que un Desarrollador pueda usar en su programación defensiva. Es decir, una intención más clara del método.
El desarrollador siempre debe usar programación defensiva para probar la validez de los objetos devueltos por otra clase / método.
Saludos
GregJF
fuente
Otras opciones para esto son: devolver algún valor que indique éxito o no (o tipo de error), pero si solo necesita un valor booleano que indicará éxito / falla, devolverá nulo para falla y un objeto para éxito no ser menos correcto, luego devolver verdadero / falso y obtener el objeto a través del parámetro.
Otro enfoque sería utilizar excepciones para indicar fallas, pero aquí, en realidad, hay muchas más voces que dicen que esta es una práctica MALA (ya que el uso de excepciones puede ser conveniente pero tiene muchas desventajas).
Por lo tanto, personalmente no veo nada malo en devolver nulo como indicación de que algo salió mal y verificarlo más tarde (para saber realmente si ha tenido éxito o no). Además, pensar ciegamente que su método no devolverá NULL y luego basará su código en él, puede dar lugar a otros errores, a veces difíciles de encontrar (aunque en la mayoría de los casos simplemente bloqueará su sistema :), como hará referencia a 0x00000000 tarde o temprano).
fuente
Función_nula @wikipedia
fuente
Bueno, de seguro depende del propósito del método ... A veces, una mejor opción sería lanzar una excepción. Todo depende de un caso a otro.
fuente
Si el código es algo como:
Si tiene un objeto ficticio cuyo método execute () no hace nada, y devuelve eso en lugar de Nulo en los casos apropiados, no tiene que verificar el caso Nulo y, en su lugar, solo puede hacer:
Entonces, aquí el problema no es entre verificar NULL frente a una excepción, sino entre que la persona que llama tiene que manejar los casos especiales de manera diferente (de cualquier manera) o no.
fuente
Para mi caso de uso, necesitaba devolver un Mapa del método y luego buscar una clave específica. Pero si devuelvo un mapa vacío, conducirá a NullPointerException y no será muy diferente devolver nulo en lugar de un mapa vacío. Pero a partir de Java8 en adelante podríamos usar Opcional . Lo anterior es la razón por la cual se introdujo el concepto opcional.
fuente
G'day
Devolver NULL cuando no puede crear un nuevo objeto es una práctica estándar para muchas API.
¿Por qué demonios es un mal diseño? No tengo idea.
Editar: Esto es cierto para los lenguajes en los que no tiene excepciones, como C, donde ha sido la convención durante muchos años.
HTH
'Avahappy,
fuente