Alura > Cursos de Programação > Cursos de Java > Conteúdos de Java > Primeiras aulas do curso Certificação Java SE 7 Programmer I: lidando com exceções

Certificação Java SE 7 Programmer I: lidando com exceções

Diferencie entre exceções do tipo checked, runtime e erros - Introdução

Durante a execução do seu programa, alguns erros podem acontecer, coisas podem dar errado. O Java oferece, para você, um mecanismo para que você consiga ver esses erros, identificá-los, ver o que aconteceu e, eventualmente, recuperar-se, resolver o erro durante a execução do programa, ou pelo menos identificar o que aconteceu.

Esses erros têm uma certa classificação, é necessário entender essa classificação para a prova. Vamos dar uma olhada nessa classificação e ver como é que isso funciona. Basicamente, a classificação desses erros é toda baseada em uma estrutura de classe, em uma hierarquia de classes. Vamos dar uma olhada nessa hierarquia e entender o que cada classe representa nessa classificação.

A classe principal dessa hierarquia é a classe Throwable, ela representa qualquer coisa que possa ser lançada pelo Java, qualquer tipo de erro que pode acontecer pelo Java. Ela é o topo da hierarquia de erros. Logo abaixo dela, temos duas classes: a classe Error e a classe Exception.

Os Errors geralmente são erros de execução que são gerados por alguma situação muito anormal que aconteceu durante a execução daquela aplicação, por exemplo, um tipo de erro bem clássico que existe é o “OutOfMemoryError”, que acontece toda vez que acaba a memória disponível para sua aplicação executar.

Esse tipo de classe, essas classes que derivam de Errors, não se espera que seu programa saiba se recuperar delas, elas só acontecem em situações muito extremas e você geralmente não tem como resolver o problema. Acabou a memória, o que você vai fazer? Não tem uma solução fácil para os Errors.

Do outro lado, nós temos as Exceptions, que são erros que podem até ser tratados, são erros que não digamos que são esperados, mas que podem acontecer dependendo do fluxo de execução da sua aplicação. Por exemplo, o seu programa pode lançar um “SQLException”, que pode acontecer caso você tenha um problema na hora que estiver executando um código com o banco de dados.

Você não conseguiu se conectar no banco? Você enviou um comando errado para o banco? Então qualquer tipo desses, que você cause, o Java vai acabar gerando para a gente uma “SQLException”.

Esse tipo de erro, em especial, as Exceptions, podem ser tratadas pela sua aplicação ou simplesmente elas podem ser evitadas. Você faz uma checagem no código para evitar que a Exception venha a acontecer. As Exceptions, por sua vez, estão divididas em duas subcategorias: nós temos as Exceptions checked e as Exceptions unchecked.

As checked são Exceptions que não é muito fácil, teoricamente, você conseguir evitar esse erro, então você tem que estar preparado, porque há uma boa probabilidade de acontecer algum erro daquele tipo, você tem que estar verificando se aquele erro vai acontecer ou não.

As unchecked, por outro lado, são erros que são um pouco mais simples de serem evitados. Se você fizer alguns tipos de checagem, por exemplo, no seu código, você pode conseguir evitar que uma Exception desse tipo ocorra.

unchecked Exception são todas as classes que são filhas de “RuntimeeException” que, por sua vez, é filha de Exception. Então Exceptions unchecked também são Exceptions, mas, no caso, são apenas as classes que são filhas de “RuntimeException”. Todas as outras classes que também são filhas de Exception e irmãs de “Runtime”, no caso, todas as outras classes, nós consideramos como checked Exceptions.

Essa diferença não fica somente na teoria. Na prática, a inserção ser checked, filha direta de Exception, ou unchecked, que é ser filho de “Runtime”, isso vai ter um impacto na hora que você estiver compilando o seu código.

Se a Exception for do tipo checked, checada, o compilador vai te obrigar a, caso você fale que você quer lançar uma Exception desse tipo, que seu programa pode dar uma Exception desse tipo, o compilador vai te obrigar a fazer um certo tipo de tratamento, nessa exceção.

As Exceptions do tipo unchecked, o compilador simplesmente ignora, ele deixa porque você poderia ter evitado esse erro, então não vamos fazer nada, eu, compilador, não vou fazer nada com isso. Essa é, basicamente, a diferença entre as diferentes classificações de Exceptions, de erros que podem acontecer no Java.

Nós temos a classe Throwable, que é a mãe de todas, qualquer coisa que pode acontecer no seu programa, qualquer coisa que pode ser lançada pelo seu programa. Errors, que são basicamente erros de execução, coisas que você não deveria estar nem esperando que acontecessem: acabou a memória, deu um erro muito grave no disco, então são erros mesmo.

E Exceptions, que são condições excepcionais, algum problema que aconteceu durante a execução da aplicação. Essas Exceptions, por si, são divididas em duas categorias: checked, que são todas as classes filhas de Exception, que o compilador vai checar se você está fazendo o tratamento ou não, e exceções do tipo unchecked, que são filhas de “RuntimeException”, que o compilador simplesmente vai ignorar qualquer exceção desse tipo que você coloque no seu código. Beleza? Te vejo na próxima.

Descreva o que são exceções e para que são utilizadas em Java - exceções e suas utilidades

Veja o seguinte trecho de código: eu criei uma classe, chamei de SuaClasse. Essa classe tem um método que faz algo, recebe um array e imprime o que estiver dentro desse array, na posição 1, ou seja, imprime o segundo elemento desse array. E tem um método main que eu uso para executar new SuaClasse() . fazAlgo, e passei um novo array de tamanho 5, para ele.

É um código Java normal, mas vamos pensar no seguinte: eu passei, para o método fazAlgo, um array de 5 posições. Quando eu executar esse código, o fazAlgo vai imprimir 0, já que o array, toda vez que você o cria, inicializa todas as posições desse array com o valor default.

E se eu passasse 0 como o tamanho desse array, seria um array vazio praticamente, um array sem nada dentro. O que ia acontecer quando eu fosse executar o print, tentando acessar a segunda posição de um array que não tem nenhuma posição dentro dele?

Para garantirmos que esse código fosse executado, teríamos que fazer uma checagem antes. Então eu teria que verificar, por exemplo, if (idades.length >=2), somente nessa situação eu deveria executar o meu System.out, meu print, apenas se o array fosse maior que 2.

Tem um outro problema, o array é um objeto, e se ninguém passar um array? Se, na parte de baixo, na hora de executar o código, alguém passasse null? Eu também teria que fazer essa verificação. Então vamos aproveitar e verificar isso também.

Então não é só se o tamanho do “idades” é maior ou igual a 2, eu também tenho que verificar se “idades” é diferente de null. Então “idades” tem que ser diferente de null e o tamanho do “idades” tem que ser maior que 0.

Então conseguimos pegar dois casos extras e fazer uma checagem em cima, mas pensem: quantos outros casos excepcionais, quantas outras coisas fora do padrão, poderiam acontecer num trecho de código. É um trecho de código de uma linha, eu já tive que testar duas coisas excepcionais, duas condições extras, imagine num código gigante.

Então pode acabar ficando muito complicado você prever todas as coisas que podem dar errado num certo trecho de código. É quase impossível você saber tudo que pode dar errado com um código que você está escrevendo.

É para esse cenário que existem as Exceptions. Elas são maneiras de você conseguir executar/escrever o seu código, pensando no caminho feliz – digamos não apenas o caminho feliz – mas 99% das vezes que vão chamar esse código, as pessoas vão passar um array de tamanho válido, um array com 5 posições, por exemplo. A maioria das vezes o pessoal vai passar assim.

Caso alguém passe um tamanho inválido do array, aí sim será uma exceção à regra. É para essas exceções à regra que temos as Exceptions. É para evitar que, no meio do seu código, você tente prever tudo que está acontecendo, você tente tratar todas as condições possíveis.

As Exceptions são uma maneira de você separar o que é código, da maioria das execuções, o código normal da aplicação, do código dessas condições excepcionais, desses 1% que acontecem de vez em nunca. Então comExceptions você consegue fazer essa separação e o seu código acaba ficando mais simples e mais legível, também.

As Exceptions também servem para te indicar o que foi que deu de errado no código. Sempre que ocorrer um erro na sua aplicação, é muito importante você parar e ler a exceção que foi lançada para você. Nessa seção, a exceção possui todas as informações necessárias para que você tente resolver o erro. O Java está interessado em que você resolva o problema, então ele vai te dar o máximo de informações que ele conseguir

Vamos pegar, por exemplo, esse código. Vou passar um array vazio para o método fazAlgo. Nesse caso, vai acontecer um erro. Vamos rodar e ver o que vai rolar? Java, sua classe já está compilada, vou compilar de novo só para garantir que não houve nenhuma alteração. java SuaClasse, o que aconteceu? Deu uma Exception. No caso, a exceção que foi lançada é o ArrayIndexOutOfBoundsException.

Eu tentei acessar uma posição do array, fora do tamanho dele. Meu array não tem tamanho nenhum. Eu criei o array sem nenhum tamanho e tentei acessar uma posição dentro dele.

O importante não é só ver o nome do Exception, repare que você tem a stack trace, que são essas linhas que estão no parágrafo, que estão para o lado e identadas debaixo da linha onde está falando que ocorreu o Exception, o Exception in thread “main”. Você vê que, nessas linhas de baixo, ele fala exatamente onde ocorreu o erro.

Então observe: deu um ArrayIndexOutOfBoundsException: 0 at, se você traduzir fica “na sua classe”, .fazAlgo, no método falAlgo da sua classe e, dentro dos parênteses, ele coloca que isso está na sua classe Java, linha 4, ou seja, o erro aconteceu na linha 4 da classe SuaClasse e dentro do método fazAlgo.

Como é que a execução chegou dentro desse método? Está na linha de baixo. Quem chamou o fazAlgo, foi o método main, que está na SuaClasse, na linha 8. Então a chamada para o método fazAlgo, que é o método que chamou o erro, está dentro do método main, na linha 8. Vamos checar e conferir? Linha 8, eu chamando o método fazAlgo passando um argumento inválido, passando um array sem nenhum tamanho dentro dele.

Então a Exception está aí para te ajudar a evitar que você tenha que colocar todas as alternativas possíveis, pensar em todos os casos que podem estar errados, no meio do seu código, e quando ocorrer uma exceção, ou seja, um desses casos excepcionais acontecer, você ter como descobrir exatamente onde foi que o erro aconteceu e, futuramente, vamos ver nas outras aulas, como faz para você fazer um tratamento, como você resolve, quando acontecer um erro desse tipo. Valeu, até a próxima.

Crie um bloco try-catch e determine como exceções alteram o fluxo normal de um programa - try catch

O que vamos falar, agora, é como criar blocos para tratar as Exceptions e os erros que podem ocorrer no meu programa, durante a execução dele. Isso é, criar blocos do tipo try-catch para tratar Exceptions e erros, alterando o fluxo de execução do meu programa.

Então vamos criar um arquivo de exemplo. Vou criar “New File”, esse meu arquivo vai se chamar “TestaTrataException.java”. Agora que estou dentro do meu método main, vamos jogar um erro.

Que erro que eu posso fazer acontecer? Eu posso ser malvado e criar uma variável chamada “nome” e fazer essa variável ser nula. Inicialize-a como nula. Se eu não a inicializá-la, lembra que você não pode usar, não compila. Força o null goela a baixo dessa variável nome = null.

Agora tenta chamar algum método do nome, por exemplo, nome.tolowerCase, para deixar ele minúsculo. O que acontece mesmo quando eu rodo esse programa? Vamos testar? Vou no meu terminal, “javac TestaTrataException”. Então ele dá o “NullPointerException”. Já conhecemos o stack trace e sabemos que deu “NullPointerException” na linha 4. Vamos na linha 4, “NullPointerException”.

Se eu colocar um System.out.println(“terminei”), o que acontece? Vou tentar compilar e rodar, e ele não fala que terminou. Por que ele não fala que terminou? Porque quando ele chegou na chamada do método tolowerCase que deu “NullPointerException”, essa Exception vazou do meu método, ela estourou, foi jogada para fora do meu método. E parou aí, não continua o meu método Então não mostrou a mensagem “terminei”.

Então você fala “ah Guilherme, eu queria tentar executar isso. Se desse certo, tudo bem. Se não desse certo, continua o programa”. Então é agora que vai entrar o nosso try, nesse primeiro cenário de uso do try.

O primeiro cenário de uso do try é: eu quero tentar executar esse comando, se der determinado tipo de erro, pega esse erro, não o deixe estourar, não o deixe vazar para fora do método, para quem chamou esse método. Segura. Como ninguém chamou esse método, quem chamou esse método foi o programa, Java, então se vaza daqui o seu programa para. Lembre-se disso.

O try, por si só, não compila, precisa de alguma coisa, ou um catch, ou um finally, que vamos ver depois, ou uma declaração de recursos, que é uma outra opção, que não é o que é o que vai cair nessa sessão.

Então o try por si só não compila, o que eu vou falar é: tenta executar isso, se der NullPointerException, faça alguma coisa. Esse NullPointerException é igual uma declaração de uma variável, uma variável chamada “ex”, que é o do tipo NullPointerException. O que eu vou fazer? Vou imprimir System.out.println(“peguei a exception”).

Então o que eu espero que aconteça agora? Que dê um NullPointerException. Esse NullPointerException está dentro de um try catch, então ele vai parar em um catch. O catch é do tipo que queremos? É do tipo que queremos. Então ele imprime “peguei a exception”. E depois ele imprime “terminei”, porque ele continua, ele não jogou a Exception. Vamos testar? Compilo, rodo, ele imprime. Peguei a Exception, terminei.

Então o try e o catch servem para mudar o nosso fluxo do programa, porque ao invés da Exception vazar para quem chamou o método, o que acontece? Ele procura um bloco catch responsável por aquela Exception, esse bloco vai ser usado para tratar.

Quando usamos os blocos try catch temos que tomar alguns cuidados, por exemplo, se esse NullPointerException for de outro tipo, um Exception que não acontece aí dentro, vou pegar um Exception do tipo runtime, que não é desse tipo.

Vou pegar o ArrayIndexOutOfBoundsException, vou compilar e vou rodar. Vou pegar uma outra Exception que não é NullPointerException, vou pegar IndexOutOfBoundsException. Compilo e rodo. Quando eu rodo, ele não imprimiu o “terminei”; por que não? Porque a exception que aconteceu, não foi tratada nos blocos catch.

Eu tenho 1 bloco catch e o bloco catch tenta pegar IndexOutOfBoundsException, a exception que ocorreu foi NullPointerException, não tem nada a ver uma com a outra, uma não é filha da outra, não existe o polimorfismo direto de um tipo para outro, não tem herança entre eles, nenhum implementa o outro, são duas classes distintas, então ele não caiu nesse bloco.

Se invés dessa Exception, eu acessasse, realmente, uma posição invalida de um array, ele iria cair dentro. Então quer dizer que ele cai dentro do bloco catch, somente se for aquele tipo de Exception. Mas IndexOutOfBoundsException e NullPointerException são ambas do tipo RuntimeException. Ambas herdam o tipo RuntimeException. Então ele vai usar polimorfismo, vai usar NullPointerException, vai cair em RuntimeException.

Vamos testar? Compilo. Rodo. Pegou o nosso NullPointerException, porque todas essas duas herdam de RuntimeException. RuntimeException também herda de Exception. Então uma maneira mais genérica ainda de falar que ela trata todas as Exceptions, é herdar Exception.

Mais genérico ainda é herdar de todas as Exceptions e todos os Errors, que você, provavelmente, não quer tratar os Errors, mas se você quisesse tratar tudo: Throwable, que é o mais genérico de todos. Tento de novo, compilo e rodo de novo.

Quando que eu posso colocar um try catch? Isso a prova pode cobrar de você. Eu posso colocar um try catch de qualquer tipo que seja RuntimeException ou de um tipo Throwable. Porque tanto o RuntimeException, quanto o Throwable, quanto o Exception e Error, todos eles são coisas dinâmicas que podem acontecer em qualquer lugar.

Se eu tenho essa linha de código apresentada, de repente pode dar um Exception. Qualquer linha de código, minha, que é uma expressão, pode dar uma Exception do tipo Runtime, então eu posso colocar um try catch do tipo Runtime, do tipo Exception ou do tipo Throwable ou Error, qualquer lugar.

Agora, uma Exception checked, tipo java.io.IOException, eu só posso colocar se ela realmente pode acontecer dentro do método. O que eu quero dizer com “realmente pode acontecer”? Somente se o código que você invoca fala explicitamente que essa Exception pode ocorrer. Dentro do método toLowerCase, a definição do método toLowerCase fala que pode ocorrer IOException? Não fala. Vamos tentar compilar?

Tento compilar e ele não deixa; por quê? Porque ele fala “eu vou ser mais esperto que você, Guilherme. Você, Guilherme, está sendo bobo e está achando que pode acontecer uma IOException dentro do método, e isso pode significar que você está fazendo algo errado, porque você está achando que pode, mas nunca vai ocorrer uma IOException dentro desse método”.

Por que nunca vai ocorrer uma IOException dentro desse método? Porque se ocorresse uma IOException dentro do método, que é do tipo checked, ele teria que dizer explicitamente que essa Exception está acontecendo, e ele não falou. Se ele não falou, nunca acontece uma IOException dentro desse método, você nunca poderá colocar um catch IOException.

Então, unchecked Exception, Error, Throwable e Exception em geral, você pode colocar a palavra Exception, a palavra Throwable, a palavra Runtime Exception e qualquer filha de Runtime Exception, você pode colocar, sem problemas.

Agora, qualquer filha de Exception que não é filha de Runtime Exception, só se quem você está invocando puder dar esse erro. Por exemplo, se eu falar que um new java.io.FIleInputStream(“a.txt”). Nisso eu jogo um FileNotFoundException, que é filho de IOException, então passa a compilar, porque pode ocorrer esse erro. Então se eu tiro isso que eu coloquei, não pode mais.

Por fim, lembra que se uma Exception ocorre, a linha seguinte, dentro do try catch não será chamada, porque vai dar Exception, vai cair nesse comando apresentado, porque nele estamos colocando um try catch catch (NullPointerException). E ele nunca vai passar na linha seguinte, porque acontece o NullPointerException, ele cai no comando, e imprime em baixo. Vamos testar?

Compilo. Observe: “linha seguinte” não é impressa. A Exception pula para o catch, essa é a mudança de fluxo que temos. Então quais são os pontos importantes do try catch? Primeiro, um try puro não compila, só um try “{}”. Pode ter um try com “()”, que é uma outra situação totalmente diferente, não cobrada na sessão da prova. Pode ter um try finally, que também não é cobrado na sessão da prova.

Pode ter um try catch, que é o que é cobrado nesta sessão da prova. Quando eu tenho um try catch, o que eu posso colocar no meu catch? Qualquer Runtime Exception, qualquer Throwable, qualquer Error, não tem problema.

Se é a palavra Throwable, pode colocar; a palavra Runtime Exception e suas filhas, pode colocar, a palavra Exception, porque ela inclui Runtime Exception, pode colocar; a palavra Error e suas filhas, pode colocar; o checked Exception, não pode colocar. Por que eu não posso colocar uma filha Exception que não seja Runtime Exception?

Porque eu só posso colocar ela se dentro do meu bloco try eu tenho esse erro possível de acontecer, isso é, se algum método que eu chamo está dizendo que joga esse erro. Se acontecer isso, você pode colocar esse checked Exception, senão não pode.

E o que acontece com esse fluxo de execução do programa? Ele para o bloco try, procura o bloco catch, se o bloco catch é do tipo que você falou ou o polimorfismo bate, ele chama o seu bloco catch e continua, se não bate com o do tipo do bloco catch, ele simplesmente vaza desse método e acabou.

Sobre o curso Certificação Java SE 7 Programmer I: lidando com exceções

O curso Certificação Java SE 7 Programmer I: lidando com exceções possui 58 minutos de vídeos, em um total de 29 atividades. Gostou? Conheça nossos outros cursos de Java em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Java acessando integralmente esse e outros cursos, comece hoje!

Plus

De
R$ 1.800
12X
R$109
à vista R$1.308
  • Acesso a TODOS os cursos da Alura

    Mais de 1500 cursos completamente atualizados, com novos lançamentos todas as semanas, emProgramação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

Matricule-se

Pro

De
R$ 2.400
12X
R$149
à vista R$1.788
  • Acesso a TODOS os cursos da Alura

    Mais de 1500 cursos completamente atualizados, com novos lançamentos todas as semanas, emProgramação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

  • Luri powered by ChatGPT

    Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com Luri até 100 mensagens por semana.

  • Alura Língua (incluindo curso Inglês para Devs)

    Estude a língua inglesa com um curso 100% focado em tecnologia e expanda seus horizontes profissionais.

Matricule-se
Conheça os Planos para Empresas

Acesso completo
durante 1 ano

Estude 24h/dia
onde e quando quiser

Novos cursos
todas as semanas