Estou construindo uma API, uma função que carrega um arquivo. Esta função não retornará nada / nulo se o arquivo tiver sido carregado corretamente e lança uma exceção quando houver algum problema.
Por que uma exceção e não apenas falsa? Como dentro de uma exceção, posso especificar o motivo da falha (sem conexão, nome do arquivo ausente, senha incorreta, descrição do arquivo ausente, etc.). Eu queria criar uma exceção personalizada (com alguma enumeração para ajudar o usuário da API a lidar com todos os erros).
Essa é uma boa prática ou é melhor retornar um objeto (com um booleano interno, uma mensagem de erro opcional e a enumeração para erros)?
java
api-design
exceptions
functions
architectural-patterns
Accollativo
fonte
fonte
Result<T, E>
ondeT
está o resultado se for bem-sucedido eE
o erro se não for bem-sucedido. Lançar uma exceção (pode ser - não é tão certo em Java) pode ser caro, pois envolve desenrolar a pilha de chamadas, mas a criação de um objeto Exception é barata. Obviamente, atenha-se aos padrões estabelecidos do idioma que você está usando, mas não combine booleanos e exceções como essa.fillInStackTrace();
é chamado no super construtor, na classeThrowable
Respostas:
Lançar uma exceção é simplesmente uma maneira adicional de fazer um método retornar um valor. O chamador pode verificar um valor de retorno tão facilmente quanto capturar uma exceção e verificar isso. Portanto, decidir entre
throw
ereturn
requer outros critérios.Lançar exceções geralmente deve ser evitado se colocar em risco a eficiência do seu programa (construir um objeto de exceção e desenrolar a pilha de chamadas é muito mais trabalhoso para o computador do que apenas colocar um valor nele). Mas se o objetivo do seu método é fazer upload de um arquivo, o gargalo sempre será a E / S da rede e do sistema de arquivos, portanto, é inútil otimizar o método de retorno.
Também é uma péssima idéia lançar exceções para o que deve ser um fluxo de controle simples (por exemplo, quando uma pesquisa é bem-sucedida ao encontrar seu valor), porque isso viola as expectativas dos usuários da API. Mas um método que não cumpre seu objetivo é um caso excepcional (ou pelo menos deveria ser), portanto não vejo razão para não lançar uma exceção. E se você fizer isso, poderá torná-lo uma exceção personalizada e mais informativa (mas é uma boa ideia transformá-lo em uma subclasse de uma exceção padrão e mais geral, como
IOException
).fonte
Não há absolutamente nenhuma razão para retornar
true
com sucesso, se você não retornarfalse
. Como deve ser o código do cliente?Nesse caso, o chamador precisa de um bloco try-catch de qualquer maneira, mas pode escrever melhor:
Portanto, o
true
valor de retorno é completamente irrelevante para o chamador. Então, apenas mantenha o métodovoid
.Em geral, existem três maneiras de projetar modos de falha.
void
, lançar (marcada) exceçãoRetorno
true
/false
Isso é usado em algumas APIs mais antigas, principalmente no estilo c. As desvantagens são óbvias, você não tem idéia do que deu errado. O PHP faz isso com bastante frequência, levando a códigos como este:
Em contextos multithread, isso é ainda pior.
Lançar exceções (marcadas)
Essa é uma boa maneira de fazer isso. Em alguns pontos, você pode esperar falhas. Java faz isso com soquetes. A suposição básica é que uma chamada deve ser bem-sucedida, mas todos sabem que certas operações podem falhar. Conexões de soquete estão entre elas. Portanto, o chamador é forçado a lidar com a falha. é um design agradável, porque garante que o chamador realmente lide com a falha e oferece ao chamador uma maneira elegante de lidar com a falha.
Retornar objeto de resultado
Essa é outra ótima maneira de lidar com isso. É frequentemente usado para analisar ou simplesmente coisas que precisam ser validadas.
Lógica limpa e agradável para o chamador também.
Há um pouco de debate sobre quando usar o segundo caso e quando usar o terceiro. Algumas pessoas acreditam que as exceções devem ser excepcionais e que você não deve projetar com a possibilidade de exceções em mente, e sempre usará as terceiras opções. Essa multa. Como verificamos exceções em Java, não vejo razão para não usá-las. Uso expetions verificadas quando a suposição básica é que a chamada deve ser bem- sucedida (como usar um soquete), mas a falha é possível e uso a terceira opção quando não está claro se a chamada deve ser bem-sucedida (como validar dados). Mas existem opiniões diferentes sobre isso.
No seu caso, eu usaria
void
+Exception
. Você espera que o upload do arquivo seja bem-sucedido e, quando isso não acontecer, será excepcional. Mas o chamador é forçado a lidar com esse modo de falha e você pode retornar uma exceção que descreva corretamente que tipo de erro ocorreu.fonte
Isso realmente se resume a se uma falha é excepcional ou esperada .
Se um erro não é algo que você geralmente espera, é razoavelmente provável que o usuário da API chame seu método sem nenhum tratamento especial. Lançar uma exceção permite que a bolha borbulhe para um local onde é notada.
Se, por outro lado, os erros são comuns, você deve otimizar para o desenvolvedor que os está verificando e as
try-catch
cláusulas são um pouco mais complicadas do que uma sérieif/elif
ouswitch
.Sempre crie uma API na mente de alguém que a esteja usando.
fonte
Não retorne um valor booleano se você nunca pretende retornar
false
. Basta fazer o métodovoid
e documentar que ele lançará uma exceção (IOException
é adequado) em caso de falha.A razão para isso é que, se você retornar um booleano, o usuário da sua API poderá concluir que pode fazer isso:
Isso não vai funcionar, é claro; isto é, há uma incongruência entre o contrato do seu método e o comportamento dele. Se você lançar uma exceção verificada, o usuário do método precisará lidar com a falha:
fonte
Se seu método tiver um valor de retorno, lançar uma exceção poderá surpreender seus usuários. Se eu ver um método retornar um valor booleano, estou bastante convencido de que retornará true se for bem-sucedido e false se não for, e estruturarei meu código usando uma cláusula if-else. Se a sua exceção for baseada em uma enumeração, você também pode retornar um valor de enumeração, semelhante ao windows HResults, e manter um valor de enumeração para quando o método for bem-sucedido.
Também é irritante ter um método lançar exceção quando não é a etapa final de um procedimento. Ter que escrever um fluxo de controle try-catch e desviar para o bloco catch é uma boa receita para espaguete e deve ser evitado.
Se você estiver avançando com exceções, tente retornar nulo, os usuários descobrirão que terão êxito se nenhuma exceção for lançada e nenhum tentará usar uma cláusula if-else para desviar o fluxo de controle.
fonte