Eu ouvi algumas vozes dizendo que a verificação de um valor nulo retornado dos métodos é um design ruim. Eu gostaria de ouvir algumas razões para isso.
pseudo-código:
variable x = object.method()
if (x is null) do something
oop
null
return-value
koen
fonte
fonte
Respostas:
A lógica por trás de não retornar nulo é que você não precisa procurá-lo e, portanto, seu código não precisa seguir um caminho diferente com base no valor de retorno. Você pode querer verificar o Null Object Pattern, que fornece mais informações sobre isso.
Por exemplo, se eu definisse um método em Java que retornasse uma coleção, normalmente preferiria retornar uma coleção vazia (ou seja
Collections.emptyList()
), em vez de nula, pois significa que meu código de cliente é mais limpo; por exemplo... que é mais limpo que:
fonte
null
são um "contêiner", que contém zero ou um ponteiro para os objetos. (Isso é certamente como é explicitamente modelada por Haskell doMaybe
nesses casos, e é o melhor para fazê-lo.)Aqui está o motivo.
No Clean Code, de Robert Martin, ele escreve que retornar nulo é um design ruim quando você pode retornar, digamos, matriz vazia. Como o resultado esperado é uma matriz, por que não? Isso permitirá que você repita o resultado sem nenhuma condição extra. Se for um número inteiro, talvez 0 seja suficiente, se for um hash, um hash vazio. etc.
A premissa é não forçar o código de chamada a lidar imediatamente com os problemas. O código de chamada pode não querer se preocupar com eles. É também por isso que, em muitos casos, as exceções são melhores que zero.
fonte
Bons usos de retornar null:
Maus usos: Tentativa de substituir ou ocultar situações excepcionais, como:
Nesses casos, lançar uma exceção é mais adequado, pois:
No entanto, as exceções não devem ser usadas para lidar com condições normais de operação do programa, como:
fonte
boolean login(String,String)
parece muito bem e assim que fazAuthenticationContext createAuthContext(String,String) throws AuthenticationException
Sim, retornar NULL é um design terrível , no mundo orientado a objetos. Em poucas palavras, o uso NULL leva a:
Confira esta postagem no blog para obter uma explicação detalhada: http://www.yegor256.com/2014/05/13/why-null-is-bad.html . Mais em meu livro Elegant Objects , Seção 4.1.
fonte
bool TryGetBlah(out blah)
ouFirstOrNull()
ouMatchOrFallback(T fallbackValue)
.isEmpty()
) e somente se for verdadeiro, chame o método. As pessoas argumentam contra o segundo que dizem que é um desempenho pior - mas, como diz a Unix Philosophy, "valorizam o tempo humano em detrimento do tempo da máquina" (ou seja, o desempenho trivialmente mais lento desperdiça menos tempo do que os desenvolvedores que depuram código que está causando erros espúrios).Quem disse que isso é um design ruim?
A verificação de nulos é uma prática comum, mesmo incentivada, caso contrário, você corre o risco de NullReferenceExceptions em qualquer lugar. É melhor lidar com o erro normalmente do que lançar exceções quando você não precisar.
fonte
Com base no que você disse até agora, acho que não há informações suficientes.
Retornar nulo de um método CreateWidget () parece ruim.
Retornar nulo de um método FindFooInBar () parece bom.
fonte
Create...
retorna uma nova instância ou lança ;Get...
retorna uma instância existente esperada ou lança ;GetOrCreate...
retorna uma instância existente ou nova, se não existir, ou lança ;Find...
retorna uma instância existente, se existir, ounull
. Para consultas de coleção -Get...
sempre retorna uma coleção, que está vazia se nenhum item correspondente for encontrado.Seu inventor diz que é um erro de um bilhão de dólares!
fonte
Depende do idioma que você está usando. Se você estiver em um idioma como C #, onde a maneira idiomática de indicar a falta de um valor é retornar nulo, retornar nulo é um bom design, se você não tiver um valor. Como alternativa, em idiomas como Haskell, que usam a mônada Maybe para esse caso, o retorno nulo seria um design ruim (se possível).
fonte
null
em linguagens como C # e Java geralmente são sobrecarregadas e têm algum significado no domínio. Se você procurar anull
palavra - chave nas especificações do idioma, significa simplesmente "um ponteiro inválido". Isso provavelmente não significa nada em nenhum domínio do problema.null
ou "não inicializado"null
Se você ler todas as respostas, fica claro que a resposta a essa pergunta depende do tipo de método.
Em primeiro lugar, quando algo excepcional acontece (IOproblem etc), logicamente são lançadas exceções. Quando exatamente algo é excepcional, provavelmente é algo para um tópico diferente.
Sempre que se espera que um método não tenha resultados, existem duas categorias:
Enumrables, strings, etc. vazios são bons exemplos
Como mencionado, presume-se que o método possivelmente não tenha resultado; portanto, ele não é excepcional, portanto, não deve gerar uma exceção. Um valor neutro não é possível (por exemplo: 0 não é um resultado neutro, dependendo do programa)
Até que tenhamos uma maneira oficial de denotar que uma função pode ou não retornar nula, tento ter uma convenção de nomenclatura para denotá-lo.
Assim como você tem a convenção Try Something () para métodos com falha esperada, costumo nomear meus métodos como Safe Something () quando o método retorna um resultado neutro em vez de nulo.
Ainda não estou totalmente de acordo com o nome, mas não consegui encontrar nada melhor. Então, eu estou correndo com isso por enquanto.
fonte
Eu tenho uma convenção nessa área que me serviu bem
Para consultas de item único:
Create...
retorna uma nova instância ou lançaGet...
retorna uma instância existente esperada ou lançaGetOrCreate...
retorna uma instância existente ou nova, caso não exista, ou lançaFind...
retorna uma instância existente, se existir, ounull
Para consultas de coleção:
Get...
sempre retorna uma coleção, que está vazia se nenhum item [1] correspondente for encontrado[1] dados alguns critérios, explícitos ou implícitos, dados no nome da função ou como parâmetros.
fonte
Get
quando espero que ele esteja lá, de modo que, se não estiver lá, é um erro e eu lancei - nunca preciso verificar o valor de retorno. UsoFind
se realmente não sei se existe ou não - preciso verificar o valor de retorno.Exceções são por exceção circunstâncias al.
Se sua função se destina a encontrar um atributo associado a um determinado objeto, e esse objeto não possui esse atributo, pode ser apropriado retornar nulo. Se o objeto não existir, lançar uma exceção pode ser mais apropriado. Se a função é destinada a retornar uma lista de atributos, e não há nenhuma a retornar, retornar uma lista vazia faz sentido - você está retornando todos os zero atributos.
fonte
Não há problema em retornar null se isso for significativo de alguma forma:
Em um caso como esse, é significativo retornar nulo se o ID não corresponder a uma entidade existente, pois permite distinguir o caso em que nenhuma correspondência foi encontrada de um erro legítimo.
As pessoas podem pensar que isso é ruim porque pode ser abusado como um valor de retorno "especial" que indica uma condição de erro, o que não é tão bom, como retornar códigos de erro de uma função, mas é confuso porque o usuário precisa verificar o retorno quanto a nulo, em vez de capturar as exceções apropriadas, por exemplo
fonte
Não é necessariamente um design ruim - como em tantas decisões de design, depende.
Se o resultado do método for algo que não teria um bom resultado no uso normal, retornar nulo é bom:
Se realmente deve sempre haver um resultado não nulo, talvez seja melhor lançar uma exceção:
fonte
Optional<>
Para certos cenários, você deseja perceber uma falha assim que ela ocorre.
Verificar NULL e não declarar (erros de programador) ou lançar (erros de usuário ou de chamador) no caso de falha pode significar que falhas posteriores são mais difíceis de localizar, porque o caso ímpar original não foi encontrado.
Além disso, ignorar erros pode levar a explorações de segurança. Talvez a nulidade advenha do fato de um buffer ter sido substituído ou algo parecido. Agora, você não está travando, o que significa que o explorador pode executar no seu código.
fonte
Que alternativas você vê para retornar nulo?
Eu vejo dois casos:
Nesse caso, poderíamos: Retornar nulo ou lançar uma exceção (marcada) (ou talvez criar um item e devolvê-lo)
Nesse caso, podemos retornar nulo, retornar uma lista vazia ou lançar uma exceção.
Acredito que o retorno nulo pode ser menos bom do que as alternativas, pois exige que o cliente lembre-se de verificar nulo, os programadores esquecem e codificam
Em Java, lançar uma exceção verificada, RecordNotFoundException, permite que o compilador lembre o cliente de lidar com o caso.
Acho que as pesquisas que retornam listas vazias podem ser bastante convenientes - basta preencher a exibição com todo o conteúdo da lista, oh está vazio, o código "simplesmente funciona".
fonte
Às vezes, retornar NULL é a coisa certa a fazer, mas especificamente quando você está lidando com sequências de diferentes tipos (matrizes, listas, seqüências de caracteres, o que você tem), provavelmente é melhor retornar uma sequência de comprimento zero, pois leva a um código mais curto e, mais esperançosamente, mais compreensível, sem precisar escrever muito mais por parte do implementador da API.
fonte
Faça com que eles chamem outro método após o fato para descobrir se a chamada anterior foi nula. ;-) Ei, foi bom o suficiente para o JDBC
fonte
A idéia básica por trás desse segmento é programar defensivamente. Ou seja, código contra o inesperado. Há uma variedade de respostas diferentes:
Adamski sugere examinar o Padrão de Objeto Nulo, com essa resposta votada para essa sugestão.
Michael Valenty também sugere uma convenção de nomenclatura para informar ao desenvolvedor o que pode ser esperado. ZeroConcept sugere um uso adequado de Exception, se esse for o motivo do NULL. E outros.
Se fizermos a "regra" de que sempre queremos fazer uma programação defensiva, podemos ver que essas sugestões são válidas.
Mas temos dois cenários de desenvolvimento.
Classes "de autoria" de um desenvolvedor: o autor
Classes "consumidas" por outro (talvez) desenvolvedor: the Developer
Independentemente de uma classe retornar NULL para métodos com um valor de retorno ou não, o Desenvolvedor precisará testar se o objeto é válido.
Se o desenvolvedor não puder fazer isso, essa classe / método não é determinístico. Ou seja, se a "chamada de método" para obter o objeto não fizer o que "anuncia" (por exemplo, getEmployee), ele quebrou o contrato.
Como autor de uma classe, sempre quero ser gentil e defensivo (e determinista) ao criar um método.
Portanto, considerando que NULL ou NULL OBJECT (por exemplo, se (funcionário como NullEmployee.ISVALID)) precisa ser verificado e isso pode precisar acontecer com uma coleção de Funcionários, a abordagem de objeto nulo é a melhor abordagem.
Mas também gosto da sugestão de Michael Valenty de nomear o método que DEVE retornar nulo, por exemplo, getEmployeeOrNull.
Um autor que lança uma exceção está removendo a opção de o desenvolvedor testar a validade do objeto, o que é muito ruim em uma coleção de objetos, e força o desenvolvedor a lidar com exceções ao ramificar seu código de consumo.
Como desenvolvedor que consome a classe, espero que o autor me dê a capacidade de evitar ou programar a situação nula que sua classe / métodos possam enfrentar.
Então, como desenvolvedor, eu programaria defensivamente contra o NULL a partir de um método. Se o autor me deu um contrato que sempre retorna um objeto (NULL OBJECT sempre o faz) e esse objeto possui um método / propriedade para testar a validade do objeto, então eu usaria esse método / propriedade para continuar usando o objeto , caso contrário, o objeto não é válido e não posso usá-lo.
Resumindo, o autor da classe / métodos deve fornecer mecanismos que um desenvolvedor possa usar em sua programação defensiva. Ou seja, uma intenção mais clara do método.
O desenvolvedor deve sempre usar programação defensiva para testar a validade dos objetos retornados de outra classe / método.
Saudações
GregJF
fonte
Outras opções para isso são: retornar algum valor que indique sucesso ou não (ou tipo de erro), mas se você precisar de um valor booleano que indique sucesso / falha, retornar nulo por falha e um objeto para sucesso não seja menos correto, retornando verdadeiro / falso e obtendo o objeto através do parâmetro Então, pessoalmente, não vejo nada de ruim em retornar nulo como indicação de que algo deu errado e verificá-lo mais tarde (para realmente saber se você conseguiu ou não). Além disso, pensar cegamente que seu método não retornará NULL e, então, basear seu código nele, pode levar a outros erros, às vezes difíceis de encontrar (embora na maioria dos casos, apenas troque seu sistema :), como você fará referência a 0x00000000 mais cedo ou mais tarde).
Outra abordagem seria usar a exceção para indicar falhas, mas aqui - na verdade, existem muito mais vozes que dizem que essa é uma prática RUIM (como usar exceções pode ser conveniente, mas tem muitas desvantagens).
fonte
Null_function @wikipedia
fonte
Bem, isso certamente depende do objetivo do método ... Às vezes, uma escolha melhor seria lançar uma exceção. Tudo depende de caso para caso.
fonte
Se o código é algo como:
Se você possui um objeto fictício cujo método execute () não faz nada, e você o retorna em vez de Null nos casos apropriados, não precisa verificar o caso Null e pode fazer:
Portanto, aqui o problema não é entre procurar NULL versus uma exceção, mas sim entre o chamador ter que lidar com casos não especiais de maneira diferente (de qualquer maneira) ou não.
fonte
Para o meu caso de uso, eu precisava retornar um mapa do método e, em seguida, procurar uma chave específica. Mas se eu retornar um mapa vazio, ele levará a NullPointerException e não será muito diferente retornar nulo em vez de um mapa vazio. Mas a partir do Java8 em diante, poderíamos usar o Opcional . A descrição acima é a razão pela qual o conceito opcional foi introduzido.
fonte
G'day,
Retornar NULL quando você não conseguir criar um novo objeto é uma prática padrão para muitas APIs.
Por que diabos é um design ruim, não faço ideia.
Editar: isso é verdade para idiomas em que você não tem exceções, como C, onde é a convenção há muitos anos.
HTH
'Avahappy,
fonte