Erros de compilação e execução, Exceções

Computação II - Ciência da Computação


Prof.: Danilo S. Carvalho

Nessa aula, vamos aprender sobre os tipos de erro que podem acontecer na criação e execução de um programa.


Ao fim da aula, saberemos como prever e lidar com certas condições excepcionais que podem interromper o funcionamento esperado do nosso código.

Existem duas maneiras pelas quais um programa que criamos pode dar errado...

Erros de compilação

  • São gerados pelo compilador quando encontrado código fonte inválido.
  • O programa executável não pode ser obtido
  • O compilador aponta a linha que causou o problema.
Erros de execução

  • São gerados pelo ambiente de execução (ou sistema operacional) quando um programa realiza uma operação inválida.
  • O programa em execução é interrompido e todos os dados em processamento são perdidos
  • O ambiente de execução / SO produz um relatório de falha (stack trace) informando o motivo da interrupção do programa

Vejam o código abaixo:

Há algum problema com o programa? De que tipo?

Sim. O literal atribuído à variável num é do tipo double, e não float.

Como o rebaixamento de tipo não é permitido em Java, ocorrerá um erro de compilação.

                        
                            public class RaizQuadrada {
                                public static void main(String[] args) {
                                    float num = 2.0;

                                    System.out.printf("A raíz quadrada de %f é %f\n", num, Math.sqrt(num));
                                }
                            }
                        
                    
                        
                            public class RaizQuadrada {
                                public static void main(String[] args) {
                                    float num = 2.0;

                                    System.out.printf("A raíz quadrada de %f é %f\n", num, Math.sqrt(num));
                                }
                            }
                        
                    
                        
                            RaizQuadrada.java:3: error: incompatible types: possible lossy conversion 
                            from double to float
		                        float num = 2.0;
		                                    ^
                            1 error
                        
                    

E quanto ao código abaixo:

Há algum problema com o programa? De que tipo?

Sim. Um array de 100 elementos tem posições válidas de 0 até 99.

Na linha 4 tenta-se atribuir um valor em uma posição fora dos limites do array.

Entretanto, o compilador Java não verifica os limites de arrays, portanto o código vai compilar sem erros.

O programa portanto causará um erro de execução.

                        
                            public class ManipulacaoDeArray {
                                public static void main(String[] args) {
                                    int[] v = new int[100];
                                    v[100] = 2;
                                }
                            }
                        
                    
                        
                            public class ManipulacaoDeArray {
                                public static void main(String[] args) {
                                    int[] v = new int[100];
                                    v[100] = 2;
                                }
                            }
                        
                    
                        
                            Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 
                            Index 100 out of bounds for length 100 at ManipulacaoDeArray.main(ManipulacaoDeArray.java:4)
                        
                    

Nosso foco aqui será nos erros de execução, que não podem ser detectados pelo compilador e possuem o potencial de causar danos ao sistema e aos usuários, caso não tratados.


Podemos antecipar e detectar certos erros de execução, criando um fluxo de código alternativo à ocorrência do erro e salvando nosso programa de uma "morte" repentina.


A esse processo se dá o nome de tratamento de exceção.

Chamamos os erros encontrados dessa maneira de exceções.

Isso é feito em três etapas:


  1. Identifica-se um possível erro de execução.
  2. Aplica-se um mecanismo de detecção, para caso o erro ocorra.
  3. Cria-se um caminho alternativo no código, que será tomado quando o erro ocorrer.

Vejam o programa abaixo:

Compilamos o programa e não ocorreram erros.

Podemos prever algum erro de execução?

Pause os slides e pense um pouco...

O programa espera receber uma idade (digitada pelo usuário) e imprime a idade recebida em binário.

E se o valor que o usuário digitar não puder ser convertido em um número inteiro?

                        
                            import java.util.Scanner;

                            public class IntroExcecoes {
                                public static void main(String[] args) {
                                    int idade;
                                    Scanner scanner = new Scanner(System.in);
                                    
                                    System.out.println("Digite sua idade e aperte <ENTER>: ");
                                    String linha = scanner.nextLine();
                                    idade = Integer.parseInt(linha);
                                    System.out.println("Sua idade em binário é: " +
                                                       Integer.toBinaryString(idade));
                                }
                            }
                        
                    

Agora que identificamos uma exceção, aplicamos o mecanismo para detectar quando ela ocorre.

No Java, esse mecanismo é o bloco try ... catch.

Colocamos dentro de um bloco try o código que pode causar a exceção.

O bloco try é sempre seguido de um bloco catch, onde colocamos o caminho alternativo que o código deve seguir se a exceção ocorrer.

O bloco catch captura apenas exceções do tipo que foi especificado em sua cláusula. Nesse caso NumberFormatException.

Nesse caso informamos ao usuário que a idade digitada é inválida.

                        
                            import java.util.Scanner;

                            public class IntroExcecoes {
                                public static void main(String[] args) {
                                    int idade;
                                    Scanner scanner = new Scanner(System.in);
                                    System.out.println("Digite sua idade e aperte : ");
                                    String linha = scanner.nextLine();
                                    try { // Bloco try: a exceção pode ocorrer aqui
                                        idade = Integer.parseInt(linha);
                                        System.out.println("Sua idade em binário é: " +
                                                           Integer.toBinaryString(idade));
                                    }
                                    catch (NumberFormatException e) {
                                        System.out.println("Idade inválida.");
                                    }
                                }
                            }
                        
                    
                        
                            import java.util.Scanner;

                            public class IntroExcecoes {
                                public static void main(String[] args) {
                                    int idade;
                                    Scanner scanner = new Scanner(System.in);
                                    System.out.println("Digite sua idade e aperte : ");
                                    String linha = scanner.nextLine();
                                    try { // Bloco try: a exceção pode ocorrer aqui
                                        idade = Integer.parseInt(linha);
                                        System.out.println("Sua idade em binário é: " +
                                                           Integer.toBinaryString(idade));
                                    }
                                    catch (NumberFormatException e) {
                                        System.out.println("Idade inválida.");
                                    }
                                }
                            }
                        
                    
                        
                            import java.util.Scanner;

                            public class IntroExcecoes {
                                public static void main(String[] args) {
                                    int idade;
                                    Scanner scanner = new Scanner(System.in);
                                    System.out.println("Digite sua idade e aperte : ");
                                    String linha = scanner.nextLine();
                                    try { // Bloco try: a exceção pode ocorrer aqui
                                        idade = Integer.parseInt(linha);
                                        System.out.println("Sua idade em binário é: " +
                                                           Integer.toBinaryString(idade));
                                    }
                                    catch (NumberFormatException e) {
                                        System.out.println("Idade inválida.");
                                    }
                                }
                            }
                        
                    

Entretanto, isso não resolveu o problema do nosso programa ser abortado quando a exceção ocorre.

Precisamos então melhorar o nosso caminho alternativo, retornando ao fluxo planejado do programa.

Podemos fazer isso repetindo o trecho que lê e imprime a idade até uma idade válida ser digitada.

                        
                            import java.util.Scanner;

                            public class IntroExcecoes {
                                public static void main(String[] args) {
                                    int idade = 0;
                                    Scanner scanner = new Scanner(System.in);
                                    while (idade == 0) {
                                        try {
                                            System.out.println("Digite sua idade e aperte : ");
                                            String linha = scanner.nextLine();
                                            idade = Integer.parseInt(linha);
                                            System.out.println("Sua idade em binário é: " +
                                            Integer.toBinaryString(idade));
                                        }
                                            catch (NumberFormatException e) {
                                            System.out.println("Idade inválida.");
                                        }
                                    }
                                }
                            }
                        
                    
                        
                            import java.util.Scanner;

                            public class IntroExcecoes {
                                public static void main(String[] args) {
                                    int idade = 0;
                                    Scanner scanner = new Scanner(System.in);
                                    while (idade == 0) {
                                        try {
                                            System.out.println("Digite sua idade e aperte : ");
                                            String linha = scanner.nextLine();
                                            idade = Integer.parseInt(linha);
                                            System.out.println("Sua idade em binário é: " +
                                            Integer.toBinaryString(idade));
                                        }
                                            catch (NumberFormatException e) {
                                            System.out.println("Idade inválida.");
                                        }
                                    }
                                }
                            }
                        
                    

Agora podemos evitar que nossos programas sejam interrompidos por exceções.


Exercitem diversos cenários possíveis onde as coisas podem dar errado. Ficarão surpresos com a quantidade de exceções diferentes que podem encontrar em programas simples.


Abordaremos mais detalhes sobre exceções adiante no curso.

Perguntas:

  1. É possivel capturar vários tipos de exceção para um mesmo bloco try?
  2. Como a máquina virtual do Java sabe que ocorreu uma exceção?

Até a próxima aula!