Se uma linguagem suporta inerentemente exceções, então é preferível lançar exceções e os clientes podem capturar a exceção se não quiser que ela resulte em uma falha. Na verdade, os clientes do seu código esperam exceções e serão executados em muitos bugs porque eles não verificarão os valores de retorno.
Existem algumas vantagens em usar exceções se você tiver uma opção.
Mensagens
As exceções contêm mensagens de erro legíveis pelo usuário, que podem ser usadas pelos desenvolvedores para depuração ou até mesmo exibidas aos usuários, se desejado. Se o código consumidor não puder manipular a exceção, ele sempre poderá registrá-lo para que os desenvolvedores possam percorrer os logs sem precisar parar em todos os outros rastreios para descobrir qual era o valor de retorno e mapeá-lo em uma tabela para descobrir qual era o valor exceção real.
Com valores de retorno, não há informações adicionais que possam ser fornecidas facilmente. Alguns idiomas suportarão a realização de chamadas de método para obter a última mensagem de erro, portanto, essa preocupação é aliviada, mas isso exige que o chamador faça chamadas extras e, às vezes, exigirá acesso a um 'objeto especial' que contenha essas informações.
No caso de mensagens de exceção, forneço o máximo de contexto possível, como:
A policy of name "foo" could not be retrieved for user "bar", which was referenced in user's profile.
Compare isso com um código de retorno -85. Qual você prefere?
Pilha de chamadas
As exceções geralmente também possuem pilhas de chamadas detalhadas, que ajudam a depurar o código de maneira mais rápida e rápida, e também podem ser registradas pelo código de chamada, se desejado. Isso permite que os desenvolvedores identifiquem o problema normalmente na linha exata e, portanto, são muito poderosos. Mais uma vez, compare isso com um arquivo de log com valores de retorno (como -85, 101, 0, etc.), qual você prefere?
Falha na abordagem tendenciosa
Se um método for chamado em algum lugar que falhe, ele lançará uma exceção. O código de chamada deve suprimir a exceção explicitamente ou falhará. Eu achei isso incrível, porque durante o desenvolvimento e teste (e até mesmo na produção) o código falha rapidamente, forçando os desenvolvedores a consertá-lo. No caso de valores de retorno, se uma verificação de um valor de retorno for perdida, o erro é silenciosamente ignorado e as superfícies de erro são inesperadas, geralmente com um custo muito maior para depurar e corrigir.
Embrulhando e desembrulhando exceções
As exceções podem ser agrupadas dentro de outras exceções e depois desdobradas, se necessário. Por exemplo, seu código pode lançar ArgumentNullException
, que o código de chamada pode incluir dentro de UnableToRetrievePolicyException
, porque essa operação falhou no código de chamada. Embora possa ser mostrada ao usuário uma mensagem semelhante ao exemplo fornecido acima, algum código de diagnóstico pode desembrulhar a exceção e descobrir que um ArgumentNullException
causou o problema, o que significa que é um erro de codificação no código do seu consumidor. Isso pode disparar um alerta para que o desenvolvedor possa corrigir o código. Esses cenários avançados não são fáceis de implementar com os valores de retorno.
Simplicidade do código
Este é um pouco mais difícil de explicar, mas eu aprendi através desta codificação tanto com valores de retorno quanto com exceções. O código que foi escrito usando valores de retorno normalmente faria uma chamada e depois teria uma série de verificações sobre qual era o valor de retorno. Em alguns casos, ele chamaria outro método e agora terá outra série de verificações para os valores de retorno desse método. Com exceções, o tratamento de exceções é muito mais simples na maioria, senão em todos os casos. Você tem um bloco try / catch / finally, com o runtime tentando o melhor para executar o código nos blocos finally para limpeza. Até mesmo os blocos try / catch / finally aninhados são relativamente mais fáceis de seguir e manter do que os valores de retorno if / else e associados de vários métodos.
Conclusão
Se a plataforma que você está usando suportar exceções (esp. como Java ou .NET), então você não deve definitivamente assumir que não há outra maneira a não ser lançar exceções porque essas plataformas possuem diretrizes para lançar exceções e seus clientes vão esperar que sim. Se eu estivesse usando sua biblioteca, não me preocuparei em verificar os valores de retorno porque espero que exceções sejam lançadas, é assim que o mundo nessas plataformas é.
No entanto, se fosse C ++, seria um pouco mais difícil determinar porque existe uma grande base de código com códigos de retorno e um grande número de desenvolvedores está ajustado para retornar valores em oposição a exceções (por exemplo, o Windows é abundante) com HRESULTs). Além disso, em muitas aplicações, também pode ser um problema de desempenho (ou pelo menos percebido como).