1
resposta

Porque substituir o tratamento com os if por uma Exception:

No exemplo que utilizou o método saca substituirmos o "if", que faz o tratamento de qual saldo pode ou não sacar, por um "if" com acréscimo de uma exceção, eu sei que é só um exemplo da utilidade da exceção, porém não consigo imaginar o quão vantajoso seria isso num exemplo real.

1 resposta

Olá, tudo bem ?

A ideia nesse caso é mais analisar a diferença entre o retorno x lançamento de exceção do que do if. O if continua sendo necessário na sua lógica, por exemplo, pra perguntar se existe saldo pra poder sacar.

O problema em está na forma como o método saca sinaliza a quem o chamou se deu certo ou não a operação.

Imagine o seguinte cenário com a mesma classe Conta:

public class Conta {
    ...
    public boolean saca(double valor) {
        if (this.saldo >= valor) { // se tem saldo 
            this.saldo -=valor; // faz o débito
            return true; // fala que deu certo
        }
        return false; // senão fala que deu errado
    }
}

Agora vemos um teste:

public class TesteConta {
    public static void main(String[] args) {
        Conta conta = new Conta(500); // conta com saldo 500
        Caixa caixaEletronico = new Caixa(); // objeto que representa a máquina com suas funções de emissão e recebimento de cédulas

        conta.saca(100); // saca 100, pois tem saldo
        caixaEletronico.emite(100); // emite 100
    }
}

Contudo, as chamadas para essas operações não podem ocorrer de forma natural. Imagine se o valor solicitado fosse maior que o saldo. Nesse cenário não seria feito o débito, mas emitiria o dinheiro mesmo assim. Problema! Logo precisamos que a emissão só seja feita em caso de sucesso de saque. (Agora entra nossa análise)

Poderiamos pensar num if, basta verificar o retorno boolean do saca e saberemos se deu certo ou não, assim:

public class TesteConta {
    public static void main(String[] args) {
        Conta conta = new Conta(500); 
        Caixa caixaEletronico = new Caixa();

        if( conta.saca(700) ) { // tentamos sacar 700, e como não tem saldo            
            caixaEletronico.emite(700); // essa linha não será executada
        }
    }
}

Parece problema resolvido. Mas nem sempre é assim. Quem nos obriga a fazer o if e pegar o retorno antes de chamar o emite? Como o programador que vai usar sua classe Conta e chamar o saca sabe que é necessário esse cuidado ?

As vezes o código que funciona tem problemas ocultos. Acredite, em algum momento do projeto alguém vai chamar o saca e esquecer de fazer qualquer verificação de retorno (que não é obrigatório, a compilação não checa). =/

A ideia é não usar o retorno dos métodos como forma de dizer a terceiros se seu processamento deu certo ou não. E sim usar as Exceptions pra isso.

Veja:

public class Conta {
    public void saca(double valor) { // volta a ser void
        if (this.saldo >= valor) { // se tem saldo suficiente
            this.saldo -=valor; // então faz o débito e termina o trabalho do método
        } else { // senão, temos uma exceção à regra de negócio
            throw new IllegalArgumentException("Saldo insuficiente");
            // lançamos exceção notificando terceiros sobre o problema
        }
    }

}

O que muda? Agora caso o teste chame o método saca em casos onde a conta não tem saldo, ele não precisa lembrar de fazer a validação do retorno do método. O próprio método saca lança um alerta de risco pra JVM dizendo que uma falha ocorreu. Assim, caso o programador descuidado/esquecido (que todos nós seremos algum dia) não faça a tentativa de saque da forma certa (lembrando se deu certo ou não antes da emissão) a JVM quebra (para a aplicação e apresenta os logs) e não deixa a lógica ser corrompida.

public class TesteConta {
    public static void main(String[] args) {
        Conta conta = new Conta(500); 
        Caixa caixaEletronico = new Caixa();

        try { // tenta executar a sequência com cuidado
            conta.saca(700); // como não tem saldo uma exceção é lançada

            // essa linha só ocorre se tudo correr bem
            caixaEletronico.emite(700); // essa linha não será executada
        } catch (IllegalArgumentExeption e) {
            Sysout(e.getMessage()); // se houver problema o catch entra em cena
        }
    }
}

Ah, uma outra coisa que as exceptions ajudam é facilitar o entendimento sobre os detalhes do problema (o que o retorno do método também não consegue ajudar). Podemos lançar exceptions de vários tipos com mensagens descritivas.

Espero ter ajudado. Abraço!