Buscar

E4_PROO

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 35 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 35 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 35 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

Rafael de Moura Moreira
PROGRAMAÇÃO 
ORIENTADA A 
OBJETOS
E-book 4
Neste E-Book:
INTRODUÇÃO ����������������������������������������������������������� 3
CLASSES ABSTRATAS ��������������������������������������������4
MÉTODOS ABSTRATOS ������������������������������������������������������������9
INTERFACES �������������������������������������������������������������13
HERANÇA VERSUS IMPLEMENTAÇÃO ���������������������������������18
TRATAMENTO DE EXCEÇÃO ��������������������������������������������������21
CONSIDERAÇÕES FINAIS ����������������������������������� 32
REFERÊNCIAS BIBLIOGRÁFICAS & 
CONSULTADAS ������������������������������������������������������� 33
2
INTRODUÇÃO
A herança e o polimorfismo são conceitos importan-
tíssimos que permitem a reutilização de códigos. Em 
razão dessa característica, neste módulo aprofunda-
remos os estudos nesses conceitos ao incorporar 
ferramentas interessantes do Java a essa equação, 
como as classes abstratas e as interfaces.
Estudaremos, em seguida, de que modo as classes 
abstratas permitem o planejamento das estruturas 
de herança mais eficientes, sem a necessidade de 
implementar métodos que deverão necessariamente 
ser sobrepostos a posteriori�
Nesse sentido, verificaremos que as interfaces per-
mitem que diversas classes concordem em oferecer 
um conjunto de funcionalidades em comum, mesmo 
que elas não estabeleçam nenhum tipo de herança 
entre si.
Por fim, estudaremos o tratamento da exceção breve-
mente, por ser uma maneira inteligente e padronizada 
de lidar com erros em nosso programa.
3
CLASSES ABSTRATAS
Imagine que você esteja desenvolvendo um siste-
ma que precisa modelar bichinhos de estimação. 
Todo bichinho terá um nome, um tutor, um gênero 
(M ou F) e uma cor. Quem tem um pet em casa sabe 
que animais de estimação costumam se comunicar 
bastante, seja por gestos corporais, seja por sons. 
Porém, cada bichinho se comunica de um jeito.
Por exemplo, os cães têm um comportamento; os 
gatos têm outro; os pássaros, outro e assim sucessi-
vamente. Então, você tem a ideia de criar uma clas-
se Pet, definindo os atributos dos bichinhos e um 
método “fala”. Depois disso, deve criar classes para 
diferentes bichinhos que herdarem da classe Pet e 
sobreponham o método “fala”. Observe:
public class Pet{
 private String nome;
 private String dono;
 private String cor;
 private String raca;
 public Pet(String nome, String dono, String 
cor, String raca){
 this.nome = nome;
 this.dono = dono;
 this.cor = cor;
 this.raca = raca;
 }
 public String getNome(){
 return this.nome;
 }
4
 
 public void fala(){
 System.out.println(this.nome + " faz 
barulhos.");
 }
}
Tabela 1: Código 1. Arquivo Pet.java Fonte: Elaboração 
própria.
public class Cachorro extends Pet {
 public Cachorro(String nome, String dono, String 
cor, String raca){
 super(nome, dono, cor, raca);
 }
 public void fala(){
 System.out.println(this.getNome() + " faz 
au au.");
 }
}
Tabela 2: Código 2. Arquivo Cachorro.java Fonte: Elaboração 
própria.
public class Gato extends Pet {
 public Gato(String nome, String dono, String 
cor, String raca){
 super(nome, dono, cor, raca);
 }
 public void fala(){
 System.out.println(this.getNome() + " faz 
miau.");
 }
}
Tabela 3: Código 3. Arquivo Gato.java Fonte: Elaboração 
própria.
5
É fácil verificar que podemos instanciar livremente 
objetos das classes Cachorro e Gato, bem como que 
um método esperando um Pet qualquer não encon-
tra dificuldades com qualquer uma dessas classes, 
pois ambas herdam de Pet e ambas têm os mesmos 
métodos.
É possível ainda instanciar objetos Pet diretamente. 
Do ponto de vista computacional, não há nenhum 
impedimento, uma vez que Pet é uma classe e possui 
atributos e métodos, um construtor etc. E quanto ao 
ponto de vista lógico, ele faz sentido?
Ninguém tem em casa um animal “genérico”, com 
formato e comportamento indefinidos. As pessoas 
têm cachorros, gatos, periquitos, hamsters, porqui-
nhos-da-índia, papagaios...
Se nosso sistema fosse um sistema de cadastro de 
pacientes de uma clínica veterinária, por exemplo, 
instanciar diretamente um Pet implicaria criar enti-
dades sem nenhuma informação específica, o que 
é ruim. Diferentes animais sofrem com diferentes 
doenças, que necessitam de diferentes vacinas, me-
dicamentos, dosagens etc.
Para esses casos, convém criar computacionalmen-
te um bloqueio para que ninguém possa instanciar 
objetos da classe Pet. O único objetivo da classe Pet 
é providenciar as características comuns a diversas 
outras classes, as quais não só podem, como devem 
ser instanciadas.
6
Com vistas a criar esse bloqueio, podemos tornar 
nossa classe Pet uma classe abstrata. Uma classe 
abstrata é uma classe que serve tão-somente para 
herança, pois instanciar objetos é proibido. Criar uma 
classe abstrata é, em outras palavras, criar uma clas-
se normal, mas com a inserção de “abstract” antes 
da palavra “class”.
Ao declarar a classe Pet como abstrata, os objetos 
das classes Cachorro e Gato continuam funcionan-
do normalmente, pois seguem herdando todos os 
atributos e métodos, bem como podem continuar 
usando o super, sobrepor métodos da classe origi-
nal, entre outros. A única mudança é, portanto, na 
própria classe Pet.
Desse ponto em diante, não podemos mais usar 
new Pet(), mas podemos criar funções que recebem 
objetos Pet, ou seja, ponteiros para Pet. Na prática, 
sempre passaremos objetos Cachorro ou Gato a ela.
public abstract class Pet{
 private String nome;
 private String dono;
 private String cor;
 private String raca;
 public Pet(String nome, String dono, String 
cor, String raca){
 this.nome = nome;
 this.dono = dono;
 this.cor = cor;
 this.raca = raca;
 }
 public String getNome(){
7
 return this.nome;
 }
 
 public void fala(){
 System.out.println(this.nome + " faz 
barulhos.");
 }
}
Tabela 4: Código 4. Arquivo Pet.java com classe abstrata. 
Fonte: Elaboração própria.
Note que a única diferença entre os códigos 1 e 4 é 
a palavra abstract. Todo o resto segue como estava. 
Porém, se em algum ponto você chamar new Pet() 
em seu programa, terá um erro de compilação.
FIQUE ATENTO
O papel do construtor é inicializar um objeto recém-
-criado. Classes abstratas não podem ser instan-
ciadas, o que pode induzir algumas pessoas a 
concluir que o código 4 não faz sentido: por que 
a classe abstrata teria um construtor?
Pois bem, nós ainda temos herança e “super”. O 
construtor da nossa classe Pet ainda existe, por-
que ele não só pode, como é utilizado pelas sub-
classes Cachorro e Gato pelo super.
8
MÉTODOS ABSTRATOS
Em nossa classe Pet, criamos um método chamado 
“fala”, porque esse é um método que todos os her-
deiros de Pet deveriam ter. Funções que recebem Pet 
provavelmente utilizarão esse método, diante desse 
fato, é importante garantir que todas as subclasses 
tenham uma. No caso, nossas subclasses Cachorro 
e Gato sobrepuseram esse método. Caso isso não 
tivesse ocorrido, elas herdariam o método original 
da classe Pet.
Então, pensemos novamente em nosso problema 
concreto. Há, pouco, concluímos que não faz senti-
do lógico em nossa modelagem instanciar um Pet, 
porque ninguém tem um bichinho genérico, e sim 
cachorros, gatos etc.
Sabemos que cada bicho possui uma fala diferen-
te. Essa é uma característica do nosso problema 
concreto: saber que diferentes espécies de animal 
fazem sons diferentes. Não tem como reaproveitar 
uma forma genérica de comunicação para diferen-
tes tipos de animal. Logo, sabemos que todas as 
classes herdeiras de nossa classe Pet devem criar 
suas próprias versões de “fala”, sem usar uma “fala” 
genérica de Pet.
Com isso, passamos a ter um problema. Se remo-
vermos o método “fala” da classe Pet, ficamos sem 
nenhuma garantia de que as classes herdeiras terão 
necessariamentealgum tipo de “fala”. Um programa-
dor pode se esquecer de implementar esse método, o 
9
que incorrerá em erros. Entretanto, manter esse méto-
do não faz sentido, afinal, não está lá para ser usado, 
por isso deveria ser redefinido em todas as classes 
herdeiras, e aquela classe jamais será instanciada.
Assim, temos como solução os métodos abstratos. 
Um método abstrato é o que esperamos do método 
“fala” de nossa classe Pet, ou seja, um método “va-
zio” que só está lá para obrigar as classes herdeiras 
a implementar algo com esse nome.
Um método abstrato não pode ser implementado em 
sua classe. Em vez disso, vamos apenas declarar a 
assinatura do método junto da palavra “abstract”. 
Por isso, é preciso colocar a palavra “abstract” entre 
o modificador de acesso (public/protected/private) 
e o tipo de retorno da função, assim como o ponto-
-e-vírgula, ao invés de abrir chaves.
Toda classe herdeira é obrigada a implementar o 
método. Se criarmos uma classe herdeira de Pet, por 
exemplo, PorquinhoDaIndia, e dentro dela não hou-
ver um método “fala” com o mesmo tipo de retorno 
previsto na classe Pet, o programa não compila.
Dessa maneira, conseguimos garantir o polimorfis-
mo, visto que todos os herdeiros de Pet terão um 
método “fala”, e ao mesmo tempo evitamos os có-
digos desnecessários ou redundantes, já que não 
implementamos um método “inútil” em nossa classe 
abstrata.
 
10
public abstract class Pet{
 private String nome;
 private String dono;
 private String cor;
 private String raca;
 public Pet(String nome, String dono, String 
cor, String raca){
 this.nome = nome;
 this.dono = dono;
 this.cor = cor;
 this.raca = raca;
 }
 public String getNome(){
 return this.nome;
 }
 public String getDono(){
 return this.dono;
 }
 
 public abstract void fala();
}
Tabela 5: Código 5. Arquivo Pet.java com método abstrato. 
Fonte: Elaboração própria.
 
 
11
FIQUE ATENTO
Um método abstrato não é feito para ser utilizado, 
mas para ser implementado pelas classes her-
deiras. O que aconteceria, então, se nossa classe 
Cachorro tivesse um método abstrato? Afinal, po-
demos instanciar os objetos dessa classe. Como 
ela se comportaria se tentássemos chamar o mé-
todo abstrato, que por definição é um método não 
implementado?
Essa situação simplesmente não ocorre, porque 
toda classe que possui pelo menos um método 
abstrato automaticamente se torna abstrata, mes-
mo que você não a tenha declarado como “abstract 
class”. Portanto, tenha sempre em mente que, se 
você pretende instanciar objetos de uma classe, 
ela não pode ter métodos abstratos.
12
INTERFACES
Nosso sistema está rodando bem, mas agora gosta-
ríamos de acrescentar veterinários. E a classe terá 
como atributos nome, CRMV do veterinário, valor da 
consulta e um método para examinar um Pet.
public class Veterinario {
 public String nome;
 public int crmv;
 public double preco;
 public Veterinario(String nome, int crmv, dou-
ble preco){
 this.nome = nome;
 this.crmv = crmv;
 this.preco = preco;
 }
 public void consulta(Pet paciente){
 System.out.println(this.nome + " examinou 
" + paciente.getNome());
 System.out.println(paciente.getDono() + " 
deverá pagar R$" + this.preco);
 }
}
Tabela 6: Código 6. Arquivo Veterinario.java Fonte: 
Elaboração própria.
Podemos notar que um objeto da classe Veterinario 
não tem praticamente nada em comum com um Pet. 
Pensando no mundo real, são duas entidades muito 
diferentes. Computacionalmente, não estabelecemos 
nenhum tipo de hierarquia ou herança entre eles. 
Assim, sua única interação é que um dos métodos 
13
de Veterinario interage com um objeto Pet, mas dado 
que Pet é uma classe abstrata, na prática, Veterinario 
sempre interage com um objeto herdeiro dela.
Porém, queremos que o banco de dados guarde in-
formações tanto sobre os animais que frequentam a 
clínica quanto sobre os veterinários que trabalham na 
clínica. E queremos que ambos tenham um método 
padronizado para mostrar sua ficha de cadastro.
Nesse ponto, temos o mesmo problema que já enun-
ciamos, quando falamos em tirar o método “fala” da 
classe Pet, ou seja, alguém implementa uma classe 
para o sistema e pode se esquecer de implementar 
o método para mostrar a ficha da entidade nova.
Reestruturar todo o sistema para fazer Pet e 
Veterinario herdarem de uma mesma classe abs-
trata é algo trabalhoso e que, ainda por cima, não 
faz sentido lógico. Veterinario e Pet não têm nada 
em comum, então por que deveriam herdar de uma 
mesma classe?
É precisamente neste ponto que entra a interface. 
Uma interface lembra um pouco uma classe abstrata, 
porque possui métodos abstratos, bem como porque 
todas as classes que implementam essa interface 
são obrigadas a implementar os métodos.
Uma classe pode herdar de apenas uma classe, mas 
pode implementar várias interfaces simultaneamen-
te. Assim, criar uma interface é parecido com criar 
uma classe. Porém, trocamos a palavra “class” por 
“interface” e todos os métodos são abstratos.
14
public interface Cadastravel {
 public abstract void mostraFicha();
}
Tabela 7: Código 7. Arquivo Cadastravel.java Fonte: 
Elaboração própria.
Fazer uma classe “assinar o contrato” com a interface é 
bastante parecido com herdar de uma classe abstrata. 
Usaremos a palavra “implements”, em vez de “extends”, 
seguido do nome da interface; ainda, implementaremos 
todos os métodos previstos na interface.
Ao fazer as classes Veterinario e Pet implementarem 
a interface Cadastravel, elas serão obrigadas a im-
plementar o método mostraFicha(), ou teremos erro 
de compilação. Em contrapartida, agora expandimos 
seu polimorfismo. Assim, podemos fazer funções 
que recebem objetos Cadastravel, sendo que essa 
função pode receber objetos de qualquer classe que 
implemente a interface Cadastravel.
Portanto, nosso sistema de cadastro consegue tra-
balhar tanto com Veterinario quanto com Pet. Caso 
novas classes sejam adicionadas ao sistema, elas 
também podem ser compatíveis desde que imple-
mentem a mesma interface.
public abstract class Pet implements Cadastravel {
 private String nome;
 private String dono;
 private String cor;
 private String raca;
 public Pet(String nome, String dono, String 
cor, String raca){
15
 this.nome = nome;
 this.dono = dono;
 this.cor = cor;
 this.raca = raca;
 }
 public String getNome(){
 return this.nome;
 }
 public String getDono(){
 return this.dono;
 }
 
 public abstract void fala();
 public void mostraFicha(){
 System.out.println("Nome: " + this.nome);
 System.out.println("Dono: " + this.dono);
 System.out.println("Cor: " + this.cor);
 System.out.println("Raça: " + this.raca);
 }
}
Tabela 8: Código 8. Arquivo Pet.java implementando a in-
terface Cadastravel Fonte: Elaboração própria.
public class Veterinario implements Cadastravel{
 public String nome;
 public int crmv;
 public double preco;
 public Veterinario(String nome, int crmv, dou-
ble preco){
 this.nome = nome;
 this.crmv = crmv;
 this.preco = preco;
 }
16
 public void consulta(Pet paciente){
 System.out.println(this.nome + " examinou 
" + paciente.getNome());
 System.out.println(paciente.getDono() + " 
deverá pagar R$" + this.preco);
 }
 public void mostraFicha(){
 System.out.println("Nome: " + this.nome);
 System.out.println("CRMV: " + this.crmv);
 System.out.println("Valor da consulta: " 
+ this.preco);
 }
}
Tabela 9: Código 9. Arquivo Veterinario.java implementando 
a interface Cadastravel Fonte: Elaboração própria.
public class Main {
 public static void main(String args[]){
 Cachorro dog = new Cachorro("Dot", "Brenda", 
"Malhado", "SRD");
 Gato cat = new Gato("Sheldon", "Rafael", 
"Laranja", "SRD");
 Veterinariovet = new Veterinario("Dr. 
Dogtor", 123456, 150.0);
 cat.fala();
 dog.fala();
 verificaFicha(cat);
 verificaFicha(vet);
 vet.consulta(cat);
 }
 public static void verificaFicha(Cadastravel cad){
 System.out.println("Consultando a ficha...");
 cad.mostraFicha();
 }
}
Tabela 10: Código 10. Arquivo Main.java com método estáti-
co utilizando interface Cadastravel Fonte: Elaboração própria.
17
HERANÇA VERSUS 
IMPLEMENTAÇÃO
Neste ponto, precisamos fazer uma distinção con-
ceitual importante: implementar uma interface é di-
ferente de herdar. Em uma herança, a classe filha 
recebe atributos e métodos da classe mãe. Em uma 
implementação, a classe se compromete a cumprir 
as especificações previstas na interface em troca de 
compatibilidade com código projetado para interagir 
com a interface.
Uma classe também pode implementar várias inter-
faces ao mesmo tempo, separando seus nomes por 
vírgula; a herança não. Uma classe pode herdar de 
apenas uma classe por vez. Por conta disso, muitos 
programadores usam interfaces para “simular” uma 
herança múltipla em Java. Na prática, isso não é he-
rança, é implementação.
Herança de interface
Uma classe herda de outra classe e implementa uma 
ou mais interfaces. Uma classe não herda de uma 
interface. Porém, uma interface pode herdar de uma 
ou mais interfaces. A sintaxe, para isso, é a mesma 
da herança de classes, ou seja, utiliza-se a palavra 
“extends” seguida do nome da(s) interface(s) mãe(s). 
Caso haja mais de uma, separa-se os nomes por 
vírgula.
A interface filha terá os mesmos métodos abstra-
tos que a(s) mãe(s), podendo ainda incluir métodos 
novos. Uma classe que implemente a interface filha 
18
deve implementar todos os métodos, tanto os herda-
dos das interfaces mãe quanto os próprios da filha.
Classes abstratas versus interfaces
A esta altura, é normal ficar um pouco confuso e, 
possivelmente, se perguntar: por que existem classe 
abstrata e interface, se ambas têm métodos abs-
tratos que devem ser implementados pelas classes 
que as herdam/implementam? Interface é só uma 
gambiarra para simular herança múltipla?
A primeira grande diferença é que, no caso da clas-
se abstrata, nem tudo é método abstrato. Podemos 
implementar métodos completos na classe abstrata 
e as classes filhas podem herdá-los e usá-los. Com 
isso, ao atualizar um sistema, podemos acrescentar 
um método novo na classe mãe sem precisar neces-
sariamente atualizar as filhas, desde que o método 
não seja abstrato.
Já no caso da interface, qualquer mudança impli-
cará automaticamente que todas as classes imple-
mentadas também sejam atualizadas, pois devem 
implementar os métodos.
Por consequência, em sistemas que mudam com 
frequência, é preferível criar uma estrutura de herança 
de modo que se possa, dentro do possível, fazer o 
máximo de atualizações nas classes “superiores”, 
de modo que elas se propagem sozinhas para todas 
as subclasses.
Uma diferença mais abstrata (ou “filosófica”): quando 
temos uma herança, a ideia que estamos passando 
19
é a de que as classes envolvidas são casos particu-
lares de uma mesma classe geral. Cachorros e gatos 
são casos particulares de pets.
Não é a mesma ideia com a interface, pois as clas-
ses que implementam uma interface não necessa-
riamente têm qualquer coisa em comum. Elas po-
dem representar entidades radicalmente diferentes, 
mas concordarem em fornecer uma funcionalidade 
específica.
FIQUE ATENTO
Apesar de usar a linguagem Java para exemplificar 
conceitos, é importante não misturar os conceitos 
gerais de programação orientada a objeto e limi-
tações específicas do Java, ou de qualquer outra 
linguagem.
Herança múltipla é proibida por algumas lingua-
gens, como o Java e o C#, mas é permitido por 
outras, como C++ e Python.
Interfaces também não são unanimidade, pois o 
próprio C++ não as oferece, sendo que sua funcio-
nalidade é obtida por meio de outras ferramentas.
Feita essa ressalva, várias linguagens orientadas 
a objeto são bastante semelhantes ao Java, como 
o C#.
20
TRATAMENTO DE EXCEÇÃO
Quando um programa está sendo executado, é nor-
mal ocorrer erros. Nem sempre as coisas saem con-
forme planejamos, pois podemos tentar acessar um 
arquivo que não existe, realizar uma conexão com 
um servidor e a rede estar fora do ar, o usuário pode 
passar um valor inválido em algum campo de entra-
da etc.
Todos esses casos podem provocar falhas de exe-
cução nos programas, podendo até mesmo fazer o 
programa ter sua execução interrompida e causar 
perda de dados para o usuário. Ou pior: imagine que é 
um sistema crítico, que deve estar sempre disponível.
Por isso, é importante prever os possíveis erros e 
tratá-los. Nem sempre o tratamento ocorre dentro 
da função ou da classe em que o erro pode ocorrer. 
Como vários módulos diferentes do programa po-
dem utilizar essa função ou classe, talvez diferentes 
módulos tenham diferentes alternativas.
Por exemplo, se um arquivo não existe, talvez um 
módulo possa simplesmente criar um arquivo em 
branco. Já outro módulo que apenas lê dados de um 
arquivo não tem essa opção; logo, precisa do arquivo.
Uma técnica bastante difundida para isso era utilizar 
os retornos de função. Em linguagens como a C, por 
exemplo, é comum que as funções que, a princípio, 
não retornariam nada retornem um booleano indi-
cando se ocorreu um erro ou não. Em sistemas mais 
complexos, é normal que seja declarada uma lista de 
21
constantes numéricas, cada uma representando um 
tipo de erro diferente, e as funções retornam essas 
constantes.
O módulo que executou a função fica responsável 
por testar seu retorno e, a partir dele, realizar o trata-
mento adequado para o erro que foi sinalizado. Essa 
abordagem, no entanto, tem duas desvantagens.
A primeira é que, quando chamamos uma função 
ou método, não somos obrigados a armazenar ou 
testar seu retorno. É comum, em sistemas do tipo, 
que programadores se esqueçam de testar o retorno 
da função, ou até mesmo deixem de fazê-lo propo-
sitalmente, por acreditarem erroneamente que os 
possíveis erros naquela função não terão impacto 
significativo no sistema. Com isso, o sistema pode 
tentar seguir a execução em uma situação poten-
cialmente problemática, causando os problemas já 
discutidos.
A outra desvantagem é a dificuldade de corrigir poste-
riormente o código para entender um erro. O retorno 
da função é um número dentre vários possíveis, e 
o significado do número, ou seja, o tipo de erro que 
a função provocou, está “codificado” no nome da 
constante.
Qualquer tipo de ferramenta de debugging ou log-
ging vai mostrar o valor numérico retornado pela 
função, então o programador perde bastante tempo 
lendo manualmente as tabelas de constantes de erro 
ao tentar compreender o fluxo problemático de seu 
programa.
22
Exceções
A solução padronizada para o problema descrito são 
as exceções. Exceção é um erro que ocorreu no pro-
grama. Várias linguagens, como o Java, apresentam 
meios de representar um erro e comunicá-lo a outros 
níveis.
Assim, se encontrar um problema, o método pode 
lançar uma exceção. O método que o chamou tem 
duas opções: (i) pode capturar a exceção e tratá-la; 
(ii) pode lançá-lo, de modo que o método que chamou 
esse método receba a exceção, que, por sua vez, 
também pode tratá-la ou lançá-la ao nível superior.
Com “tratar” uma exceção, queremos dizer simples-
mente criar um bloco de código com ações que se-
jam tomadas quando o erro previsto for encontrado.
Lançando exceções
Quando implementamos um método, após os pa-
rênteses de abrir chaves podemos usar a palavra 
“throws”, seguida da exceção que acreditamos que 
aquele método pode provocar.
As exceções são definidas por classes também, sen-
do que há uma classe genérica “Exception”, e temos 
várias exceções já prontas que herdam dessa clas-
se. Caso o erro ocorra e seja relacionado à exceção 
prevista, ao invés do programa travar ou encerrar, o 
método é interrompido, e oJava busca no método 
que o chamou algum tratamento para aquela exce-
ção. Em caso de não encontrar e o método também 
lançar a exceção, segue para o método que o cha-
23
mou e sucessivamente. Com isso, para de “subir de 
nível” na pilha de execução quando encontrar um 
tratamento ou encontrar um método que não trate 
nem lance a exceção. Nesse caso sim a execução 
do programa será interrompida por conta do erro.
O bloco try/catch
A fim de tratar uma possível exceção, precisamos 
começar pelo comando “try”, o qual abrirá um bloco 
de comandos. Dito de outra forma, após a palavra 
“try”, abriremos as chaves, dentro das quais coloca-
remos todo o código que pode provocar a exceção. 
Por exemplo, uma chamada para um método que 
pode lançar uma exceção. Se qualquer uma daquelas 
linhas falhar, o bloco “try” é interrompido, e a execu-
ção salta para os blocos “catch”.
Os blocos “catch” surgem logo após o “try”. Podemos 
ter quantos blocos “catch” forem necessários. Cada 
bloco recebe entre parênteses uma exceção. A ideia 
de criar vários blocos catch é cada um lidar com 
um tipo diferente de exceção. Um bloco “catch” que 
simplesmente receba um objeto “Exception” lida com 
qualquer tipo de exceção.
O Java executa, assim, o primeiro bloco “catch” cuja 
exceção corresponder à exceção que ocorreu no “try”.
Finally
Imagine que vários erros diferentes possam ocorrer 
em uma mesma função, e cada um exige tratamento 
específico. Ao final, existe uma ação comum que 
pode ser tomada independentemente de ter dado 
24
erro ou não, ou de qual erro ocorreu. Por exemplo, 
imagine que leremos dois números do teclado e re-
alizaremos uma divisão entre eles. Pelo menos duas 
exceções podem ocorrer:
 ● Se o valor do denominador for 0, teremos uma 
ArithmeticException na divisão.
 ● Se o usuário digitar algo que não é número, pode-
mos ter uma InputMismatchException.
Suponha que, em caso de erro, queremos mostrar 
uma mensagem amigável explicando qual foi o erro 
que ocorreu. Porém, independentemente do erro, 
queremos que a função retorne um resultado mes-
mo assim.
As mensagens que mostraremos variam conforme 
o erro. Por isso, faz sentido que cada uma entre em 
um “catch” diferente. A atribuição de valor é padrão, 
por isso faz sentido ficar repetindo código? Bem, a 
resposta é não.
É aí que entra o bloco “finally”, que é empregado de-
pois de todos os “catch”, e executado independente-
mente de qual “catch” foi executado, ou até mesmo 
quando não ocorrerem exceções.
O “finally” é tipicamente utilizado para realizar ope-
rações de limpeza após uma possível operação ar-
riscada, como fechar recursos (um arquivo aberto, 
por exemplo), reiniciar o valor de variáveis, limpar 
ponteiros etc. Vamos verificar na prática uma imple-
mentação de tratamento de exceção:
25
 
import java.util.*;
public class Main {
 public static void main(String args[]) {
 double resultado = 0;
 // Vamos executar linhas de código com 
possíveis problemas...
 try {
 resultado = fazDivisao();
 }
 // Tratando os erros...
 catch (ArithmeticException e) {
 System.out.println("Você tentou dividir 
por zero!");
 resultado = -1;
 } catch (InputMismatchException e) {
 System.out.println("Número inválido!");
 resultado = -1;
 }
 // Já fizemos os tratamentos diferenciados 
nos catch...
 // Agora vem o comum a todos:
 finally {
 System.out.println("O resultado da di-
visão foi: " + resultado);
 }
 }
 // A função não irá tratar essas duas exceções.
 // Ela irá jogar para ser tratada um nível 
acima.
 public static double fazDivisao() throws 
InputMismatchException, ArithmeticException {
 int numero1, numero2;
 Scanner scan = new Scanner(System.in); 
26
 // Nas próximas linhas: risco de 
InputMismatchException
 // Usuário pode digitar algo que não é int 
 System.out.println("Digite o numerador: ");
 numero1 = scan.nextInt();
 System.out.println("Digite o denominador: 
");
 numero2 = scan.nextInt();
 scan.close();
 // próxima linha: risco de ArithmeticException
 // se o usuário fizer numero2 = 0
 return (double)numero1/numero2; 
 }
}
Tabela 11: Código 11. Tratamento de exceção de uma fun-
ção com divisão e leitura de valores pelo teclado. Fonte: 
Elaboração própria.
Nesse exemplo, o desenvolvedor já sabia da pos-
sibilidade de ocorrerem exceções ao fazer leitura 
de inteiros pelo teclado e ao fazer a divisão, mas 
mesmo assim optou por não tratá-los. O método “fa-
zDivisao” simplesmente joga as possíveis exceções 
para o nível superior, então o nível superior deve se 
responsabilizar por tratá-las ou repassá-las também.
No nível superior (função main), note que a chamada 
para a função está dentro de um “try”. Se você execu-
tar o programa e digitar valores bem-comportados, 
não há problema. A função executa até o final, e o 
programa salta do “try” direto para o “finally”. Mas 
caso faça algo indevido, como digitar “abc” para um 
dos números ou 0 para o denominador, a função não 
completa a execução. O “catch” correspondente ao 
27
erro provocado, que é executado, em seguida, o pro-
grama segue para o “finally”.
Criando o próprio tipo de exceção
Não precisamos utilizar apenas as exceções prontas 
do Java. Podemos criar nossas próprias exceções 
e implementar as verificações personalizadas de 
certas condições, utilizando a palavra “throw” para 
ordenar a interrupção da execução do método e o 
lançamento da sua exceção.
A exceção personalizada pode herdar de uma das 
várias exceções existentes do Java, o que pode ser 
útil caso alguma função tenha previsto uma dessas 
exceções, mas não a sua em particular. Por exemplo, 
se a sua exceção se refere a uma falha específica de 
conta, ela pode ser herdeira da ArithmeticException. 
Caso nenhuma opção existente seja uma boa classe-
-base para ela, pode simplesmente herdar da classe 
genérica Exception.
Pode-se, inclusive, personalizar uma mensagem de 
erro para ela, e é essa a mensagem exibida caso 
o programa eventualmente dê erro sem tratar a 
exceção.
Vamos modificar o exemplo anterior. Suponha que, 
por algum motivo, nossa função não deva trabalhar 
com números negativos. Portanto, criamos uma 
exceção específica de número negativo. A String 
passada no construtor é a mensagem de erro per-
sonalizada que aparece, caso o programa dê erro 
sem ser tratado.
28
public class ValorNegativo extends Exception {
 public ValorNegativo(String mensagem) {
 super(mensagem);
 }
}
Tabela 12: Código 12. Arquivo ValorNegativo.java Fonte: 
Elaboração própria.
import java.util.*;
public class Main {
 public static void main(String args[]) {
 double resultado = 0;
 // Vamos executar linhas de código com 
possíveis problemas...
 try {
 resultado = fazDivisao();
 }
 // Tratando os erros...
 catch (ArithmeticException e) {
 System.out.println("Você tentou dividir 
por zero!");
 resultado = -1;
 } catch (InputMismatchException e) {
 System.out.println("Número inválido!");
 resultado = -1;
 }
 // Tratando nossa exceção personalizada:
 catch (ValorNegativo e) {
 System.out.println("Valor negativo.");
 }
 // Já fizemos os tratamentos diferenciados 
nos catch...
 // Agora vem o comum a todos:
 finally {
 System.out.println("O resultado da di-
visão foi: " + resultado);
29
 }
 }
 // Nossa exceção personalizada é lançada pela 
função:
 public static double fazDivisao() thro-
ws InputMismatchException, ArithmeticException, 
ValorNegativo {
 int numero1, numero2;
 Scanner scan = new Scanner(System.in); 
 // Nas próximas linhas: risco de 
InputMismatchException
 // Usuário pode digitaralgo que não é int 
 System.out.println("Digite o numerador: ");
 numero1 = scan.nextInt();
 System.out.println("Digite o denominador: 
");
 numero2 = scan.nextInt();
 scan.close();
 // lançando nossa exceção personalizada:
 if (numero1 < 0 || numero2 < 0) {
 throw new ValorNegativo("Erro! Você não 
deveria digitar valores negativos!");
 }
 // próxima linha: risco de ArithmeticException
 // se o usuário fizer numero2 = 0
 return (double)numero1/numero2; 
 }
}
Tabela 13: Código 13. Exemplo do código 11 tratando a 
exceção ValorNegativo.
Essa exceção se comporta como qualquer uma das 
exceções padrão do Java: o método que não a trata 
informa que vai jogá-la pelo “throws” em sua decla-
30
ração. O método que se propõe a tratá-la tem um 
bloco “catch” especial para ela. A mensagem interna 
aparece, caso dê errado, para os desenvolvedores sa-
berem qual foi o erro e, com isso, possam rastreá-lo.
SAIBA MAIS
A documentação oficial do Java disponibilizada 
pela Oracle contém a documentação da classe 
“Exception” e de todas as suas subclasses, as 
quais são pré-definidas quando da instalação do 
Java. Saiba mais em: https://docs.oracle.com/ja-
vase/8/docs/api/java/lang/Exception.html�
31
https://docs.oracle.com/javase/8/docs/api/java/lang/Exception.html
https://docs.oracle.com/javase/8/docs/api/java/lang/Exception.html
CONSIDERAÇÕES FINAIS
Iniciamos este módulo expandindo a forma com que 
lidamos com a herança por meio de classes e mé-
todos abstratos. Com isso, pudemos verificar que 
é possível impedir certas classes de serem instan-
ciadas, caso não faça sentido lógico no programa, 
bem como que somos capazes de exigir que todas 
as classes herdeiras necessariamente implementem 
um certo método, sem precisar herdar alguma versão 
já pronta dele.
Em seguida, estudamos novas possibilidades de po-
limorfismo sem herança com a ajuda das interfaces. 
As interfaces permitem que diferentes classes que 
não tenham qualquer tipo de relação de herança se 
comprometam a implementar os mesmos métodos, 
permitindo que façamos polimorfismo entre objetos 
de todas essas classes.
Por fim, aprendemos a utilizar as exceções em Java 
visando a transmitir as mensagens sobre os possí-
veis erros entre os diferentes métodos do programa, 
de modo que eles sejam tratados adequadamente e 
evitem que o programa falhe.
32
Referências Bibliográficas 
& Consultadas
ASCÊNCIO, A. F. G.; CAMPOS, E. A. V; Fundamentos 
da programação de computadores. 2.ed. São Paulo: 
Pearson Prentice Hall, 2007 [Biblioteca Virtual].
DEITEL, P.; DEITEL, H. Java: como programar. 10. 
ed. São Paulo: Pearson Education do Brasil, 2017 
[Biblioteca Virtual].
DOWNEY, A. B. Pense em Python. 2. ed. São Paulo: 
Editora Novatec, 2016.
ELLIOTT, E. Composing Software: An exploration of 
functional programming and object composition in 
JavaScript. São Francisco: [s.n.], 2018.
HORSTMANN, C. S; CORNELL, G. Core Java 2. 8. ed. 
São Paulo: Pearson Prentice Hall, 2010. 
MELO, A. C. V.; SILVA, F. S. C. Princípios de linguagem 
de programação. São Paulo: Blücher, 2003 [Minha 
Biblioteca].
SANTOS, R; Introdução à programação orientada a 
objetos usando Java. 2. ed. Rio de Janeiro: Elsevier, 
2013.
SCHILDT, H. Java para iniciantes: crie, compile e 
execute programas Java rapidamente. 6. ed. Porto 
Alegre: Bookman, 2015 [Minha Biblioteca].
SOMMERVILLE, I. Engenharia de software. 10. 
ed. São Paulo: Pearson Education do Brasil, 2018 
[Biblioteca Virtual].
	_GoBack
	INTRODUÇÃO
	CLASSES ABSTRATAS
	MÉTODOS ABSTRATOS
	INTERFACES
	HERANÇA VERSUS IMPLEMENTAÇÃO
	TRATAMENTO DE EXCEÇÃO
	CONSIDERAÇÕES FINAIS
	Referências Bibliográficas & Consultadas

Continue navegando