Please enable JavaScript.
Coggle requires JavaScript to display documents.
Programação Orientada a Objetos com Java - Coggle Diagram
Programação Orientada a Objetos com Java
Classe
Membros
Métodos (funções / operações)
Elimina a repetição de trecho de código ao longo do programa principal
Delega a execução de uma ação para a classe responsável
Atributos (propriedades) - dados / campos
Recursos
Construtores
Sobrecarga
Encapsulamento
Herança
Polimorfismo
Classificação (O que pode ser representado pro classes)
Entidades
Produto, Cliente, Triangulo
Serviços
ProdutoService, ClienteService, EmailService, StorageService
Controladores
ProdutoController, ClienteController
Utilitários
Calculadora, Compactador
Outros (views, repositórios, gerenciadores, etc.)
Definição
Unidade básica de encapsulamento
Modelo de algo para construir um objeto
É um tipo estruturado composto por membros
A classe pode prover muitos recursos
É um tipo composto (pode ter diversos atributos)
Modificadores de acesso
public
O membro é acessado por todas classes ( ao menos que ele resida em um módulo diferente que não exporte o pacote onde ele está)
private
O membro só pode ser acessado na
própria classe
protected
O membro só pode ser acessado nas classes do
mesmo pacote
, bem como em
subclasses de pacotes diferentes
default (nada)
O membro só pode ser acessado nas classes do
mesmo pacote
Exemplo
O triângulo pode ser representado por uma classe com nome Triangulo
Essa classe possui
Atributos
lados
a
b
c
Métodos
area()
perimetro()
A classe Triangulo é um tipo
Um cliente pode ser representado pela classe Cliente
Atributos
nome
cpf
email
endereco
métodos
comprarProduto()
pagarFatura()
Benefícios de se calcular a área de um triângulo por meio de um método dentro da classe Triangle
Reaproveitamento de código
elimina-se o código repetido no programa principal.
Delegação de responsabilidades
quem deve ser responsável por saber como calcular a área de um triângulo é o próprio triângulo. A lógica do cálculo da área não deve estar em outro lugar.
Princípio da Coesão
Instanciação
Para utilizar membros não estáticos de uma classe é necessário instanciá-la, ou seja, criar um objeto
O comando usado para instanciar uma classe é "new"
Ao serem declaradas, as variáveis são criadas numa área de memória chamada Stack
Durante a execução do programa, pode-se fazer a alocação dinâmica de memória usando o comando "new"
No momento em que se faz "x = new Triangle()", um objeto é criado em outra área de memória chamada Heap
Heap: área de memória aonde são criados os os objetos dinâmicos (durante a execução)
A variável "x" guarda apenas a referência ao objeto que está no Heap - contém o endereço que aponta para o objeto
A classe é apenas a definição do tipo
Os objetos são instâncias da classe
Estrutura de uma classe
public double a;
public double b;
public double c;
atributos da classe
public double area() {
método da classe
public class Triangle {
nome da classe
return Math.sqrt(p
(p - a)
(p - b) * (p - c));
Corpo do método
package entities;
pacote da classe
}
}
double p = (a + b + c) / 2.0;
Projeto da classe (UML - Diagrama de classes)
Nome da classe
Atributos da classe
Métodos da classe
Toda classe em Java é uma subclasse da classe Object
Object possui os métodos
equals - compara se o objeto é igual a outro
hashCode - retorna um código hash do objeto
toString - converte o objeto para string
getClass - retorna o tipo do objeto
Logo, toda classe herda os métodos da classe mãe Object
Membros estáticos
Também chamados membros de classe
Em oposição a membros e instância
São membros que fazem sentido independentemente de objetos
Não precisam de objeto para serem chamados.
São chamados a partir do próprio nome da classe.
Aplicações comuns
Classes utilitárias
Math.sqrt(double) - Math é o nome da classe
Declaração de constantes
public static final double PI = 3.14159;
Padrão de escrita de constantes
letras maiúsculas
se for composta por mais de uma palavra, usar underline entre elas (NET_SALARY).
Não é possível chamar um método não estático dentro de um método estático (por exemplo, dentro do main(String[] args), se eles estiverem dentro da mesma classe; métodos não estáticos são acessados pela instância da classe).
Uma classe que possui somente membros estáticos, pode ser uma classe estática também. Esta classe não poderá ser instanciada.
Membros estáticos vs. Membros de instância
Para um método de instância, cada objeto tem o seu valor, calculado usando os atributos da própria classe (é preciso instanciar os objetos para usar seus membros).
São chamadas a partir da variável de referência que guarda o endereço para o objeto
Já para um método estático, os resultados das chamadas do método não mudam quando os mesmos parâmetros são passados.
Por exemplo, os cálculos não mudam para calculadoras diferentes (são cálculos estáticos).
São chamadas a partir do nome da classe
Construtores
Operação especial da classe executada no momento da instanciação do objeto
Usos
Iniciar valores dos atributos
Permitir ou obrigar que o objeto receba dados ou dependências no momento de sua instanciação (injeção de dependência)
Se não há um construtor customizado, a classe disponibiliza o construtor padrão
Product p = new Product()
É possível especificar mais de um construtor na mesma classe (sobrecarga)
Por padrão, quando um objeto é instanciado, os atributos são criados com seus valores padrão (null para variáveis de referência e zero para variáveis numéricas de tipos primitivos, por exemplo);
Como não faz sentido um produto sem nome, etc. (ou seja, deixá-lo em um estado inconsistente), cria-se um construtor personalizado que obriga o fornecimento de parâmetros no momento da instanciação
Recomenda-se colocar o construtor entre os atributos e os métodos da classe
Gerar construtor automaticamente no Eclipse
Botão direito -> Source -> Generate Constructor using Fields
Palavra this
É uma referência para o próprio objeto
Usos
Diferenciar atributos do objeto de variáveis locais (parâmetros do método ou construtor)
Passar o próprio objeto como argumento na chamada de um método ou construtor
Na chamada do método placeNewPiece, passa-se uma letra, um número e uma peça. Para a peça instanciada, passa-se uma referência à própria classe (CheesMatch); isso significa que o objeto King tem um atributo que guarda a referência ao objeto ChessMatch
Usado para eliminar ambiguidade
Sobrecarga
Recurso de uma classe para oferecer mais de uma operação com o mesmo nome, porém com diferentes listas de parâmetros
Exemplo: uma classe pode ter diferentes construtores com listas de parâmetros diferentes.
Por exemplo, deseja-se instanciar um produto, porém ele ainda não tem quantidade em estoque
Para issso, cria-se um construtor adicional que recebe como parâmetros apenas o nome e preço do produto
Disponibiliza mais de uma versão da mesma operação
Nota: é possível também incluir um construtor padrão
Encapsulamento
Princípio de esconder detalhes de implementação, expondo apenas operações seguras e que mantenham os objetos em um estado consistente
Regra de ouro: o objeto deve sempre estar em um estado consistente, e a própria classe deve garantir isso
Analogia: aparelho de som tem vários circuitos internos, porém o usuário não tem acesso a esse circuitos para não danificar o aparelho. O usuário só pode colocar um CD no aparelho, pausar e executar uma música, etc. (operações expostas ao usuário - operações que não prejudicam o funcionamento do aparelho)
Regra geral básica
Não expor nenhum nenhum atributo (modificador de acesso private - encapsula o atributo)
Atributos devem ser acessados por meio de métodos get e set
Padrão JavaBeans
Padrão de desenvolvimento que estabelece algumas regras básicas para construção dos objetos
Exemplo
Padrão para implementação de getters e setters
Nem todos os atributos terão métodos set (isso irá depender da regra do negócio), de forma a proteger o objeto de alterações inconsistentes
Comandos para gerar os métodos get e set automaticamente
Botão direito -> Source -> Generate Getters and Setters
Variáveis
Classes são tipos referência
Não podem ser entendidas como caixas, mas sim como "tentáculos" (ponteiros) para caixas
Quando instancia-se um objeto, o objeto é criado em uma área de memória chamada Heap (alocação dinâmica de memória - em tempo de execução)
Esse espaço de memória contém os valores para os atributos do objeto criado
Quando se fala em memória, refere-se à memória RAM
As variáveis declaradas são criadas em uma região da memória chamada Stack (alocação estática de memória)
Quando o tipo da variável é uma classe, essa região no Stack guarda o endereço de memória do objeto (no Heap) quando o objeto é instanciado.
Aceitam valor "null"
Se uma variável recebe "null", ela é iniciada, mas não aponta para nada
Tipos primitivos são tipos valor
Tipos valor são caixas e não ponteiros.
Ao serem declaradas, caixas são criadas na área de memória chamada Stack e os valores atribuídos são guardados nessa caixa
boolean
true or false
char
Unicode character
byte
Inteiro
short
inteiro
int
inteiro
long
inteiro
float
ponto flutuante
double
ponto flutuante
O compilador verifica se a variável foi inicializada. Uma variável não pode ser usada sem ter sido inicializada.
Valores padrão
Quando aloca-se (new) qualquer tipo estruturado (array ou classe), os seguintes valores são atribuídos aos seu elementos (atributos)
números: 0
boolean: false
char: caractere código 0 (Unicode character)
objeto: null
Tipos referência vs. tipos valor
Classe
Vantagem: usufrui de todos recursos OO
Variáveis são ponteiros
Objetos precisam ser instanciados usando new, ou
apontar para um objeto já existente.
Aceita valor null
Y = X;
"Y passa a apontar para onde X aponta"
Objetos instanciados no heap
Objetos não utilizados são desalocados em um
momento próximo pelo garbage collector
O garbage collector é um processo que serve para verificar o heap e desalocar os objetos que não são mais utilizados
Tipo primitivo
Vantagem: é mais simples e mais performático
Performático - no sentido que quando precisa-se carregar uma imagem, o uso de tipos primitivos proporciona economia de memória e maior eficiência
Variáveis são caixas
Não instancia. Uma vez declarados, estão prontos
para uso.
Não aceita valor null
Y = X;
"Y recebe uma cópia de X"
"Objetos" instanciados no stack
"Objetos" são desalocados imediatamente quando
seu escopo de execução é finalizado
Desalocação
Garbage collector
Monitora os objetos alocados dinamicamente pelo programa (no heap), desalocando aqueles que não estão mais sendo utilizados (ou seja, que não tem mais referência)
É um processo que automatiza o gerenciamento de memória (Heap) de um programa em execução
Por escopo
Dentro do Stack, há uma área referente ao escopo do programa. Quando o escopo de execução é finalizado, as variáveis são desalocadas imediatamento
Variáveis locais são desalocadas imediatamente assim que seu escopo local sai de execução
Não tem relação com Garbage Collector
Vetores
Arranjo
Estrutura de dados
Homogênea (dados do mesmo tipo)
Ordenada (elementos acessados por meio de posições)
Alocada de uma vez só em um bloco contíguo de memória
São arranjos unidimensionais
Vantagens
Acesso imediato aos elementos pela posição
Não é necessário percorrer todo array até a posição desejada
Acesso muito rápido
Desvantagens
Tamanho fixo
O tamanho é definido no momento da instanciação do array
Dificuldade para se realizar inserções e deleções
Por exemplo, ao remover o elemento da posição 1, todos os elementos a partir da posição 2 devem ser movidos para cobrir a posição vaga
Muito custoso (tempo)
Vetor do tipo referência
Ao ser instanciado, os elementos são "null"
Para atribuir um valor a um elemento, é necessário instanciar um objeto e fazer com que o elemento da posição x do vetor aponte para o objeto
Cada posição guarda o endereço de memória do objeto que foi instanciado
Comprimento do vetor: método length()
O uso do método length torna o código mais coeso
Conversões entre tipos referência e valor
Boxing
É o processo de conversão de um objeto tipo valor para um objeto tipo referência compatível
Unboxing
É o processo de conversão de um objeto tipo referência para um objeto tipo valor compatível
O casting é necessário em algumas situações (para torná-los compatíveis)
Wrapper classes
São classes equivalentes aos tipos primitivos
Boxing e unboxing é natural na linguagem (não precisa de casting)
Usados para tratar os tipos primitivos como classes, de forma transparente ao compilador (sem necessidade de casting)
Uso comum: campos de entidades em sistemas de informação
Pois tipos referência (classes) aceitam valor null e usufruem dos recursos OO
Isso é bom para fazer a equivalência entre as classes e o banco de dados
Importante para que os atributos possam aceitar valores null
Existem para que o boxing e unboxing entre tipos equivalentes seja realizado de forma natural (sem necessidade de casting)
São classe que foram criadas com objetivo de tratar os tipos primitivos como classes de uma forma transparente ao compilador (sem necessidade de fazer casting)
Laço "for each"
Sintaxe opcional e simplificada para percorrer coleções
Sintaxe
Para cada elemento do vetor faça
Listas
Conceito de lista
É uma estrutura de dados
Homogênea (dados do mesmo tipo)
Inicia vazia, e seus elementos são alocados sob demanda
Cada elemento ocupa um "nó" (ou nodo) da lista
O nodo armazena o valor e a referência para o nodo relacionado (seguinte)
Ordenada (elementos acessados por meio de posições)
Tipo (interface): List
Classes que implementam
ArrayList, LinkedList, etc.
Uma interface define apenas as especificações das operações
A interface não pode ser instanciada
Vantagens
Tamanho variável
Facilidade para se realizar inserções e deleções
As vantagens da lista são justamente os pontos fracos do vetor
Desvantagens
Acesso sequencial aos elementos
Deve-se navegar em todos nodos até chegar na posição desejada
Dependendo do tipo de implementação da lista, a navegação pode ser otimizada
O ArrayList é uma implementação otimizada de List (mistura de um vetor e lista)
Assuntos relacionados
interfaces
generics
predicados (lambda)
Operações
Tamanho da lista
size()
Encontrar posição de elemento
indexOf(obj), lastIndexOf(obj)
Quando o indexOf não encontra o elemento ele retorna "-1"
Remover elementos da lista
remove(obj), remove(int), removeIf(Predicate)
Predicate - função lâmbida que retorna V ou F
removeIf(x -> x.charAt(0) == 'M');
Filtrar lista com base em predicado
List<Integer> result = list.stream().filter(x -> x > 4).collect(Collectors.toList());
Inserir elemento na lista
add(obj)
add(int, obj) - inserção em posição específica
Encontrar primeira ocorrência com base em predicado
Integer result = list.stream().filter(x -> x > 4).findFirst().orElse(null);
Obter o elemento de uma posição
get(position)
Declaração
List<Tipo> list;
Não aceitas tipos primitivos
<Tipo> - generics
permite parametrizar a definição de um tipo informando um tipo específico desejado
Instanciação
new ArrayList<>()
ArrayList é uma das classes que implementa a interface List
A especificação do tipo se tornou opcional nas últimas versões do Java
Matrizes
Em programação, "matriz é o nome dado a arranjos bidimensionais
Vetor de vetores
Arranjo (array)
Ordenada (elementos acessados por meio de posições)
Alocada de uma vez só, em um bloco contíguo de memória
Homogênea (dados do mesmo tipo)
Vantagens
Acesso imediato aos elementos pela sua posição
Desvantagens
Tamanho fixo
Dificuldade para se realizar inserções e deleções
Em algumas situações, não funciona como em vetores: não é preciso deslocar os elementos para preencher os vazios causados por remoções
Declaração e instanciação na memória
int[][] mat = new int[n][n];
Matriz de ordem n
Obter quantidade de linhas da matriz
mat.length
Obter quantidade de colunas da matriz
mat[i].length
Observação: matriz de ordem N -> N linhas e N colunas
Enumerações
É um tipo especial que serve para especificar de forma literal um conjunto de constantes relacionadas
Palavra chave em Java: enum
Vantagem: melhor semântica, código mais legível e auxiliado pelo compilador
Exemplo: ciclo de vida de um pedido
Entregue
Enviado
Processando
Aguardando o pagamento
Criando um tipo enumerador
Uma classe pode ter um tributo do tipo enumerado
Conversão de String para enum
OrderStatus os2 = OrderStatus.valueOf("DELIVERED");
Instanciando um tipo Enum
OrderStatus os1 = OrderStatus.DELIVERED;
Notação UML
Pode-se especificar um número inteiro para cada enumerado
Constantes enum são implicitamente final
Constantes enum são implicitamente static
Qualquer tentativa de criar um objeto de um tipo enum com um operador new resulta em um erro de compilação
Design
Categorias de classes
Em um sistema orientado a objetos, de modo geral "tudo" é objeto.
Por questões de design tais como organização, flexibilidade, reuso, delegação, etc., há várias categorias de classes
Views
Telas do sistema
Services
Representam funcionalidades do sistema
Entities
Entidades de negócio: Product, Customer, Order, etc.
Repositories
Objetos responsáveis por acessar os dados: banco dados, etc.
Controllers
Faz o link entre a tela e o sistema
Composição
É um tipo de associação que permite que um objeto contenha outro
Vantagens
Coesão
Cada objeto é responsável por uma coisa: tem uma responsabilidade simples e bem definida
Organização: divisão de responsabilidades
Cada classe tem sua responsabilidade
Flexibilidade
Trabalhar com alguma coisa que está bem dividida em partes é mais flexível que trabalhar com algo muito grande ou mal dividida
Reuso
Pode ser reaproveitado em mais de um lugar
Nota: embora o símbolo UML para composição (todo-parte) seja o diamante preto, neste contexto estamos chamando de composição qualquer associação tipo "tem-um" e "tem-vários".
O lado ligado ao diamante é o todo
O lado sem o diamante é a parte
Exemplo: um pedido (todo) tem vários itens (partes)
A composição pode ocorrer entre classes entidades e serviços
Uma associação entre classes pode ser considerada uma composição
Relação
"tem-um"
"tem-vários"
A classe que contém os vários itens terá um atributo do tipo List
A lista não é incluída no construtor
Apenas inicia-se a lista na declaração de atributos da classe
A inserção e remoção de elementos da lista é realizada por métodos da classe
O método set não deve ser implementado para a lista: não se pode substituir a lista existente por outra
Composição de objetos na memória
Exemplo
Associação do Worker com o Department
Associação do Worker com os contratos por hora (HourContract)
StringBuilder
Classe usada na construção de Strings muito grandes a partir de Strings menores no lugar do operador de concatenação que consome muita memória tornando o programa lento
A função que permite concatenar é append() (acrescentar no final)
Herança
É um tipo de associação que permite que uma classe herde
todos
dados e comportamentos de outra
Definições importantes
Superclasse (classe base) / subclasse (classe
derivada)
Account é a superclasse e BusinessAccount é a subclasse
Herança / extensão
A classe BusinessAccount estende a class Account, acrescenta novas característcas e métodos
Generalização/especialização
A classe Account é o tipo mais genérico, e a classe BusinessAccount é uma classe específica
Herança é uma associação entre classes (e não entre objetos)
Quando uma subclasse é instanciada apenas um objeto é criado com todos os membros herdados e próprios
Relação "é-um"
Exemplo: uma conta empresarial (BusinessAccount) é uma conta (Account), porém com algo mais (especificidades)
Sintaxe
class A extends B
Vantagens
Reuso
Herança permite o reuso de atributos e métodos (dados e comportamentos)
Polimorfismo
Exemplo
Herança
Palavra super
Usa-se a palavra chave super na subclasse para se referir à superclasse
O comando super(parâmetros) pode ser usado dentro do construtor da subclasse para invocar o construtor da superclasse de forma que os atributos da superclasse seja inicializados com os argumentos transmitidos.
Isso evita repetição de comandos, já que a lógica de atribuição já está implementada na superclasse
Modificador de acesso "protected"
Um membro da classe definido como protected pode ser acessado:
por membros da própria classe,
por classes do mesmo pacote e
por subclasses em diferentes pacotes
Upcasting e Downcasting
Upcasting
Casting da subclasse para superclasse
(converter um objeto da subclasse para um objeto da superclasse)
Uso comum: polimorfismo
Exemplo: como uma conta empresarial é uma conta, pode-se atribuir um objeto do tipo BusinessAccount a uma variável do tipo Account.
Não há necessidade de casting explícito
Downcasting
Casting da superclasse para subclasse
(converter um objeto da superclasse para um objeto da subclasse)
Palavra instanceof
Usado para saber se uma variável de um tipo é uma instância de outra classe
Uso comum: métodos que recebem parâmetros genéricos (ex: equals)
Exemplo: como uma conta empresarial é uma conta, mas uma conta não é uma conta empresarial, não pode-se atribuir um objeto do tipo Account a uma variável do tipo BusinessAccount.
Pode-se forçar a conversão através do casting (o casting tem o tipo da variável da subclasse)
Ao fazer o downcasting, pode ocorrer um erro em tempo de execução (o compilador não identifica o erro) - essa situação pode ser evitada pelo programador
Sobreposição ou sobrescrita
É a implementação de um método de uma superclasse na subclasse
Usar para definir um comportamento específico da subclasse
É fortemente recomendável usar a anotação
Overrride
em um método sobrescrito
Facilita a leitura e compreensão do código (o programador irá saber que o método é sobrescrito)
Avisamos ao compilador (boa prática) - o compilador é capaz de verificar se a assinatura do método está correta
Palavra
super
É possível chamar a implementação da superclasse usando a palavra super.
Exemplo: suponha que, na classe BusinessAccount, a regra para saque seja realizar o saque normal ente da superclasse, e descontar mais 2.0.
Override
public void withdraw(double amount) {
super.withdraw(amount);
balance -= 2.0;
}
Reutilização do código que já foi implementado na superclasse
Classes e métodos final
Palavra chave: final
Classe: evita que a classe seja herdada
Exemplo: public final class SavingsAccount {
Método: evita que o método seja sobreposto
Pra quê usar a palavra chave final
Segurança
: dependendo das regras do negócio, às vezes é desejável garantir que uma classe não seja herdada, ou que um método não seja sobreposto.
Geralmente convém acrescentar final em métodos sobrepostos, pois sobreposições múltiplas podem ser uma porta de entrada para inconsistências
Performance
: atributos de tipo de uma classe final são analisados de forma mais rápida em tempo de execução.
Exemplo clássico: String
Se uma classe for "final" a operação do tipo reflection - desserialização de um dado no formato JSON para o objeto em memória - é realizada de forma mais rápida
Pilares da Orientação a Objeto
Herança
Polimorfismo
Recurso que permite que variáveis de um mesmo tipo mais genérico possam apontar para objetos de tipos específicos diferentes, tendo assim comportamentos diferentes conforme cada tipo específico.
Exemplo
Account x = new Account(1020, "Alex", 1000.0);
Account y = new SavingsAccount(1023, "Maria", 1000.0, 0.01);
x.withdraw(50.0);
y.withdraw(50.0);
A chamada de método x.withdraw irá executar o método do objeto Account;
A chamada do método y.withdraw irá executar o método do objeto SavingsAccount
O conceito é simples. O desafio está na aplicação desse recurso
Soluções sofisticadas, elegantes e flexíveis utilizando esse recurso
Variáveis do mesmo tipo se comportando de formas diferentes, conforme os objetos para os quais ela aponta
Objetos de tipos diferentes na memória, mas variáveis do mesmo tipo
Importante entender
A associação do tipo específico com o tipo genérico é realizada em tempo de execução (é feito um upcasting)
O compilador não sabe para qual tipo específico a chamada do método será feita (ele só sabe qual é o tipo da variável)
O método adequado é processado em tempo de execução com base no objeto instanciado
Encapsulamento
Classes Abstratas
São classes que não podem ser instanciadas
É uma forma de garantir herança total: somente subclasses não abstratas podem ser instanciadas, mas nunca a superclasse abstrata
Exemplo
Suponha que em um negócio relacionado a banco, apenas contas poupança e contas para empresas são permitidas. Não existe conta comum.
Para garantir que contas comuns não possam ser instanciadas, basta acrescentarmos a palavra "abstract" na declaração da classe.
public abstract class Account {
(...)
Notação UML: itálico
Questionamento
Se a superclasse (classe Account) não pode ser instanciada, por que simplesmente não criar somente as subclasses (SavingsAccount e BusinessAccount)?
Resposta
Reuso
: se a superclasse não existisse, teria-se que repetir todos os atributos em todas as subclasses
Polimorfismo
: a superclasse classe genérica nos permite tratar de forma fácil e uniforme todos os tipos de conta, inclusive com polimorfismo se for o caso (como fizemos nos últimos exercícios). Por exemplo, você pode colocar todos tipos de contas em uma mesma coleção.
Operações do tipo: totalizar o saldo de todas as contas e depositar 10,00 em todas as contas ficam mais fácil de implementar usando uma classe genérica
Métodos Abstratos
Se uma classe possuir pelo menos um método abstrato, então esta classe também é abstrata.
Notação UML: itálico
Métodos precisam ser abstratos quando a classe é genérica demais para conter sua implementação.
Por exemplo, as classes Rectangle e Circle são subclasses da classe Shape. A classe Shape é muito genérica para conter implementação de métodos (o método area() não pode ser implementado em Shape, pois a forma não é definida em Shape)
Questionamento:
Por que não tirar o método area() da classe Shape, e implementá-los apenas nas subclasses?
Sem o método area() em Shape, não é possível usar o recurso do Polimorfismo
São métodos que não possuem implementação
public abstract double area();
Uma subclasse de uma classe abstrata é obrigada a implementar os métodos abstratos definidos na superclasse
Ao trabalhar com listas, sempre declará-la com o tipo genérico para permitir o uso de polimorfismo
Durante a execução, é realizado o upcasting
Exceções
Em Java, uma exceção é um objeto herdado da classe:
java.lang.Exception
- o compilador obriga a tratar ou propagar
java.lang.RuntimeException
- o compilador não obriga a tratar ou propagar
Quando lançada, uma exceção é propagada na pilha de chamadas de métodos em execução, até que seja capturada (tratada) ou o programa seja encerrado
O mapeamento da ordem de chamada parte do método no qual a exceção foi lançada até o método que chamou.
Uma exceção é qualquer condição de erro ou comportamento inesperado encontrado por um programa em execução
Hierarquia de exceções do Java
Throwable
Error
OutOfMemoryError
Estourou a memória
O programa não deve tratar esse tipo de erro pois a memória estourou e nada poderá ser feito (o programa encerrará naturalmente)
VirtualMachineError
Erros que não se espera que o programador irá tratar (erros inesperados)
Exception
IOException
Erros de entrada e saída de dados disparam esse tipo de exceção
RuntimeException
IndexOutOfBoundsException
Essa exceção ocorre quando o compilador tenta acessar uma posição do array que não existe.
NullPointerException
Quando tenta-se acessar uma variável que é definida como nula (null)
Especifica exceções que não tem obrigatoriedade de tratamento (o compilador não obriga o programador a tratar)
Erros que ocorrem na execução do programa que se espera que o programa irá tratá-los (são erros tratáveis)
Classe mais genérica que engloba todas as classes de exceções e erros
Amostra das exceções da biblioteca do JDK
Por que exceções?
O modelo de tratamento de exceções permite que erros sejam tratados de forma consistente e flexível, usando boas práticas
Vantagens
Trata de forma organizada (inclusive hierárquica) exceções de tipos diferentes
Uma operação pode gerar vários tipos de exceções; cada exceção tem determinado tipo (classe); pode-se, então, ordenar como as exceções serão tratadas a partir do tipo de cada exceção
A exceção pode carregar dados quaisquer
Como a exceção é uma classe, ela pode ter atributos
Delega a lógica do erro para a classe responsável por conhecer as regras que podem ocasionar o erro
Exemplo: digamos que um saque só possa ser realizado se houver saldo na conta e se a quantidade sacada for menor que um limite de saque. A lógica de testar essas condições e gerar um erro caso elas não sejam satisfeitas não deve estar no programa principal, mas sim na classe Conta. A própria conta que deve conhecer as regras de validação das operações dela.
Estrutura try-catch
Bloco
try
Contém o código que representa a execução normal do trecho de código que
pode
acarretar em uma exceção
Bloco
catch
Contém o código a ser executado caso uma exceção ocorra
Deve ser especificado o tipo da exceção a ser tratada (upcasting é permitido)
Upcasting (pode-se utilizar uma exceção mais genérica que captura qualquer tipo de exceção que é sua subclasse)
Podem existir tantos blocos catch quanto necessário
Captura a exceção, quando ela é lançada, e efetua uma alguma lógica
Sinxtaxe
Pilha de chamada de métodos
A pilha de chamada de métodos consiste na sequência de chamadas de métodos que gerou a exceção.
No topo da pilha está o método no qual a exceção foi lançada; na base da pilha está o primeiro método
O método printStackTrace() imprime a pilha de chamadas de métodos da exceção capturada pelo bloco catch (o método é invocado pela variável declarada no bloco catch)
Por padrão, quando uma exceção não é tratada, o programa é finalizado, e o stackTrace aparece no console.
O rastreamento da pilha ajuda a identificar o que está acontecendo e qual a causa da exceção
Bloco
finally
É um bloco que contém código a ser executado independentemente de ter ocorrido ou não uma exceção.
Exemplo clássico: fechar um arquivo, conexão de banco de dados, ou outro recurso específico ao final do processamento.
Sintaxe
Exceções personalizadas
Sugestão de pacotes de uma aplicação
Padrão MVC
Interface com o usuário
Model
Além do pacote das entidades e suas regras de negócio (transformações entre elas), inclui um pacote com tipos enumerados, um
pacote de exceções
e um pacote de ser serviços
(representa os dados do sistema e as transformações desses dados conforme as regras de negócio - é o sistema em si)
São criadas no pacote model.exceptions do sistema para representar uma exceção específica da aplicação.
Por exemplo, pode-se criar uma exceção DomainExceptions que representa um erro na entidade de domínio do sistema.
Uma classe exceção deve ser acompanhada com um sufixo Exceptions
DomainException
As exceções personalizadas podem ser uma extensão de outras classes de exceções, por exemplo: Exception e RuntimeException (as mais comuns)
Os objetos de classes serializable podem ser convertidas para bytes e, assim, trafegar em redes, serem gravadas em arquivos, etc.
Para ser serializable define-se um padrão de versão
Cria-se um construtor que recebe um String como argumento para que seja possível instanciar a exceção passando uma mensagem, que será armazenada dentro da exceção
Conceitos adicionais
O compilador obriga a propagação e tratamento de exceções da família Exception.
Propaga-se a exceção na assinatura do método
O compilador não obriga a propagação e lançamento de exceções da família RuntimeException
Sendo assim , não é necessário colocar a declaração throws na assinatura do método
Mesmo sendo uma RuntimeException, deve-se capturar a exceção de forma que o programa não "quebre"
A palavra throw é usada para lançar uma exceção / cortar o método. A sintaxe é: throw new typeException();
Programação defensiva (boa prática)
- sempre é bom tratar as exceções no início dos métodos
Cláusula throws: propaga a exceção ao invés de trata-la
A declaração "throws typeException" é colocada após a assinatura do método para avisar ao compilador que o método pode lançar a exceção epecificada e o que ele não a trata, ou seja, ele propaga a exceção
Resumo das vantagens do tratamento de exceções
Lógica delegada
Construtores podem ter tratamento de exceções
É possível capturar inclusive outras exceções de sistema
Possibilidade de auxílio do compilador (Exception)
Código mais simples. Não há aninhamento de condicionais
a qualquer momento que uma exceção for disparada, a execução é interrompida e cai no bloco catch correspondente.