Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

Dúvida sobre formas de tratar uma Exception

Olá, gostaria de saber pq quando declaro throws estou tratando uma exception. Já não havia o try/catch na classe TestaConta tratando? Entendi que declarando throws diz que pode haver uma exception.

6 respostas

Olá Kelvin. Basicamente a diferença entre o throws e o try/catch é:

throws: se ocorrer uma exceção, ela é capturada mas não tratada, ela é lançada para o método que a chamou. Exemplo: eu tenho a classe A e a classe B

class A{
   B b = new B();
   b.metodoException();
}

class B{
   public void metodoException() throws Exception{
       // se ocorrer alguma exceção aqui ela sera lançada para a classe A que foi que de onde o método foi chamado
   }
}

try/catch: se ocorrer uma exceção, ela é capturada no try e tratada no catch.

Exemplo:

class A{
   B b = new B();
   b.metodoException();
}

class B{
   public void metodoException() {
try{
       // se ocorrer alguma exceção ela sera capturada aqui
}catch(Exception e){
   // e tratada aqui sem que A nem saiba de qualquer problema
}

   }
}

Já no caso de ter um método com com as duas declarações seria pelo fato de que pode ocorrer vários tipos de exceção num mesmo bloco.

Exemplo: eu posso ter um try/catch para tratar um divisão por zero

public void divisaoException(tipo valor1, tipo valor2) {
try{
   // suponha que um dos valores seja nulo
   valor1/valor2;
}catch(ExceptionDivisao ed){ Exceção da divisão por zero}
}

nesse caso vai ocorrer uma exceção não de divisão, mas de valor nulo, que não foi tratado, nesse caso você teria duas opções adicionar o throws pra tratar o valor nulo(que acho ter sido sua dúvida) ou o que considero mais adequado que é adicionar um segundo catch e nele tratar o valor nulo.

Oi Kelvin e João

Na linguagem java o comando para tratar a exceção é o try/catch. O throws na verdade não faz nenhum tratamento de erros, ele é apenas utilizado para demarcar que um método lança uma exceção que precisa ser tratada.

No java existem dois tipos de exceção: checked e unchecked (também conhecida como runtime exception).

Checked exceptions são as exceções que são filhas de Exception mas não fazem parte da hierarquia de RuntimeException. Essas exceções são geralmente utilizadas para indicar uma situação de erro esperada na regra de negócio, por exemplo, quando um usuário tenta sacar dinheiro de um caixa eletrônico ele pode não ter saldo suficiente ou a conta pode estar bloqueada, nesse caso, estamos executando uma operação ilegal no programa (um erro que seria indicado por uma exceção), mas essa exceção é esperada, já que ela faz parte do fluxo de negócio e, por isso, a aplicação deveria ser forçada a tratar essa exceção.

As runtime exceptions são as exceções que herdam de RuntimeException no java. Quando um método lança uma runtime exception o programador não é obrigado a tratá-la (ao contrário da checked exception). Elas geralmente indicam um erro de programação como acessar uma referência não inicializada (NullPointerException) ou enviar um argumento inválido para o método (IllegalArgumentException).

Agora, para ilustrar as diferenças que existem, vamos ver um código que vocês podem testar:

public class CheckedSaldoInsuficienteException extends Exception {}

public class Conta {
    private double saldo;

    public void saca(double valor) throws CheckedSaldoInsuficienteException {
        if(valor <= this.saldo) {
            this.saldo -= valor;
        } else {
            throw new CheckedSaldoInsuficienteException();
        }
    }
}

Nesse exemplo, como o CheckedSaldoInsufienteException é uma checked exception do java, o método saca da conta é obrigado a declarar que a exceção pode ser lançada (através do throws CheckedSaldoInsuficienteException). Qualquer classe que tentar chamar esse método saca da Conta é obrigada pelo compilador do java a tratar a exceção.

public class CaixaEletronico {
   public static void main(String[] args){
      try{
         Conta c = new Conta();
         c.saca(500);
      } catch (CheckedSaldoInsufienteException e) {
          // faz o tratamento
      }
   }
}

Se removermos o try/catch do código acima, teremos um erro de compilação. Agora vamos ver o que acontece se a exceção lançada for uma unchecked exception:

public class UncheckedSaldoInsuficienteException extends RuntimeException{}

public class Conta {
    private double saldo;

    public void saca(double valor) {
        if(valor <= this.saldo) {
            this.saldo -= valor;
        } else {
            throw new UncheckedSaldoInsuficienteException();
        }
    }
}

A primeira diferença que pode ser notada, é que como UncheckedSaldoInsuficienteException herda de RuntimeException, o código do método saca não precisa mais colocar o throws. E no código do CaixaEletronico não precisamos mais do try/catch:

public class CaixaEletronico {
   public static void main(String[] args){
      Conta c = new Conta();
      c.saca(500);
   }
}

`` public class ValorInvalidoException extends Exception{ private final double valor;

public ValorInvalidoException(double valor) { super("Depósito negativo: " + valor); this.valor = valor; } }

public class TestePrograma { public static void main(String[] args) throws ValorInvalidoException { ContaCorrente cc = new ContaCorrente();

// try { cc.deposita(-1); // } // catch (ValorInvalidoException e){ // System.out.println(e.getMessage()); // } System.out.println(cc.calculaTributos());

//Testando Polimorfismo: Tributavel t = cc; System.out.println(t.calculaTributos()); } } ``

Repare que o código acima compila, mesmo eu comentando o try/catch, pois eu adicionei throws ValorInvalidoException. Eu achei isso curioso e queria entender.

public class ValorInvalidoException extends Exception{ private final double valor; public ValorInvalidoException(double valor) { super("Depósito negativo: " + valor); this.valor = valor; } }

public class TestePrograma { public static void main(String[] args) throws ValorInvalidoException { ContaCorrente cc = new ContaCorrente(); // try { cc.deposita(-1); // } // catch (ValorInvalidoException e){ // System.out.println(e.getMessage()); // } System.out.println(cc.calculaTributos()); //Testando Polimorfismo: Tributavel t = cc; System.out.println(t.calculaTributos()); } }

public class TestePrograma {
    public static void main(String[] args) throws ValorInvalidoException {
        ContaCorrente cc = new ContaCorrente();

//        try {
            cc.deposita(-1);
//        }
//        catch (ValorInvalidoException e){ 
//            System.out.println(e.getMessage());
//            }
        System.out.println(cc.calculaTributos());

        //Testando Polimorfismo:
        Tributavel t = cc;
        System.out.println(t.calculaTributos());
    }
}

public class ValorInvalidoException extends Exception{
    private final double valor;

    public ValorInvalidoException(double valor) {
        super("Depósito negativo: " + valor);
        this.valor = valor;
    }
}

Agora acho que vai!

solução!

Oi Kelvin

Quando você coloca o throws em um código que pode lançar uma checked exception você está basicamente delegando a responsabilidade para quem chamou o método. A exceção ainda precisa ser tratada em algum nível da pilha de execução.

No caso do main, temos a impressão que a exceção foi tratada por que não colocamos o try/catch e o código continua compilando, mas isso é apenas uma ilusão. Nesse caso a exceção é lançada para a JVM e o tratamento implementado pelo java é mostrar a stack trace para o usuário.