Perguntas sobre MVC Desktop! Existe solução? (+ MVP,MVC WEB,Observer e Exception's)

Sobre o código, ele ficaria melhor se você der mais responsabilidade à eles:

public class Cliente
{
  Documento doc;
  String nome;

  ClienteDao dao = DaoFactory.get(Cliente.class);

  public Cliente(Documento doc, String nome)
  {
     this.doc = doc;
     
     if (nome = null)
       throw new IllegalArgumentException("O nome não pode ser nulo.");

     nome = nome.trim();
     if (nome.isEmpty())
       throw new IllegalArgumentException("O nome não pode estar em branco.");

     this.nome = nome;
  }

  public void cadastrar() throws CadastroDeClienteException
  {
     try
     {
       if (dao.jaEstaCadastrado(this))
         throw new ClienteJaCadastradoException();

       dao.cadastrar(this);
     }
     catch (PersistenciaException ex)
     {
       throw new CadastroDeClienteException(ex);
     }
  }
}

public abstract class Documento {}

public class CPF extends Documento {
  String numero;
  public CPF(String numero)
  {
    if(!Util.validaCPF(numero))  
      throw new IllegalArgumentException("CPF inválido.");
    this.numero = numero;
  }
}

[color=blue]Fala Brunão[/color], boa noite! Desculpa a demora para postar a resposta é que precisei ler com calma para entender! :smiley:
Obrigado por continuar atento ao tópico, sua ajuda está sendo muito importante. Agradeço muito! :wink:

Entendi a explicação e também o código. Legal ter criado a classe abstrata Documento, pois assim a classe CPF pode estende-la e futuramente uma classe RG, CNPJ ou qualquer outra relasionada a um documento também poderá. Também gostei muito da separação de responsabilidade nas exceções, ou seja, onde cada uma deve estar!

Como postou anteriormente, arrumei o ClienteControl (controle). Veja como ficou:

Controle

public class ClienteControl {     
         
   private Cliente cli = null;     
     
   ClienteControl(Cliente cli) {     
      this.cli = cli;     
   }   
     
   public void executar(String nome, String cpf) throws CadastroDeClienteException { 
         CPF doc = new CPF(cpf);
         this.cli = new Cliente(doc, nome);
         this.cli.cadastrar();
   }       
}  

Modelo: Está a classe Cliente implementada pelo Bruno na sua postagem anterior! NADA ALTERADO!

Visão

   import javax.swing.*;
   import java.awt.event.*;

    public class ClienteView extends JPanel {
    
      private ClienteControl controller = null;
      private JButton btnExecute;
      private JTextField nome;   
      private JTextField cpf;   
      private JLabel lblCad; 
   
       public ClienteView(ClienteControl controller) {
         this.controller = controller;
         this.initialize();
      }
   
       private void initialize() {
         nome = new JTextField(10);   
         add(nome);   
         cpf = new JTextField(10);   
         add(cpf);   
         btnExecute = new JButton("Cadastrar");   
         btnExecute.addActionListener(
                new ActionListener() {
                   public void actionPerformed(ActionEvent e) {		     
                     View.this.executar();
                  }
               });
         add(btnExecute);   
         lblCad = new JLabel();   
         add(lblCad);   
      }
   
       private void executar() {
         try {
            this.controller.executar(nome.getText(), cpf.getText());
            lblCad.setText("Cadastro realizado com sucesso");
         }
             catch (CadastroDeClienteException e) {
               lblCad.setText(e.getMessage());
            } 
      }  
   }

Pronto, então a pergunta de hoje: (1) Como a mensagem da exceção que ocorrer no modelo deverá ser mostrada ao usuário na visão?
Ou seja, como o JLabel lblCad de ClienteView vai receber a mensagem [color=blue]“O nome não pode ser nulo.”[/color] caso ela seja lançada no Cliente?
Ou como o mesmo JLabel vai receber a mensagem [color=blue]“CPF inválido.”[/color] caso ela seja lançada na classe CPF?
Lembrando que ambas são [color=red]IllegalArgumentException[/color] e quando ocorrem são mostradas no console!

Outra pergunta: (2) A classe CadastroDeClienteException estende RuntimeException, Exception ou não estende nada? E ClienteJaCadastradoException, estende alguém?

Fico no aguardo pelas respostas, volto a agradecer a todos que estão colaborando. É incrível a magia que o grupo de usuários do GUJ realiza. Só participando mesmo para descobrir. Vejo em todos os posts o esforço do pessoal para tentar chegar a melhor forma de responder as perguntas. Estão todos de parabéns. E não deixem de opinar, mesmo sendo a primeira vez que está lendo o tópico (no primeiro post deixo algumas orientações, se necessário para não se perder no tópico). [color=red][size=18]OBRIGADO GALERA![/color][/size]

[quote=pedromuyala]
Pronto, então a pergunta de hoje: (1) Como a mensagem da exceção que ocorrer no modelo deverá ser mostrada ao usuário na visão?
Ou seja, como o JLabel lblCad de ClienteView vai receber a mensagem [color=blue]“O nome não pode ser nulo.”[/color] caso ela seja lançada no Cliente?
Ou como o mesmo JLabel vai receber a mensagem [color=blue]“CPF inválido.”[/color] caso ela seja lançada na classe CPF?
Lembrando que ambas são [color=red]IllegalArgumentException[/color] e quando ocorrem são mostradas no console![/quote]
Mude os tipos das exceções para alguma do domínio da tua aplicação, ou dê um catch nesse IllegalArgumentException, ou mesmo em Exception. Esses dois últimos não recomentdo.

ClienteJaCadastradoException é uma CadastroDeClienteException. Este, por sua vez, pode ser o que você quiser, desde ele seja algo que faça parte da hierarquia de Exception (Throwable para falar a verdade).

[color=red]Boa noite Bruno,[/color] tudo beleza por aí? :smiley: MUITÍSSIMO OBRIGADO por continuar colaborando com o tópico!

[quote=Bruno Laturner][quote=pedromuyala]
Pronto, então a pergunta de hoje: (1) Como a mensagem da exceção que ocorrer no modelo deverá ser mostrada ao usuário na visão?
Ou seja, como o JLabel lblCad de ClienteView vai receber a mensagem [color=blue]“O nome não pode ser nulo.”[/color] caso ela seja lançada no Cliente?
Ou como o mesmo JLabel vai receber a mensagem [color=blue]“CPF inválido.”[/color] caso ela seja lançada na classe CPF?
Lembrando que ambas são [color=red]IllegalArgumentException[/color] e quando ocorrem são mostradas no console![/quote]
Mude os tipos das exceções para alguma do domínio da tua aplicação, ou dê um catch nesse IllegalArgumentException, ou mesmo em Exception. Esses dois últimos não recomentdo.[/quote]

:arrow: Portanto, vamos ao código-exemplo, na maneira que entendi:
[color=red]OBS IMPORTANTE:[/color] Como ainda não quero entrar na persistencia dos dados, não estou aplicando até este momento nenhuma chamada as classes de persistencia no código-exemplo, limitando o entendimento somente entre a comunicação M-V-C com Exception’s, ok?

MODELO: abstract Documento

    public abstract class Documento {}

MODELO: CPF

    public class CPF extends Documento {   
      String numero;   
       public CPF(String numero)   
      {   
         if(!Util.validaCPF(numero))     
            throw new CPFException();   
         this.numero = numero;   
      }   
   }  

MODELO: Cliente

    public class Cliente {
   
      private String nome;
      private Documento cpf;
   
       public Cliente() {
      }
   	
       public Cliente(Documento cpf, String nome)   
      {   
         this.setCPF(cpf);       
         this.setNome(nome);   
      }   
   
       Documento getCPF() {
         return this.cpf;
      }
   			
       void setCPF(Documento cpf) {
         this.cpf = cpf;
      }
   
       String getNome() {
         return this.nome;
      }
   			
       void setNome(String nome) {
         if (nome == null)   
            throw new ClienteException("O nome não pode ser nulo.");   
         nome = nome.trim();
         if (nome.isEmpty())
            throw new ClienteException("O nome não pode estar em branco.");
         this.nome = nome;
      }
   }

CONTROLE:

    public class ClienteControl {       
           
      private Cliente cli = null;       
       
       ClienteControl(Cliente cli) {       
         this.cli = cli;       
      }     
       
       public void cadastrar(String nome, String cpf) throws CadastrarClienteException {
         try {      
            CPF doc = new CPF(cpf);
            this.cli = new Cliente(doc, nome);
         }
             catch(CPFException e) {
               throw new CadastrarClienteException(e.getMessage());
            }
             catch(ClienteException e) {
               throw new CadastrarClienteException(e.getMessage());
            }				
      }         
   }    

VISÃO:

    public class View extends JPanel {
    
      private ClienteControl controller = null;
      private JButton btnExecute;
      private JTextField nome;   
      private JTextField cpf;   
      private JLabel lblCad; 
   
       public View(ClienteControl controller) {
         this.controller = controller;
         this.initialize();
      }
   
       private void initialize() {
         nome = new JTextField(10);   
         add(nome);   
         cpf = new JTextField(10);   
         add(cpf);   
         btnExecute = new JButton("Cadastrar");   
         btnExecute.addActionListener(
                new ActionListener() {
                   public void actionPerformed(ActionEvent e) {		     
                     View.this.cadastrar();
                  }
               });
         add(btnExecute);   
         lblCad = new JLabel();   
         add(lblCad);   
      }
   
       private void cadastrar() {
         try {
            this.controller.cadastrar(nome.getText(), cpf.getText());
            lblCad.setText("Cadastro realizado com sucesso");
         }
             catch (CadastrarClienteException e) {
               lblCad.setText(e.getMessage());
            } 
      }  
   }

ClienteJaCadastradoException é uma CadastroDeClienteException. Este, por sua vez, pode ser o que você quiser, desde ele seja algo que faça parte da hierarquia de Exception (Throwable para falar a verdade).
[/quote]
Exceções: CPFException

    public class CPFException extends RuntimeException{
       public CPFException() {
         super("CPF Inválido");
      }
   }

Exceções: ClienteException

    public class ClienteException extends RuntimeException {
   
        public ClienteException(String msg) {
         super(msg);
      }
   }

Exceções: CadastrarClienteException

    public class CadastrarClienteException extends RuntimeException {
   
       public CadastrarClienteException(String msg) {
         super(msg);
      }
   }

:arrow: OQ EU FIZ: Tentei seguir o conselho de usar RuntimeException no lugar de Exception e de separar “fronteiras entre nações” ([color=blue]Ver linhas vermelhas na imagem em anexo[/color])
Dessa forma, ClienteException trabalha para a classe Cliente e CPFException trabalha para a classe CPF. No controle, como é ele quem transfere os dados da visão para o modelo (cadastra os dados informados nos campos da visão para o BEAN Cliente no modelo) então é encapsulada as mensagens das exceções que aparecerem entre o try{}…catch(){} como CadastrarClienteException. A visão, por sua vez, faz a leitura final de CadastrarClienteException mostrando as mensagens ao usuário, caso elas ocorram.

Agora a pergunta é, com toda humildade do mundo: Estou causando confusão na cabeça dos programadores ou realmente dessa vez ficou certo? Estou fazendo má prática em algum lugar? :shock:

Volto a pedir a todos muita calma e paciência comigo. É uma coisa que estou fazendo todo esforço possível para conseguir entender e não sair por aí vida afora desenvolvendo aqueles famosos códigos que nem o cara que desenvolveu vai entender! :frowning: Como já havia dito em postagens anteriores eu quero mesmo aprender e não me aproveitar da boa vontade das pessoas que estão ajudando fazendo essas como “empregados”. Pode ter certeza que a sua ajuda aqui será importante não só para mim mas para muitas pessoas que sofrem em entender o padrão MVC. :wink:
[size=15]
Obrigado a todos que estão lendo ou tentando ajudar no tópico! Não deixem de opinar, criticar, sugerir… é muito importante sua participação!
Um abração especial aí para o pessoal do GUJ, para os usuários fantomas, Bruno Laturner, André e todos aqueles que postaram também no início do tópico!
[/size]

Antes de começar, uma opinião:

Eu acho um pouco de exagero fazer uma exceção para cada coisa, por mim só atirar um MinhaAplicacaoException bem genérica já resolveria a maioria dos problemas. Não acho que valha a pena criar várias exceções a menos que você vá fazer algo com elas. A especialização é boa quando você precisa tratar casos especiais de forma diferente, que fogem à regra de tratamento da exceção principal. Não é isso que temos ainda.
Com isto dito, vamos continuar com o que já foi feito.

Fazendo todas elas estender diretamente de RuntimeException faz com que você tenha que dar um catch RuntimeException para pegar todos de maneira uniforme. Isso não é bom.

MinhaAplicacaoException é a exceção do domínio da aplicação que marca a fronteira. Todo o resto das exceções estendem dela, e também implementam os mesmos construtores.

[code]package minhaaplicacao.exception;

public class MinhaAplicacaoException extends RuntimeException
{
public MinhaAplicacaoException() {
super();
}

public MinhaAplicacaoException(String message) {
    super(message);
}

public MinhaAplicacaoException(Throwable cause) {
    super(cause);
}

public MinhaAplicacaoException(String message, Throwable cause) {
    super(message, cause);
}

}[/code]

private void cadastrar() { try { this.controller.cadastrar(nome.getText(), cpf.getText()); lblCad.setText("Cadastro realizado com sucesso"); } catch (MinhaAplicacaoException e) { lblCad.setText(e.getMessage()); } }

Eu tinha mais umas coisas pra falar, mas o sono está atrapalhando a organizar as idéias hehe. :slight_smile: ;O

Opa Bruno… magina cara não quero atrapalhar seu sono! :smiley:
Mas fiquei curioso com a frase final que avisou! Fico no aguardo, abração!

Acho que era só isso mesmo.

Quando for atirar uma nova exceção a partir de outra, use os construtores da classe que recebem um Throwable, ao invés de mandar só a String com uma mensagem. Daí dá para saber de onde veio a exceção.

Na maioria dos casos eu preferiria deixar a exceção se propagar até o final, sem encapsular uma dentro da outra. Não dou um catch quando não tenho nada para fazer com a exceção. Polui menos o código também.

Fala Bruno, beleza, boa tarde! :smiley:
Acho que agora sim eu entendi a essência da Exception! Ou seja, CPFException, ClienteException, OutraExeption… estendem MinhaAplicacaoException e no controle, no método cadastrar(), eu deixo só o throws MinhaAplicacaoException para passar até a visão e aí sim finalmente uso o try{}… catch(){} para colocar a mensagem no JLabel. É isso? Agora acertei? :roll: Por favor Bruno, não deixe de confirmar se é isso mesmo para que eu possa implementar e mostrar o código aqui para todos. [color=red]Obrigadão Bruno, fico no aguardo[/color]!

É isso mesmo.

O próximo passo é tratar erros que você não esteja esperando.

Tente lançar de propósito RuntimeException que não seja um MinhaAplicaçãoException, lá de dentro do model, para ver o comportamento da aplicação quanto à essas exceções.

Opa Bruno, é o Pedro. [color=olive]Fiz como mandou e realmente ficou 100% a implementação![/color] :wink:
Antes de postar o código, vou responder a pergunta que me fez:

A exceção apareceu no console e não na visão. Até entendi o porque pois essa throw new RuntimeException("…"); no modelo não estende a classe MinhaAplicacaoException.

Vixe, mas e agora… como vou tratar as exceções (erros) que não conheço?

Já sei que não é para ficar atirando qualquer coisa senão vou acabar criando um Mega Zord Exception no método do controle. :lol: Mas a princípio acredito que não vou poder ficar mostrando na visão qualquer tipo de exceção que vier das camadas de baixo nível até para que não apareçam mensagens que um simples usuário do sistema não vai entender. Ex: NullPointerException, RuntimeException ou qualquer outra que estende a classe Exception. Porém não posso simplemesmente ignorar o erro pois aí estaria cometendo uma “infração de sete pontos na carteira”, principalmente nas Exception’s checadas. Imaginem o problemão caso ignore uma SQLException na hora de cadastrar um cliente… Acredito eu que agora sim vai entrar uma espécie de encapsulamento ou voltei a falar abobrinhas? Desculpem se for o caso. :oops:

Mas estou ficando muito feliz! :smiley: :smiley: :smiley: Até porque é a primeira vez que estou entendendo como escrever códigos de forma legível ao mundo dos javeiros.
Realmente é muito legal a magia do Java quando bem escrito, bem estruturado!

[size=15]Fico no aguardo pela resposta. Volto a agradecer a todos que estão acompanhando o tópico, sejam os veteranos como os novos, e ao pessoal do GUJ que mantém essa comunidade maravilhosa! Volto a dizer, sei que estou sendo repetitivo, mas não deixe de opinar, sugerir mudanças, criticar, perguntar, doar idéias, reclamar… enfim tudo aquilo que possa colaborar com o tópico. Tenho a absoluta certeza que muita gente, principalmente o pessoal novo na linguagem JAVA estará aprendendo muito aqui.[/size] :thumbup:

Um abração para todos, [color=blue][size=15]OBRIGADO![/size][/color]

Ninguém mesmo? Mas fico no aguado. :smiley:

Exceções que você não conhece são as unchecked, Errors ou RuntimeExceptions. Errors não tem muito o que fazer a não ser fechar o programa(e tentar logar o erro). RuntimeExceptions geralmente são erros de programação, também o que dá para fazer é logar a exceção e dar desculpas.

Em ambos os casos você se previne escrevendo bons códigos com boas práticas.

Fala Brunão, boa tarde! :smiley:

Então se ocorrer um erro/exception que por ventura venha ocorrer e não estende MinhaAplicacaoException, no máximo, deve ser logado e só?

Bruno, você acha que estou fazendo certo o MVC se comunicar através de Exceções?

Eu gostei da idéia porque todas as letras do (M-V-C) interagem sem precisar instanciar uma a outra. Até aí, legal, afinal: É um cadastro. Ou seja, a informação transita da visão -> controle -> modelo. Se algum problema ocorre nesse meio (Exception) ela facilmente chega a visão. :smiley:

Mas e se eu fizer uma busca que retornara clientes? Aí o fluxo é invertido (visão <- controle <- modelo). Não vou trazer informações do modelo até aparecer na visão através de Exception’s, estou errado? :frowning:

Obrigado Bruno, fico no aguardo pela resposta! :wink:

[quote=pedromuyala]Fala Brunão, boa tarde! :smiley:

Então se ocorrer um erro/exception que por ventura venha ocorrer e não estende MinhaAplicacaoException, no máximo, deve ser logado e só?

Bruno, você acha que estou fazendo certo o MVC se comunicar através de Exceções?

Eu gostei da idéia porque todas as letras do (M-V-C) interagem sem precisar instanciar uma a outra. Até aí, legal, afinal: É um cadastro. Ou seja, a informação transita da visão -> controle -> modelo. Se algum problema ocorre nesse meio (Exception) ela facilmente chega a visão. :smiley:

Mas e se eu fizer uma busca que retornara clientes? Aí o fluxo é invertido (visão <- controle <- modelo). Não vou trazer informações do modelo até aparecer na visão através de Exception’s, estou errado? :frowning:

Obrigado Bruno, fico no aguardo pela resposta! :wink:[/quote]

[color=red]Opa pessoal, estou postando o código já implementado (qua havia prometido) já com as exceções para ficar viável o entendimento da pergunta acima.[/color]

Classes do Modelo: [abstract Documento, Cliente e CPF]

abstract Documento:

    public abstract class Documento {}

CPF:

    public class CPF extends Documento {   
      String numero;   
       public CPF(String numero)   
      {   
         if(!Util.validaCPF(numero))     
            throw new CPFException();   
         this.numero = numero;   
      }   
   }  

Cliente:

    public class Cliente {
   
      private String nome;
      private Documento cpf;
   
       public Cliente() {
      }
   	
       public Cliente(Documento cpf, String nome)   
      {   
         this.setCPF(cpf);       
         this.setNome(nome);   
      }   
   
       Documento getCPF() {
         return this.cpf;
      }
   			
       void setCPF(Documento cpf) {
         this.cpf = cpf;
      }
   
       String getNome() {
         return this.nome;
      }
   			
       void setNome(String nome) {
         if (nome == null)   
            throw new ClienteException("O nome não pode ser nulo.");   
         nome = nome.trim();
         if (nome.isEmpty())
            throw new ClienteException("O nome não pode estar em branco.");
         this.nome = nome;
      }
   }

Classe do Controle:

    public class ClienteControl {       
           
      private Cliente cli = null;       
       
       ClienteControl(Cliente cli) {       
         this.cli = cli;       
      }     
       
       public void cadastrar(String nome, String cpf) throws CadastroDeClienteException {
         CPF doc = new CPF(cpf);
         this.cli = new Cliente(doc, nome);
      }
   }

Classe da Visão:

   import javax.swing.*;
   import java.awt.event.*;

    public class View extends JPanel {
    
      private ClienteControl controller = null;
      private JButton btnExecute;
      private JTextField nome;   
      private JTextField cpf;   
      private JLabel lblCad; 
   
       public View(ClienteControl controller) {
         this.controller = controller;
         this.initialize();
      }
   
       private void initialize() {
         nome = new JTextField(10);   
         add(nome);   
         cpf = new JTextField(10);   
         add(cpf);   
         btnExecute = new JButton("Cadastrar");   
         btnExecute.addActionListener(
                new ActionListener() {
                   public void actionPerformed(ActionEvent e) {		     
                     View.this.cadastrar();
                  }
               });
         add(btnExecute);   
         lblCad = new JLabel();   
         add(lblCad);   
      }
   
       private void cadastrar() {
         try {
            this.controller.cadastrar(nome.getText(), cpf.getText());
            lblCad.setText("Cadastro realizado com sucesso");
         }
             catch (CadastroDeClienteException e) {
               lblCad.setText(e.getMessage());
            } 
      }  
   }

Classes de Exceções: [CadastroDeClienteException, ClienteException e CPFException]

CadastroDeClienteException:

    public class CadastroDeClienteException extends RuntimeException {
    
       public CadastroDeClienteException() {   
         super();   
      }   
   
       public CadastroDeClienteException(String message) {   
         super(message);   
      }   
   
       public CadastroDeClienteException(Throwable cause) {   
         super(cause);   
      }   
   
       public CadastroDeClienteException(String message, Throwable cause) {   
         super(message, cause);   
      }   
   }  

ClienteException:

    public class ClienteException extends CadastroDeClienteException {
   
       public ClienteException(String msg) {
         super(msg);
      }
   }

CPFException:

    public class CPFException extends CadastroDeClienteException {
       public CPFException() {
         super("CPF Inválido");
      }
   }

[size=16]A pergunta é a citada nesta mensagem.[/size]
Agradeço a todos do GUJ que estão ajudando e colaborando com o tópico! :smiley:
Agradeço também aqules que disponiblizam de seu tempo simplesmente lendo o tópico e mesmo não postando, de alguma maneira, tentou ajudar!
Não deixe de opinar, dar sugestões, criticar… [color=orange][size=20]OBRIGADO![/size][/color]

Meu Deus esse silêncio me assusta! :shock:
Devo estar fazendo perguntas sem sentido… :frowning:

Pessoal se estiver existindo alguma dificuldade para entender a pergunta por favor não deixem de avisar que eu tento expor melhor o problema para vocês.
Qualquer coisa também se preferir mandar a pergunta por MP pode mandar.
Peço antecipadamente desculpa se estou formulando mal a pergunta…é que realmente tenho muita dificuldade às vezes até para formular as perguntas.
Não me levem a mal… qualquer situação de dúvida pode falar!
Obrigado pessoal, um abraçopara todos e para o Bruno que me ajudou bastante nessas últimas postagens. Sucesso! :smiley:

Boa Tarde pessoal!

Sério mesmo que não existe nada na qual possa me ajudar para resolver o caso? :slight_smile:
Nada mesmo, uma dica, uma opinião, uma pergunta, uma crítica…??? :oops:
Ou estou pedindo algo impossível e insustentável??? :frowning:
Que vontade de chorar… :cry: :cry: :cry:

Não, vc não está errado! Vc não vai utilizar exceptions para transportar dados.

visão <- controle <- modelo

A idéia do padrão MVC tem que ficar isolado no cliente sem envolver diretamente o servidor ou outro tipo de coisa. Significa que o controle é quem irá executar qualquer ação externa ao módulo (MVC).

Existe uma variação desta idéia chamada MVP, dá uma lida no conteúdo deste link http://www.javafree.org/artigo/871446/Apresentando-ModelViewPresenter-o-MVC-focado-na-visualizacao.html.

flws

Fantomas, boa tarde! Desculpa na demora ao responder!
Mais uma vez muitíssimo obrigado por continuar atento ao tópico, sem palavras!

Vou implementar neste final de semana o exemplo do artigo com calma e volto a postar! :wink:
Um abração!

Pedro, dê uma lida no Mundo Java nº 36 que saiu este mês, nele tem um artigo do Eduargo Guerra que resume exatamente o que explicamos aqui sobre exceções. É bem mais claro e diz algumas coisas que não falamos aqui.