Pergunta

Eu acho que a exceção.FillInstackTrace deve retornar exceção ou exceção derivada objetos. Considerando as duas funções abaixo,

public static void f() throws Throwable {
    try {
        throw new Throwable();
    } catch (Exception e) {
        System.out.println("catch exception e");
        e.printStackTrace();
    } 
}
public static void g() throws Throwable {
    try {
        try {
            throw new Exception("exception");
        } catch (Exception e) {
            System.out.println("inner exception handler");
            throw e.fillInStackTrace();
        }
    } catch (Exception e) {
        System.out.println("outer exception handler");
        e.printStackTrace();
    }
}
  1. o exception handler não poderia pegar o new Throwable() Na primeira função f().
  2. o exception handler poderia pegar o e.fillInstackTrace() Na segunda função g().
  3. Mas a segunda função g() ainda precisaria throws Throwable. Isso é realmente estranho, já que poderíamos pegar e.fillInstackTrace().

Portanto, minha pergunta é por que a exceção não é excepção.

EDITAR:
Para esclarecer Minha pergunta: o que quero dizer com "Strange Syntax" são

  1. Desde Exception.fillInStackTrace() Retorna Throwable referência, o manipulador de exceção que recebe Exception A referência não deve ser capaz de pegar a exceção. Porque return (Exception)e.fillInstackTrace().
  2. Já que foi projetado que o manipulador de exceção recebe Exception referência poderia lidar com o Throwable exceção, não há necessidade de marcar o método g() joga Throwable Exception.Cão o compilador Java nos aplicaria a fazê -lo.

obrigado.

Foi útil?

Solução

É realmente mais fácil responder suas perguntas a partir da pergunta 2.

Você perguntou: 2. Como foi projetado que a referência de exceção do manipulador de exceção pode lidar com a exceção de arremesso, não há necessidade de marcar o método G () lança exceção de arremesso. Mas o compilador Java nos aplicaria a fazê -lo.

RESPOSTA: Na verdade, o Catch (Exceção e) não pode pegar um lançável. Experimente isso:

try {
       Throwable t = new Throwable();
       throw t.fillInStackTrace();
} catch (Exception e) {
    System.out.println("outer exception handler");
    e.printStackTrace();
} 

Você verá que a cláusula de captura não pega o arremesso neste caso.

A razão pela qual a cláusula de captura funciona no seu método G () é que quando você invoca throw e.fillInStackTrace(), a chamada para preencher otrace realmente retorna uma exceção (isso é porque E é uma exceção em si). Como a exceção é uma subclasse de arremesso, isso não contradiz a Declaração de Fillinstacktrace.

Agora para a primeira pergunta

Você perguntou: 1. Como a exceção.FillInstackTrace () Retorno Referência lançável, o manipulador de exceção que recebe a referência de exceção não deve ser capaz de obter a exceção. Porque preenchiStackTrace ().

Resposta: Isso não é exatamente uma abatida implícita. Pense nisso como uma variação da sobrecarga.

Digamos que você tenha

void process(Throwable t){
   ...
}
void process(Exception e){
  ...
} 

Se você ligar process(someObject), será determinado em tempo de execução, seja o primeiro ou o segundo método do processo é chamado. Da mesma forma, se a cláusula de captura (Exceção e) pode ou não pegar seu arremesso será determinada em tempo de execução, com base no fato de você lançar uma exceção ou arremesso.

Outras dicas

Estou bastante intrigado com sua pergunta. Há claramente algo sobre exceções de Java / manuseio de exceção que você não entende. Então, vamos começar do início.

Em Java, todas as exceções (no sentido de que esse termo é usado na especificação da linguagem Java) são instâncias de uma classe que é uma subclasse de java.lang.Throwable. Existem duas (e apenas duas) subclasses diretas de arremesso; ou seja java.lang.Exception e java.lang.Error. Instâncias de todas essas classes ... incluindo instâncias de arremesso e erro ... são chamadas de exceções no JLS.

Um manipulador de exceção capta exceções (no sentido da JLS) que são compatíveis com o tipo de exceção usado no catch declaração. Por exemplo:

try {
    ....
} catch (Exception ex) {
    ...
}

vai pegar qualquer exceção lançada no try bloco que é uma instância de java.lang.Exception ou de um subtipo direto ou indireto de java.lang.Exception. Mas não vai pegar uma instância de java.lang.Throwable, porque isso (obviamente) não é um dos itens acima.

Por outro lado:

try {
    ....
} catch (Throwable ex) {
    ...
}

vai pegar uma instância de java.lang.Throwable.

Revendo seu exemplo à luz disso, é óbvio por que o f O método não está pegando a instância jogável: ele não corresponde ao tipo de exceção na cláusula de captura! Por outro lado, no g Método A instância de exceção correspondeu ao tipo de exceção na cláusula de captura e, portanto, é capturada.

Eu não entendo o que você está dizendo sobre a necessidade de jogar um arremesso g. Em primeiro lugar, o fato de o método declara que ele lança arremesso não significa que ele realmente precisa jogá -lo. Tudo o que está dizendo é que poderia jogue algo atribuível ao arremesso ... possivelmente em alguma versão futura do g método. Em segundo lugar, se você acrescentasse throw e; para o bloco de captura externo, ele gostaria Esteja jogando algo que é atribuível ao arremesso.

Por fim, geralmente é uma má idéia criar instâncias de arremesso, exceção, erro e tempo de execução. E você precisa ter muito cuidado quando e como os pega. Por exemplo:

try {
     // throws an IOException if file is missing
    InputStream is = new FileInputStream("someFile.txt");
    // do other stuff
} catch (Exception ex) {
    System.err.println("File not found");
    // WRONG!!!  We might have caught some completely unrelated exception;
    // e.g. a NullPointerException, StackOverflowError, 
}

EDITAR - em resposta dos comentários da OP:

Mas o que eu jogo com arreme e.fillinstacktrace (); Deve ser uma integridade de arremesso, não exceção!

O Javadoc diz especificamente que o objeto retornado é o objeto de exceção que você está chamando do método. O objetivo do fillInStacktrace() O método é preencher o rastreamento da pilha para um objeto existente. Se você quiser uma exceção diferente, você deve usar new para criar um.

Na verdade, quero dizer, o manipulador de exceção do Outter não deve pegar o lançável jogado por Throw e.fillinstacktrace ().

Eu expliquei por que isso acontece - porque o jogável é realmente a exceção original. Existe algo sobre a minha explicação que você não entende ou está simplesmente dizendo que não gosta da maneira como Java é definido?

Editar 2

E se o manipulador de exceção do Outter poderia lidar com a exceção jogável, por que devemos especificar que o método G lançaria a exceção de arremesso

Você entendeu mal o que eu estava dizendo ... que era que se você jogasse uma exceção, então o throws Throwable não seria redundante. OTOH, finalmente acho que entendo sua queixa.

Eu acho que o cerne de sua reclamação é que você receberá um erro de compilação com isso:

public void function() throws Exception {
    try {
        throw new Exception();
    } catch (Exception ex) {
        throw ex.fillInStackTrace();
        // according to the static type checker, the above throws a Throwable
        // which has to be caught, or declared as thrown.  But we "know" that the 
        // exception cannot be anything other than an Exception.
    }
}

Eu posso ver que isso é um pouco inesperado. Mas é inevitável que eu receba. Não há como (falta de uma grande mudança no sistema de tipo de Java) que você possa declarar a assinatura do fillInStacktrace Isso funcionará em todos os casos. Por exemplo, se você moveu a declaração do método para a classe de exceção, repetiria o mesmo problema com os subtipos de exceção. Mas se você tentasse expressar a assinatura usando um parâmetro de tipo genérico, ela implicaria fazer todas as subclasses de tipos genéricos explícitos lançáveis.

Felizmente, a cura é realmente simples; lançar o resultado de fillInStacktrace() do seguinte modo:

public void function() throws Exception {
    try {
        throw new Exception();
    } catch (Exception ex) {
        throw (Exception) (ex.fillInStackTrace());
    }
}

E o ponto final é que é muito incomum que um aplicativo ligue explicitamente fillInStacktrace(). À luz disso, simplesmente não valeria a pena que os designers de Java "pegassem suas entranhas" tentando resolver isso. Especialmente porque é realmente apenas um pequeno inconveniente ... no máximo.

Eu acho que você teria que perguntar a Frank Yellin (o @author do java.lang.Exception). Como outros disseram, fillInStackTrace() é declarado em Throwable e documentado para retornar this, então seu tipo de retorno deve ser Throwable. É apenas herdado por Exception. Frank poderia ter substituído isso em Exception, assim:

public class Exception extends Throwable{
    /**Narrows the type of the overridden method*/
    @Override
    public synchronized Exception fillInStackTrace() {
        super.fillInStackTrace();
        return this;
    }
}

... mas ele não. Antes do Java 1.5, o motivo é que ele teria produzido um erro de compilação. Em 1.5 e além, os tipos de retorno covariante são autorizadas e o acima é legal.

Mas meu palpite é que, se a substituição acima existia, você estaria perguntando por que RuntimeException não tem uma substituição semelhante, por que ArrayStoreException Não substitui essa substituição e assim por diante. Então Frank e amigos provavelmente não queriam escrever essas centenas de substituições idênticas.

Vale a pena notar que, se você estiver lidando com suas próprias classes de exceção personalizadas, você pode substituir facilmente o fillinStackTrace() Método como já fiz acima e obtenha o tipo mais estreito que você procura.

Usando genéricos, pode -se imaginar aumentando a declaração de Throwable para:

public class Throwable<T extends Throwable<T>>{
    public synchronized native T fillInStackTrace();
}

... Mas isso não é realmente satisfatório, por razões que estão além do escopo desta resposta.

fillInStackTrace Retorna a referência ao mesmo objeto. É o encadeamento de método para permitir o refúgio do Exception e redefinir rastreamento da pilha da exceção.

public static void m() {
    throw new RuntimeException();

}

public static void main(String[] args) throws Throwable {
    try {
        m();
    } catch (Exception e) {
        e.printStackTrace();
        throw e.fillInStackTrace();
    }
}

O tipo de retorno do método pode ser apenas o tipo de base que é Throwable. Pode ser generificado para que o método retorne o tipo parametrizado. Mas esse não é o caso por enquanto.

RuntimeException e = new RuntimeException();
Throwable e1 = e.fillInStackTrace();
System.out.println(e1.getClass().getName()); //prints java.lang.RuntimeException
System.out.println(e == e1); //prints true

fillInStackTrace() é definido por Throwable, não Exception.

Nem todas as subclasses de Throwable são exceções (Error, por exemplo). Tão longe quanto Throwable está preocupado, a única coisa que pode garantir sobre o valor de retorno de fillInStackTrace() é isso é um exemplo de Throwable (já que apenas retorna o mesmo objeto, como Chandra Patni notado).

Na realidade fillInStackTrace Retorna o mesmo objeto em que foi invocado.

e.fillInStackTrace == e é sempre verdadeiro

É apenas um atalho, você também pode apenas escrever

    } catch (Exception e) {
        System.out.println("inner exception handler");
        e.fillInStackTrace();
        throw e;
    }

ou use um elenco

    throw (Exception) e.fillInStackTrace();

Btw, o mesmo acontece com initCause().

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top