A interface Java lança a melhor prática de exceções

Estou definindo uma nova API de interface … admitidamente não é algo que faço com frequência. Eu gostaria de definir os methods de interface para lançar uma exceção para permitir alguma flexibilidade para os implementadores. Eles podem, então, optar por lançar uma exceção, lançar uma subclass mais específica de exceção ou lançar nada. Eu li algumas vezes que, embora seja bom permitir a implementação de classs com essa flexibilidade, também é ruim definir o método de interface com “throws Exception”. Em vez disso, é recomendado subclassificar Exception (por exemplo, MyException) e lançar a subclass. As explicações para esta prática foram falta de detalhes, então alguém pode elaborar sobre esta melhor prática, por favor? Obrigado.

Eu posso apreciar a tentativa de dar aos implementadores alguma flexibilidade, mas a exceção é parte da API, então você deve refletir sobre quais exceções (verificadas) fazem sentido.

Ao dizer throws Exception , você não está ajudando os clientes da interface a entender que tipos de falhas devem dar a eles uma chance de reagir apropriadamente a eles. Você pode considerar semelhante a aceitar um parâmetro de método Object para permitir que os implementadores decidam quais argumentos eles podem aceitar. É bom para o implementador, mas um pesadelo para os clientes da interface.

Melhor ter uma ideia de quais exceções você precisa jogar mais tarde. Há o chamado princípio da substituição de Liskov, que recomenda não lançar exceções em subclasss que não seriam lançadas pela superclass.

Princípio da substituição de Liskov aka. design por contrato: http://en.wikipedia.org/wiki/Liskov_substitution_principle

Se você não tiver certeza de qual Exceção precisa ser emitida, use “throws Exception” (mesmo que não seja legal). Apenas não permita comportamentos inesperados implementando classs quando eles lançam exceções onde eles não foram planejados por você.

O pior caso seria um programador que lança desesperadamente exceções de tempo de execução devido à falta de declarações de lançamentos.

Eu prefiro lançar a subclass padrão Java de RuntimeException . Isso oferece a flexibilidade de permitir que a exceção se propague ou seja capturada sem referências à sua API.

Existem muitas subclasss para escolher em http://docs.oracle.com/javase/7/docs/api/java/lang/RuntimeException.html

Muitas vezes eu uso IllegalStateException ou IllegalArgumentException

Pense nas exceções verificadas como valores de retorno opcionais. A API cujos methods retornam Object é compreensivelmente rara, e o mesmo princípio deve ser aplicado para exceções verificadas.

A razão para dizer que um método de interface declarando para lançar a class base Exception é uma prática ruim é porque de fato tornaria uma instância daquela class base uma implementação legal da interface, que é o que você claramente quer evitar.

É por isso que você usaria apenas tipos de exceção especializados / personalizados em suas assinaturas.

Eu não iria tão longe quanto dizer que uma interface não deve declarar um lançamento de qualquer Exceção antecipadamente, como alguém disse em sua resposta anteriormente, porque a interface na verdade não é flutuante livre.

Você, como aquele que declara a interface, invoca ou usa os methods de uma determinada maneira, e faz afirmações sobre como os methods serão usados ​​pelo seu lado do código.

Na verdade, é um contrato que você cria. E as exceções fazem parte desse contrato. Na verdade, aquele que usa a interface (não o que a implementa) será feito com seu trabalho antes que uma implementação possa existir.

em geral, lançar uma exceção significa uma das duas opções:

  1. pedindo ao interlocutor para tomar uma ação com base em algo que aconteceu, geralmente esperando que ele tenha uma compreensão mais ampla / melhor da situação para tomar uma decisão
  2. Notificar o chamador que a ação falhou além do reparo

focando no primeiro tipo lançando exceções específicas é uma boa idéia e o chamado pode fazer:

 try { } catch (ServerIsBusyException ex) { // wait 10 sec and continue / try another server } catch (BadUserNameException ex2) { // try another name } .... 

segundo tipo é geralmente RuntimeException s que significa uma situação inesperada

veja uma boa explicação nesta resposta