Comportamento esperado quando uma solicitação para uma coleção terá zero itens

13

Digamos que você receba o seguinte ...

List<Thing> theThings = fubar.Things.All();

Se não houvesse nada para retornar, o que você esperaria que fubar.Things.All () retornasse?

Edit: Obrigado pelas opiniões. Vou esperar um pouco e aceitar a entrada com mais altos.

Eu concordo com as respostas até agora, principalmente as que sugerem uma coleção vazia. Um fornecedor forneceu à API várias chamadas semelhantes ao exemplo acima. Um fornecedor que faturou US $ 4,6 milhões em receita por meio de suas APIs no ano passado, a BTW. Eles fazem algo que eu discordo fundamentalmente - eles lançam uma exceção.

abscode
fonte
Parece ser um consenso bastante sólido [aqui] [1]: Coleção vazia. Sempre. [1]: stackoverflow.com/questions/1969993/…
Jesse C. Slicer
Para que serve o tipo de dados Things? Se faz sentido que o Thingscampo retorne nulo, faz sentido receber uma exceção porque você não procurou nulo antes de ligar para All(). No entanto, concordo com as pessoas que pensam que fubar.Thingsdevem retornar uma coleção vazia em vez de nula.
Colin D
Entendo o que você está dizendo, Colin. Nesse caso, você pode assumir que as coisas existem e tudo () é estático. A exceção é específica para a coleção estar vazia, não por outro motivo.
abscode
OMG eles lançam uma exceção ...! o_O
Stuart Marks
Agora, a pergunta mais interessante seria qual a razão que alguém poderia ter para jogar em um caso tão genérico ou o que torna o caso tão especial para justificar o lançamento ??
Martin Ba

Respostas:

29

Das duas possibilidades (por exemplo, retornar uma nullou retornar uma coleção vazia), eu escolheria retornar uma coleção vazia, porque isso permite ao chamador ignorar uma verificação do valor retornado. Em vez de escrever isso

List<Thing> theThings = fubar.Things.All();
if (theThings != null) {
    for (Thing t : theThings) {
        t.doSomething();
    }
}

eles seriam capazes de escrever o seguinte:

List<Thing> theThings = fubar.Things.All();
for (Thing t : theThings) {
    t.doSomething();
}

Esse segundo fragmento de código é mais curto e fácil de ler, porque o nível de aninhamento é menor em um.

dasblinkenlight
fonte
2
Eu acho que também acho mais fácil entender conceitualmente como 'o conjunto está vazio' (sem itens). Nulo é 'não existe conjunto', o que é bem diferente. (Isso também deve cobrir coisas que são impossibilidades lógicas - o conjunto de todos os itens ímpares e pares também deve estar vazio, não nulo). Estou sinceramente não sei o que (logicamente) constituiria um conjunto nulo ... (mesmo se você estiver totalmente nu em uma ilha, seus bens são um conjunto vazio, não um nulo um)
Clockwork-Muse
@ X-Zero Mas se você estiver pelado, "objetos na mochila" podem retornar um conjunto nulo, já que você nem tem uma mochila. Ele poderia ser um BackpackNotFoundException, mas somente se ele é realmente inesperado. Deve ser um estado normal em, digamos, um jogo de sobrevivência na ilha.
Izkata
A verificação extra nula é o que me ajuda a dormir à noite.
Joel B
6

Eu esperaria uma lista vazia. theThingsainda seria um objeto, mas theThings.Countou theThings.size()retornaria 0.

David Hogue
fonte
5

Problemas de design como esse são tratados pelo padrão Null Object

... Em vez de usar uma referência nula para transmitir a ausência de um objeto (por exemplo, um cliente inexistente), usa-se um objeto que implementa a interface esperada, mas cujo corpo do método está vazio. A vantagem dessa abordagem sobre uma implementação padrão funcional é que um Objeto Nulo é muito previsível e não tem efeitos colaterais: não faz nada.

Por exemplo, uma função pode recuperar uma lista de arquivos em um diretório e executar alguma ação em cada um. No caso de um diretório vazio, uma resposta pode ser lançar uma exceção ou retornar uma referência nula em vez de uma lista. Assim, o código que espera uma lista deve verificar se realmente possui uma antes de continuar, o que pode complicar o design ...

A sugestão particularmente aplicável ao seu caso (retornando Listquando não houver Things) é:

... Ao retornar um objeto nulo (ou seja, uma lista vazia ), não é necessário verificar se o valor de retorno é de fato uma lista. A função de chamada pode simplesmente iterar a lista como normal, efetivamente sem fazer nada. No entanto, ainda é possível verificar se o valor retornado é um objeto nulo (por exemplo, uma lista vazia) e reagir de maneira diferente, se desejado.

mosquito
fonte
3

Você deve, IMHO, retornar um valor VAZIO. Eu não sei sobre c #, mas em Java, temos o seguinte:

  List list = Collections.EMPTY_LIST;
  Set set = Collections.EMPTY_SET;
  Map map = Collections.EMPTY_MAP;

  // For the type-safe 
  List<String> s = Collections.emptyList();
  Set<Long> l = Collections.emptySet();
  Map<Date> d = Collections.emptyMap();

http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html

Marcelo Assis
fonte
1
A C # equivalente é Enumerable.Empty<T>(), que retorna um vazio IEnumerable<T>(ver msdn.microsoft.com/en-us/library/bb341042.aspx )
Avner Shahar-Kashtan
1
Os documentos atuais estão aqui: docs.oracle.com/javase/7/docs/api/java/util/Collections.html - os documentos 1.4.2 têm agora cerca de dez anos.
Stuart Marks
2

Eu retornaria uma coleção vazia com o retorno de um valor nulo, pois dessa forma você pode evitar escrever uma verificação nula no código de chamada.


fonte
2

As duas soluções significam coisas diferentes.

Se houver apenas zero da coisa que você está retornando, você SEMPRE retornará uma coleção vazia! Veja o caso de uma listagem de diretório. Se não houver arquivos no diretório, você retornará uma coleção vazia de arquivos.

Por outro lado, se o diretório não existir, isso não é realmente apropriado. "Não posso devolver nada" significa algo totalmente diferente. Nesse caso, você deve retornar nulo ou lançar uma exceção, dependendo da situação, não basta retornar uma coleção vazia como se nada estivesse errado.

Bill K
fonte
Explicação muito razoável. O resultado retornado não deve cobrir estado inválido, temos exceções para isso.
Ivaylo Slavov