Tengo un fragmento de código que se puede representar como:
public class ItemService {
public void DeleteItems(IEnumerable<Item> items)
{
// Save us from possible NullReferenceException below.
if(items == null)
return;
foreach(var item in items)
{
// For the purpose of this example, lets say I have to iterate over them.
// Go to database and delete them.
}
}
}
Ahora me pregunto si este es el enfoque correcto o si debo lanzar una excepción. Puedo evitar excepciones, porque regresar sería lo mismo que iterar sobre una colección vacía, lo que significa que no se ejecuta ningún código importante de todos modos, pero por otro lado, posiblemente esté ocultando problemas en algún lugar del código, porque ¿por qué alguien querría llamar? DeleteItems
con null
parámetro? Esto puede indicar que hay un problema en otro lugar del código.
Este es un problema que generalmente tengo con los métodos en los servicios, porque la mayoría de ellos hacen algo y no devuelven un resultado, por lo que si alguien pasa información no válida, el servicio no tiene nada que hacer, por lo que se devuelve.
fuente
Respuestas:
Estas son dos preguntas diferentes.
¿Deberías aceptar
null
? Eso depende de su política general acercanull
de la base del código. En mi opinión, prohibir ennull
todas partes, excepto donde está documentado explícitamente, es una muy buena práctica, pero es una práctica aún mejor cumplir con la convención que su base de código ya tiene.¿Deberías aceptar la colección vacía? En mi opinión: SÍ, absolutamente. Es mucho más esfuerzo restringir a todas las personas que llaman a colecciones no vacías que hacer lo matemáticamente correcto, incluso si sorprende a algunos desarrolladores que están dudosos con el concepto de cero.
fuente
AhaINoticedYouPassingInNullException
cuando el tiempo de ejecución ya te brinda la posibilidad de tirarNullReferenceException
por ti, sin que escribas ningún código. Hay alguna utilidad (por ejemplo, su herramienta de cobertura de código le dirá si tiene o no una prueba de unidad para pasar nula en el primer caso pero no en el último), pero ninguna de las excepciones debe probarse / capturarse en cada llamada al servicio, porque generalmente es un error del programador.NullReferenceException
ni enAhaINoticedYouPassingInNullException
ninguna parte, excepto en el código de recuperación de desastres de alto nivel. Y ese controlador de excepciones probablemente debería crear un informe de error :-)null
: los controladores contienen repetitivo para atrapar y continuar en ese caso también?ArgumentNullException
es superior a permitir que el código interior arroje unNullReferenceException
: simplemente mirando el mensaje de excepción, es obvio que es un error de entrada en lugar de un error lógico en el cuerpo del método en el sitio de lanzamiento, y garantizar la salida anticipada significa que es más probable que haya dejado otros datos en un estado válido en lugar de mutar parcialmente de un nulo inesperado más adelante.Valor nulo
Como @KilianFoth ya dijo, cumpla con su política general. Si se trata
null
como una "taquigrafía" para una lista vacía, hágalo de esa manera.Si no tiene una política coherente sobre
null
valores, le recomendaría la siguiente:null
debe reservarse para representar situaciones que no se pueden expresar con el tipo "normal", por ejemplo, usarnull
para representar "No sé". Y esa es una buena opción, ya que todos los que intenten usar este valor descuidadamente obtendrán una excepción, que es lo correcto.Usar
null
como una abreviatura para una lista vacía no califica de esa manera, ya que ya hay una representación perfecta, siendo una lista con cero elementos. Y es una mala elección técnica, ya que obliga a cada parte de su código que trata con listas a verificar la taquigrafía válidanull
.Lista vacía
Para un
DeleteItems()
método, pasar una lista vacía efectivamente significa no hacer nada. Permitiría eso como un argumento, no arrojando una excepción, solo regresando rápidamente.Por supuesto, la persona que llama podría verificar primero cero elementos y omitir la
DeleteItems()
llamada en ese caso. Si hablamos de una API web, por razones de eficiencia, la persona que llama debería hacerlo para evitar el tráfico innecesario y las latencias de ida y vuelta. Pero no creo que su API deba hacer cumplir eso.fuente
Lanza una excepción y maneja nulos en el código de llamada.
Como regla de diseño, trate de evitar valores nulos como parámetros. Reducirá NullPointerExceptions en general, ya que los nulos realmente serán una excepción.
Además de eso, mira el resto de tu código. Si este es un patrón común en su proyecto, manténgase constante.
fuente
En términos generales, las excepciones de lanzamiento deben reservarse para situaciones excepcionales, es decir, si el código no tiene un curso de acción razonable para tomar en el contexto actual.
Puede aplicar ese proceso de pensamiento a esta situación. Dado que esta es una clase pública con un método público, tiene una API pública y, en teoría, no tiene control sobre lo que se le pasa.
Su código no tiene contexto sobre lo que lo llama (como no debería), y no hay nada que pueda hacer razonablemente con un valor nulo. Esto sin duda sería un candidato para un
ArgumentNullException
.fuente
null
?null
no tienes colección. Si se supone / se espera que el código de llamada proporcione una colección al método, hay algo mal, por lo que debe arrojarlo. La única razón para tratar un nulo de la misma manera que una colección vacía es si razonablemente puede esperar que el código de llamada produzca colecciones nulas. Como señalaron otras respuestas, la mayoría de las veces, algonull
es una anomalía. Si los trata igual que las colecciones vacías, posiblemente esté ignorando un problema en otra parte del código.null
entiende que está vacío, ese contexto es específico de este método. En otro lugar de la misma base de código, es posible que tenga un parámetroIEnumerable
oIContainer
que realice algún tipo de filtrado, quenull
podría significar "sin filtro" (permitir todo), mientras que un filtro vacío significa que no permite nada. Y en otro lugar,null
podría significar explícitamente "No sé". Entonces, dado quenull
no siempre significa lo mismo en todas partes, es una buena idea no inventar ningún significado para él a menos que ese significado sea necesario o al menos útil para alguien.Esta pregunta parece no ser sobre excepciones, sino sobre
null
ser un argumento válido.Entonces, antes que nada, debe decidir si
null
es un valor permitido para el argumento de ese método. Si es así, entonces no necesita una excepción. Si no es así, entonces necesita una excepción.Es deseable si desea permitirlo
null
o no, como lo demuestran muchos y muchos éxitos de Google al respecto. Es decir, no obtendrá una respuesta clara, y de alguna manera depende de la opinión y la tradición en el lugar donde está trabajando.Otra área de disputa es si una función de biblioteca debe ser realmente estricta sobre tales cosas, o lo más indulgente posible, siempre que no esté tratando de "arreglar" parámetros erróneos. Compare esto con el mundo de los protocolos de red, transferencia de correo, etc. (que son contratos de interfaz, al igual que los métodos de programación). Allí, por lo general, la política es que el remitente debe ajustarse lo más estrictamente posible al protocolo, mientras que el receptor debe hacer todo lo posible para poder trabajar con lo que se avecina.
Por lo tanto, debe decidir: ¿es realmente el trabajo de un método de biblioteca imponer políticas bastante grandes como el
null
manejo? Especialmente si su biblioteca también es utilizada por otras personas (que podrían tener políticas diferentes).Probablemente me equivocaría al permitir
null
valores, definir y documentar su semántica (es decir,null = empty array
en este caso), y no lanzar una excepción, a menos que el 99% de su otro código similar (código de estilo de "biblioteca") lo haga de la otra manera 'redondo.fuente
null
el principio de ser liberal en lo que aceptas, entonces iniciar sesión o incluso tirar sería útil para las personas cuya intención es ser estrictas en lo que pasan, pero que han desordenado su código y sus pruebas unitarias en la medida en que pasan denull
todos modos.null
, sino declarar abiertamente en el contrato del método que es aceptable (o no, dependiendo de la solución que surja), y luego la pregunta de si lanzar una excepción (o no) se resuelve solo.