Eu estava lendo o livro SCJP 6 de Kathe Sierra e me deparei com essas explicações de lançar exceções no método sobrescrito. Eu não entendi direito. Alguém pode me explicar isso?
O método de substituição NÃO deve lançar exceções verificadas que são novas ou mais amplas do que aquelas declaradas pelo método de substituição. Por exemplo, um método que declara uma FileNotFoundException não pode ser substituído por um método que declara uma SQLException, Exception ou qualquer outra exceção de tempo de execução, a menos que seja uma subclasse de FileNotFoundException.
Respostas:
Isso significa que se um método declara lançar uma determinada exceção, o método de substituição em uma subclasse só pode declarar lançar essa exceção ou sua subclasse. Por exemplo:
SocketException extends IOException
, masSQLException
não.Isso ocorre por causa do polimorfismo:
Se
B
tivesse decidido jogarSQLException
, então o compilador não poderia forçá-lo a pegá-lo, porque você está se referindo à instância deB
por sua superclasse -A
. Por outro lado, qualquer subclasse deIOException
será tratada por cláusulas (catch ou throws) que tratamIOException
A regra de que você precisa para se referir a objetos por sua superclasse é o Princípio de Substituição de Liskov.
Visto que exceções não verificadas podem ser lançadas em qualquer lugar, elas não estão sujeitas a esta regra. Você pode adicionar uma exceção não verificada à cláusula throws como uma forma de documentação, se quiser, mas o compilador não impõe nada sobre isso.
fonte
@Override public void foo() {...}
é legal.O método de substituição PODE lançar qualquer exceção não verificada (tempo de execução), independentemente de o método substituído declarar a exceção
Exemplo:
fonte
Na minha opinião, é uma falha no design da sintaxe Java. O polimorfismo não deve limitar o uso do tratamento de exceções. Na verdade, outras linguagens de computador não fazem isso (C #).
Além disso, um método é sobrescrito em uma subclasse mais especializada de modo que seja mais complexo e, por esse motivo, mais provável de lançar novas exceções.
fonte
Eu forneço esta resposta aqui para a velha questão, uma vez que nenhuma resposta informa o fato de que o método de substituição não pode lançar nada, aqui está novamente o que o método de substituição pode lançar:
1) lançar a mesma exceção
2) lançar a subclasse da exceção lançada do método sobrescrito
3) não jogue nada.
4) Não é necessário ter RuntimeExceptions nos lançamentos.
Pode haver RuntimeExceptions em throws ou não, o compilador não reclamará disso. RuntimeExceptions não são exceções verificadas. Apenas as exceções marcadas devem aparecer nos lançamentos se não forem capturadas.
fonte
Para ilustrar isso, considere:
Suponha que você então escreva:
Isso gerará um erro de compilação, porque r.close () lança uma IOException, que é mais ampla que FileNotFoundException.
Para corrigir isso, se você escrever:
Você obterá um erro de compilação diferente, porque está implementando a operação perform (...), mas lançando uma exceção não incluída na definição do método da interface.
Por que isso é importante? Bem, um consumidor da interface pode ter:
Se a IOException pudesse ser lançada, o código do cliente não estaria mais correto.
Observe que você pode evitar esse tipo de problema se usar exceções não verificadas. (Não estou sugerindo que você faça ou não, essa é uma questão filosófica)
fonte
Deixe-nos responder a uma pergunta da entrevista. Existe um método que lança NullPointerException na superclasse. Podemos substituí-lo por um método que lança RuntimeException?
Para responder a esta pergunta, diga-nos o que é uma exceção não verificada e verificada.
As exceções verificadas devem ser capturadas ou propagadas explicitamente conforme descrito em Tratamento básico de exceções try-catch-finally As exceções não verificadas não têm esse requisito. Eles não precisam ser pegos ou declarados lançados.
As exceções verificadas em Java estendem a classe java.lang.Exception. As exceções não verificadas estendem o java.lang.RuntimeException.
public class NullPointerException estende RuntimeException
As exceções não verificadas estendem o java.lang.RuntimeException. É por isso que NullPointerException é uma exceção não marcada.
Vejamos um exemplo: Exemplo 1:
O programa será compilado com sucesso. Exemplo 2:
O programa também será compilado com sucesso. Portanto, é evidente que nada acontece no caso de exceções não verificadas. Agora, vamos dar uma olhada no que acontece no caso de exceções verificadas. Exemplo 3: quando a classe base e a classe filha lançam uma exceção verificada
O programa será compilado com sucesso. Exemplo 4: Quando o método da classe filha está lançando exceção de verificação de borda em comparação com o mesmo método da classe base.
O programa não será compilado. Portanto, devemos ter cuidado ao usar exceções verificadas.
fonte
digamos que você tenha superclasse A com o método M1 jogando em E1 e a classe B derivando de A com o método M2 substituindo M1. M2 não pode lançar nada DIFERENTE ou MENOS ESPECIALIZADO que E1.
Por causa do polimorfismo, o cliente que usa a classe A deve ser capaz de tratar B como se fosse A. Herança ===> Is-a (B é-a A). E se esse código que lida com a classe A estivesse tratando da exceção E1, como M1 declara que lança essa exceção verificada, mas um tipo diferente de exceção foi lançado? Se M1 estava lançando IOException, M2 poderia muito bem lançar FileNotFoundException, pois é uma IOException. Os clientes de A poderiam lidar com isso sem problemas. Se a exceção lançada fosse mais ampla, os clientes de A não teriam a chance de saber sobre isso e, portanto, não teriam a chance de capturá-la.
fonte
Bem, java.lang.Exception estende java.lang.Throwable. java.io.FileNotFoundException estende java.lang.Exception. Portanto, se um método lançar java.io.FileNotFoundException, no método de substituição, você não pode lançar nada mais alto na hierarquia do que FileNotFoundException, por exemplo, você não pode lançar java.lang.Exception. Você poderia lançar uma subclasse de FileNotFoundException. No entanto, você seria forçado a lidar com FileNotFoundException no método sobrescrito. Crie um código e experimente!
As regras existem para que você não perca a declaração original de projeções ao ampliar a especificidade, pois o polimorfismo significa que você pode invocar o método sobrescrito na superclasse.
fonte
O método de substituição NÃO deve lançar exceções verificadas que são novas ou mais amplas do que aquelas declaradas pelo método de substituição.
Exemplo:
fonte
O método de substituição NÃO deve lançar exceções verificadas que são novas ou mais amplas do que aquelas declaradas pelo método de substituição.
Isso significa simplesmente que quando você substitui um método existente, a exceção que esse método sobrecarregado lança deve ser a mesma que o método original lança ou qualquer uma de suas subclasses .
Observe que verificar se todas as exceções verificadas são tratadas é feito em tempo de compilação e não em tempo de execução. Portanto, no próprio tempo de compilação, o compilador Java verifica o tipo de exceção que o método substituído está lançando. Uma vez que qual método sobrescrito será executado pode ser decidido apenas em tempo de execução, não podemos saber que tipo de exceção devemos capturar.
Exemplo
Digamos que temos classe
A
e sua subclasseB
.A
tem métodom1
e classeB
substituiu este método (vamos chamá-lom2
para evitar confusão ..). Agora, digamos quem1
lançaE1
em2
lançaE2
, que éE1
a superclasse de. Agora escrevemos o seguinte trecho de código:Observe que
m1
nada mais é do que uma chamada param2
(novamente, as assinaturas de método são as mesmas em métodos sobrecarregados, portanto, não se confunda comm1
em2
.. eles são apenas para diferenciar neste exemplo ... ambos têm a mesma assinatura). Mas, em tempo de compilação, tudo o que o compilador java faz é ir para o tipo de referência (classeA
, neste caso), verifica se o método está presente e espera que o programador o trate. Obviamente, você jogará ou pegaráE1
. Agora, em tempo de execução, se o método sobrecarregado lançarE2
, que éE1
a superclasse de, então ... bem, está muito errado (pela mesma razão que não podemos dizerB myBObj = new A()
). Conseqüentemente, o Java não permite isso. As exceções não verificadas lançadas pelo método sobrecarregado devem ser iguais, subclasses ou inexistentes.fonte
Para entender isso, vamos considerar um exemplo onde temos uma classe
Mammal
que define oreadAndGet
método que está lendo algum arquivo, fazendo alguma operação nele e retornando uma instância da classeMammal
.Class
Human
estende a classeMammal
e substitui oreadAndGet
método para retornar a instância de emHuman
vez da instância deMammal
.Para chamar
readAndGet
, precisaremos manipularIOException
porque é uma exceção verificada e a de um mamífero areadAndMethod
está jogando.E sabemos que o compilador
mammal.readAndGet()
está sendo chamado a partir do objeto da classe,Mammal
mas em tempo de execução a JVM resolverá amammal.readAndGet()
chamada do método para uma chamada da classeHuman
porquemammal
está segurandonew Human()
.Método
readAndMethod
deMammal
está jogandoIOException
e porque é um compilador de exceção verificada nos forçará a pegá-lo sempre que nós chamamosreadAndGet
emmammal
Agora suponha que
readAndGet
inHuman
está lançando qualquer outra exceção verificada, por exemplo, Exception e sabemos quereadAndGet
será chamado a partir da instância deHuman
becausemammal
is holdingnew Human()
.Porque para o compilador o método está sendo chamado
Mammal
, então o compilador nos forçará a manipular apenas,IOException
mas em tempo de execução sabemos que o método lançará umaException
exceção que não está sendo tratada e nosso código será interrompido se o método lançar a exceção.É por isso que isso é evitado no próprio nível do compilador e não temos permissão para lançar nenhuma exceção verificada nova ou mais ampla, porque ela não será tratada pela JVM no final.
Existem também outras regras que precisamos seguir ao substituir os métodos e você pode ler mais em Por que devemos seguir as regras de substituição de métodos para saber os motivos.
fonte
Que explicação atribuímos ao seguinte
A classe DerivedClass.java lança uma exceção de tempo de compilação quando o método print lança uma Exceção, o método print () da classe base não lança nenhuma exceção
Posso atribuir isso ao fato de que Exception é mais restrito que RuntimeException, pode ser No Exception (erro de Runtime), RuntimeException e suas exceções filho
fonte
O método de sobrescrita da subclasse só pode lançar múltiplas exceções verificadas que são subclasses da exceção verificada do método da superclasse, mas não pode lançar múltiplas exceções verificadas que não estão relacionadas à exceção verificada do método da superclasse
fonte
Java está dando a você a opção de restringir exceções na classe pai, porque está assumindo que o cliente restringirá o que é capturado . IMHO você essencialmente nunca deve usar esse "recurso", porque seus clientes podem precisar de flexibilidade no caminho.
Java é uma linguagem antiga que é mal projetada. As linguagens modernas não têm tais restrições. A maneira mais fácil de contornar essa falha é criar sua classe base
throw Exception
sempre. Os clientes podem lançar exceções mais específicas, mas tornar suas classes básicas realmente amplas.fonte
Regra de tratamento de exceções de verificação e não verificadas em métodos substituídos
- Quando o método da classe pai não declara nenhuma exceção, o método de substituição da classe filha pode declarar ,
- Quando o método da classe pai declara exceção não verificada, o método de substituição da classe filha pode declarar ,
- Quando o método da classe pai declara a exceção verificada, o método de substituição da classe filha pode declarar ,
Todas as conclusões acima são verdadeiras, mesmo se a combinação de exceção marcada e não verificada for declarada no método da classe-pai
Ref
fonte