Apostila - Oficina Java Lecom

50

description

Material didático que será utilizado na Oficina de Java do dia 17/03/2014 ao dia 28/03/2014.

Transcript of Apostila - Oficina Java Lecom

Page 1: Apostila - Oficina Java Lecom
Page 2: Apostila - Oficina Java Lecom

INTRODUÇÃO AO JAVA WEB

Realização: Lecom

Informações de contato

André Farina – Lecom

Rua Manoel Bento da Cruz, 11-29, Bauru - SP

Fixo: 14 4009.8900

Internet: www.lecom.com.br

Email: [email protected]

Rafael Fantini da Costa – Lecom / MNIX

Rua Manoel Bento da Cruz, 11-29, Bauru - SP

Fixo: 14 4009.8910 / Cel: 14 8104.9339

Internet: www.mnix.com.br

Email: [email protected]

Licença de uso

Este material está licenciado sob a Licença Creative Commons Atribuição-NãoComercial-SemDerivações 4.0 Internacional.

Para ver uma cópia desta licença, visite http://creativecommons.org/licenses/by-nc-nd/4.0/

Page 3: Apostila - Oficina Java Lecom

CONTEÚDO

1. INTRODUÇÃO .......................................................................................................................... 1

1.1 O que é Java? ........................................................................................................................ 1

1.2 Características da Linguagem ................................................................................................ 1

1.3 Plataforma Java ..................................................................................................................... 1

1.4 Java Development Kit (JDK) ................................................................................................. 2

1.5 A Máquina Virtual Java ......................................................................................................... 2

1.6 Garbage Collection ................................................................................................................ 3

1.7 Convenções de Código .......................................................................................................... 3

2. A LINGUAGEM JAVA ............................................................................................................... 4

2.1 Princípios .............................................................................................................................. 4

2.2 Membros de uma Classe ........................................................................................................ 4

2.3 O Método “main” .................................................................................................................. 5

2.4 Exercícios.............................................................................................................................. 5

2.5 Variáveis e Operadores .......................................................................................................... 5

2.6 Palavras Reservadas .............................................................................................................. 6

2.7 Tipos de Dados ...................................................................................................................... 6

2.7.1 Inteiro ............................................................................................................................. 6

2.7.2 Ponto Flutuante ............................................................................................................... 7

2.7.3 Caractere ........................................................................................................................ 7

2.7.4 Lógico ............................................................................................................................ 7

2.7.5 Tipo de Referência .......................................................................................................... 7

2.8 Escopo de Variáveis ............................................................................................................... 8

2.9 Operadores ............................................................................................................................ 8

2.9.1 Precedência de Operadores ............................................................................................. 9

2.10 Constantes ....................................................................................................................... 9

2.11 Controle de Fluxo ................................................................................................................ 9

2.11.1 if – else ......................................................................................................................... 9

2.11.2 switch ......................................................................................................................... 10

2.11.3 while ........................................................................................................................... 10

2.11.4 for ............................................................................................................................... 10

2.11.5 continue – break .......................................................................................................... 11

2.12 Exercícios .......................................................................................................................... 11

3. MÉTODOS ............................................................................................................................... 12

3.1 Modificadores de Acesso ..................................................................................................... 12

3.2 Parâmetros .......................................................................................................................... 12

3.3 Retorno ............................................................................................................................... 12

4. PROGRAMAÇÃO ORIENTADA A OBJETOS ........................................................................ 13

Page 4: Apostila - Oficina Java Lecom

4.1 O Antecessor ....................................................................................................................... 13

4.2 Conceitos ............................................................................................................................ 13

4.2.1 Abstração ...................................................................................................................... 13

4.2.2 Encapsulamento ............................................................................................................ 14

4.2.3 Classe e Objeto ............................................................................................................. 14

4.2.4 Herança ........................................................................................................................ 16

4.2.5 Polimorfismo ................................................................................................................ 17

4.2.6 Modularidade ............................................................................................................... 18

4.3 Benefícios ........................................................................................................................... 18

4.4 Construtores ........................................................................................................................ 19

4.5 this & super ......................................................................................................................... 19

4.6 Exercícios............................................................................................................................ 20

4.7 Membros Estáticos .............................................................................................................. 20

4.7.1 Ocorrências de membros estáticos ................................................................................ 20

4.8 Exercícios............................................................................................................................ 20

5. CLASSES ABSTRATAS E INTERFACES ............................................................................... 22

5.1 Classes Abstratas ................................................................................................................. 22

5.2 Interfaces ............................................................................................................................. 23

5.3 Exercício ............................................................................................................................. 23

6. EXCEÇÕES .............................................................................................................................. 24

6.1 Definição de Exception ....................................................................................................... 24

6.2 Classes de Exceções ............................................................................................................ 24

6.3 Tratamento de Exceções ...................................................................................................... 24

6.3.1 Capturando Exceções .................................................................................................... 25

6.3.2 Deixando uma Exceção Passar ...................................................................................... 26

6.3.3 Lançando uma Exceção ................................................................................................ 26

6.4 Exercícios............................................................................................................................ 27

7. SERVLETS ............................................................................................................................... 27

7.1 O Protocolo HTTP............................................................................................................... 27

7.2 Common Gateway Interface ................................................................................................ 29

7.3 O que são Servlets? ............................................................................................................. 29

7.4 Funcionamento da Servlet ................................................................................................... 30

7.5 Respostas ............................................................................................................................ 31

7.5.1 Exercícios ......................................................................................................................... 32

7.5.2 Status HTTP ................................................................................................................. 32

7.5.3 Exercícios ..................................................................................................................... 33

7.6 Requisições ......................................................................................................................... 33

7.6.1 Parâmetros da requisição .............................................................................................. 33

7.6.2 Exercícios ..................................................................................................................... 33

Page 5: Apostila - Oficina Java Lecom

7.6.3 Cabeçalhos de Requisição ............................................................................................. 33

8. COOKIES ................................................................................................................................. 35

8.1 Definição ............................................................................................................................. 35

8.2 Estrutura .............................................................................................................................. 35

8.3 Adicionando Cookies........................................................................................................... 35

8.4 Recuperando Cookies .......................................................................................................... 36

8.5 Exercícios............................................................................................................................ 36

9. SESSÕES.................................................................................................................................. 37

9.1 Funcionamento .................................................................................................................... 37

9.2 Exercícios............................................................................................................................ 38

9.3 Validade da Sessão .............................................................................................................. 38

9.4 Exercícios............................................................................................................................ 38

10. CICLO DE VIDA DA SERVLET ............................................................................................ 39

10.1 Inicialização ...................................................................................................................... 39

10.2 Atendendo as Requisições ................................................................................................. 39

10.3 Finalização ........................................................................................................................ 40

10.4 Servlet Context .................................................................................................................. 40

10.5 Exercícios .......................................................................................................................... 41

11. VISÃO GERAL SOBRE JSP .................................................................................................. 42

11.1 O que é uma página JSP? ................................................................................................... 42

11.2 Diretivas ............................................................................................................................ 42

11.2.1 Diretiva page .............................................................................................................. 43

11.2.2 Diretiva include .......................................................................................................... 43

11.3 Expressões ......................................................................................................................... 43

11.4 Exercícios .......................................................................................................................... 43

11.5 Scriptlets ........................................................................................................................... 44

11.6 Objetos Implícitos ............................................................................................................. 44

11.7 Declarações ....................................................................................................................... 44

Page 6: Apostila - Oficina Java Lecom

1

1. INTRODUÇÃO

1.1 O que é Java?

Java é uma linguagem de programação orientada a objetos mantida pela Oracle e originalmente

desenvolvida pela Sun Microsystems. Baseada no C++, o Java foi projetado para ser uma

linguagem portável para todas as plataformas.

A portabilidade é alcançada através do uso de um interpretador que traduz os bytecodes (código

resultante da compilação de um programa Java) em instruções de máquina. Isso dispensa a tarefa de

portar o código para diversas plataformas, uma vez que basta instalar a máquina virtual na

plataforma alvo e o programa Java funcionará como na plataforma original.

1.2 Características da Linguagem

Orientada a objetos: Paradigma de programação mais utilizado na atualidade. Entre os

principais benefícios estão o reuso de código e maior facilidade na manutenção dos sistemas

desenvolvidos;

Simples e robusta: Inspirada no C++, o Java apresenta várias melhorias em relação a

linguagem da qual foi originada. Possui várias características que previnem o programador

de cometer erros comuns no C++, além de estruturas que facilitam a programação, tornando-

a mais produtiva;

Gerenciamento automático de memória: O Java abstrai o conceito de referências, livrando

o programador da (árdua) tarefa de lidar com ponteiros. Além disso, tanto alocação quanto a

liberação de memória são geridas pela máquina virtual Java, liberando o programador da

preocupação de gerenciar a memória em baixo nível. A este mecanismo de liberação de

memória damos o nome de Garbage Collection;

Independência de plataforma: Uma das características mais marcantes do Java é a sua

capacidade de executar programas em plataformas diferentes daquela para a qual o

programa foi inicialmente desenvolvido, como evidenciado pelo mote “write once, run

everywhere”. Isso é possível graças à utilização da máquina virtual que interpreta bytecodes;

Multi-threading: A execução de tarefas paralelas é facilitada pelo uso da biblioteca de

threading e pelos recursos de sincronização.

1.3 Plataforma Java

A tecnologia está separada em três edições com propósitos distintos:

Java Standard Edition (Java SE): ferramentas e frameworks básicos para qualquer

aplicação Java (inclusive para as outras duas plataformas). Suficientemente completo para

desenvolvimento de aplicações com interface gráfica, por exemplo;

Java Enterprise Edition (Java EE): ferramentas e frameworks para desenvolvimento de

aplicações distribuídas e sites voltados para o uso corporativo. Engloba tecnologias como

EJB, JMS, RMI, CORBA, etc;

Java Micro Edition (Java ME): ferramentas e frameworks para desenvolvimento de

aplicações executadas em dispositivos móveis e integrados: celulares, set-top boxes,

impressoras, eletrodomésticos, etc.

Page 7: Apostila - Oficina Java Lecom

2

1.4 Java Development Kit (JDK)

O JDK é o kit de desenvolvimento disponibilizado pela Oracle que permite ao desenvolvedor criar

aplicativos para a plataforma Java. A última versão, 1.7, do JDK, pode ser encontrada em

http://www.oracle.com/technetwork/pt/java/javase/downloads

O JDK compreende:

Java Runtime Environment (JRE) utilizado para executar as aplicações

Ferramenta de desenvolvimento: compilador, empacotador JAR, debugger, utilitários (como

o Java2WSDL), etc

Biblioteca de código (framework) com vários recursos prontos para uso: criação de

aplicativos com recursos visuais, manipulação de estruturas de dados, etc

1.5 A Máquina Virtual Java

O JRE provê os requisitos mínimos para a execução Java: a Java Virtual Machine (JVM),

implementação das bibliotecas e arquivos de suporte. Além de ser o coração da JVM, o JRE é a

pedra angular da filosofia “write once, run everywhere”.

Explicando a imagem anterior:

Na compilação, ao invés do código-fonte ser convertido em código-objeto, as instruções são

geradas em bytecode. O bytecode é genérico e independe de arquitetura ou sistema

operacional;

Page 8: Apostila - Oficina Java Lecom

3

Quando um programa Java é executado, o arquivo bytecode é interpretado pela JVM. Cada

sistema operacional / arquitetura possui sua implementação própria de JVM e a mesma

deverá ser instalada na máquina onde o programa será executado. Os browser, por exemplo,

possui uma implementação própria da JVM, utilizada para execução de Applets (como a

applet de segurança do banco).

1.6 Garbage Collection

Comparativamente, tanto no C quanto no C++, o programa desenvolvido é responsável pela

alocação e liberação de memória, sendo responsável por um grande número de erros: memory leak,

crashes, etc. No Java, ao criar um objeto, a plataforma se encarrega de alocar a quantia certa de

memória e manter o registro de utilização do mesmo. Assim, quando não estiver mais sendo usado

(referenciado), o objeto é “coletado” e a memória ocupada por ele é devolvida ao sistema.

Por ser uma operação custosa, o Garbage Collection é acionado automaticamente apenas quando a

aplicação sendo executada excede um limiar de memória em uso. Essa liberação ocorre numa

thread em background para evitar o travamento do programa.

Embora seja possível invocar o Garbage Collector manualmente utilizando a chamada System.gc(),

destruir objetos diretamente não é permitido. Para forçar a liberação, é preciso eliminar todas as

referências a esse objeto e, em seguida, invocar o System.gc().

1.7 Convenções de Código

Convenções de código são importantes para desenvolvedores por um número de razões:

80% da vida útil de um software é gasto em manutenção;

Dificilmente um software é mantido por toda a sua vida pelo autor original;

Convenções de código aumentam a legibilidade do código, permitindo que os

desenvolvedores entendam o código mais rapidamente e corretamente.

Por ser extenso e fora do escopo deste curso, deixo aqui o link para a página que contém uma

definição extensa e completa das convenções de código utilizadas pelos desenvolvedores Java ao

redor do mundo: http://www.oracle.com/technetwork/java/javase/documentation/codeconvtoc-

136057.html

Page 9: Apostila - Oficina Java Lecom

4

2. A LINGUAGEM JAVA

Como o Java é uma linguagem orientada a objetos, o desenvolvimento de programas é feito por

meio de classes. Uma classe java segue a seguinte sintaxe:

<modificador de acesso> class <nome da classe>

{

<Declaração das Variáveis de Instância (Atributos)>

<Declaração de Métodos>

public static void main( String args[] )

{

// corpo principal do programa

}

}

Por exemplo:

public class Exemplo1 { String mensagem = "Minha mensagem"; public void imprimeTexto(String texto) { // Mostra 'texto' no console System.out.println(texto); } public static void main( String args[] ) { imprimeTexto(mensagem); } }

2.1 Princípios

Assim como toda linguagem, o Java possui suas particularidades:

Identificadores (nomes de variável, classe, método) devem começar sempre por letras ou

underscore ( _ )

Comandos são finalizados com um ponto e vírgula ( ; )

Java é case-sensitive, ou seja, diferencia maiúsculas de minúsculas (diferente de Delphi)

Blocos de código são delimitados por um par de chaves { }

Comentários são precedidos por // ou contidos entre /* */

o // Isto é um comentário

o /* Isto também é */

2.2 Membros de uma Classe

As variáveis de um objeto (instância) são chamadas de campos e, juntamente com os métodos,

compõe os elementos básicos para a construção de uma classe. Como tal, são denominados de

membros da classe.

Os campos são blocos de memória reservados para o armazenamento de informações durante a vida

Page 10: Apostila - Oficina Java Lecom

5

útil de um objeto e, portanto, constituem o estado interno do mesmo. Campos são inicializados na

construção do objeto e ficam disponíveis para utilização por todos os seus métodos. Os métodos,

por sua vez, definem as operações (ações) que podem ser realizadas pela classe.

2.3 O Método “main”

Para executar, toda aplicação Java precisa de um ponto de entrada e este ponto é o método main().

A declaração deve conter a seguinte assinatura para que a aplicação consiga ser iniciada com

sucesso: public static void main( String[] args ) { … }

Quando um programa é executado, o interpretador chamará primeiramente o método main da classe.

É ele quem controla o fluxo de execução do programa e executa qualquer outro método necessário

para a funcionalidade da aplicação.

Nem toda classe terá um método main (normalmente apenas uma classe tem um “main”). Uma

classe que não possui um método main() não pode ser “executada” pois não representa um

programa em Java. Ela será sim, utilizada como classe utilitária para a construção de outras classes

ou mesmo de um programa.

2.4 Exercícios

Utilizando a IDE Eclipse:

1. Crie um Java Project que imprima “Hello World”

2. Crie um programa com uma classe que contenha as quatro operações algébricas básicas

(soma, subtração,...) e outra classe que faça uso das mesmas

2.5 Variáveis e Operadores

Variáveis são denominações dadas a porções de memória que armazenam algum dado. Toda

variável válida tem as seguintes características:

É declarada antes de ser inicializada;

Possui um tipo, um identificador e um escopo;

Podem ser locais, quando declaradas em métodos ou são campos, quando declaradas no

corpo da classe;

Podem ser inicializadas na declaração.

Como Java é uma linguagem fortemente tipada, todas as variáveis devem ser declaradas antes de

serem usadas. O tipo de uma variável determina o tipo de informação que pode ser armazenada nela.

Variáveis em Java podem ser declaradas como campos, no corpo da classe, ou podem ser declaradas

localmente em qualquer parte da implementação de um método. Variáveis também possuem um

escopo, o qual determina onde no programa ela estará visível e poderá ser acessada.

Declaração de variáveis é feita como segue:

tipo identificador [= valor] [, identificador [= valor]];

Exemplos:

String texto = “Exemplos de declaração de variáveis”;

int umNumero, UmNumero;

char letra = ‘i’;

Page 11: Apostila - Oficina Java Lecom

6

2.6 Palavras Reservadas

Alguns identificadores reservados para uso da própria linguagem e recebem o nome de palavras

reservadas. São elas:

abstract continue for new switch

assert default goto package synchronized

boolean do if private this

break double implements protected throw

byte else import public throws

case enum instanceof return transient

catch extends int short try

char final interface static void

class finally long strictfp volatile

const float native super while

2.7 Tipos de Dados

No Java, uma variável pode pertencer a quatro tipos distintos: classes, interfaces, arrays (vetores) e

tipos primitivos. Variáveis com classes, interfaces e arrays contém apenas a referência de memória

(ponteiros) par ao objeto real, enquanto tipos primitivos são armazenados em sua totalidade e

possuem tamanho fixo.

O tamanho e as características de cada tipo primitivo são consistentes entre as plataformas, não

havendo variações entre plataformas diferentes, como ocorre no C e C++. Os tipos primitivos são:

Categoria Tipo Tamanho Valor padrão

Inteiro byte 8 bits 0

Inteiro short 16 bits 0

Inteiro* int 32 bits 0

Inteiro long 64 bits 0L

Ponto flutuante float 32 bits 0.0f

Ponto flutuante* double 64 bits 0.0

Caractere char 16 bits '\u0000'

Lógico boolean 8 bits False

Os tipos marcados com um asterisco ( * ) são o padrão para literais definidos no código.

2.7.1 Inteiro

Tipos inteiros armazenam valores numéricos sem casas decimais. Por padrão, literais inteiros são

do tipo int e podem ser especificados como hexadecimais utilizando o prefixo 0x . Para literais do

tipo long, deve-se utilizar o sufixo L . Ex:

int hexa = 0xfe; // OK long outro = 1L; // OK long combo = 0xfeL; // OK, equivale a 254 int errado = 1L; // Não compila

Page 12: Apostila - Oficina Java Lecom

7

Tipo Variação

byte -128 .. +127

short -32768 .. +32767

int -2147483648 .. +2147483647

long -9 quintilhões .. +9 quintilhões

2.7.2 Ponto Flutuante

Variáveis de ponto flutuante armazenam números com casas decimais (conjunto dos números reais).

Deve ser utilizado o ponto ( . ) como separador de casas decimais e, quando necessário, os números

podem ser escritos em notação exponencial utilizando a caractere E . Para literais do tipo float,

deve-se utilizar o sufixo f . Ex:

double expo = 1.1e4; // OK, equivale a 1.1 * 10^4 = 11000.0 float outro = 1.2f; // OK float errado = 1.2; // Não compila

2.7.3 Caractere

Uma variável char armazena apenas 1 caractere em seu interior – o armazenamento de palavras é

reservado a classe String, que não é um tipo primitivo. Internamente, o Java utiliza o padrão

UNICODE para codificação das variáveis do tipo char.

O literal char é identificado pelo uso de aspas simples ( ' ) ao redor da letra. Alguns exemplos:

char letra = 'a'; char linha = '\n'; // Nova linha char simples = '\''; // Aspas simples

char dupla = '\"'; // Aspas dupla char unicode = '\u007F'; // Valor UNICODE char tabula = '\t'; // Tabulação

2.7.4 Lógico

Uma variável boolean pode armazenar apenas os valores true e false . Não é possível utilizar

valores numéricos para testes lógicos, como ocorre no C / C++.

2.7.5 Tipo de Referência

Tipos se separam em primitivos ou referência. Como vimos, os primitivos armazenam valores

numéricos, caracteres e booleanos. Tipos de referência são classes, interfaces e arrays, e

diferentemente dos tipos primitivos, podem ser definidos pelo desenvolvedor.

Uma grande diferença entre os tipos primitivos e de referência é a alocação: tipos primitivos são

alocados na Stack por possuir tamanho fixo e tipos de referência são alocados na Heap, por não

possuírem tamanho definido. Em função disso, tipos primitivos são sempre passados por valor,

enquanto tipos de referência são passados por referência.

Um exemplo prático da diferença: ao alterar um parâmetro inteiro recebido por uma função, você

estará alterando uma cópia da variável que foi passada como parâmetro. Caso fosse um array, a

mudança seria refletida na variável original.

Page 13: Apostila - Oficina Java Lecom

8

2.8 Escopo de Variáveis

O escopo de uma variável é delimitado pelo bloco { } no qual ela está inserida e isso, por sua vez,

determina o ciclo de vida da variável e quem terá acesso sobre ela.

De forma geral, quando uma variável é declarada no corpo de uma classe, chamamos de campo e

quando é declarada no corpo de um método, chamados de local. Uma variável local só pode ser

acessada pelo método que a definiu, enquanto um campo tem o nível de acesso definido pelo seu

modificador de acesso (public, private, protected).

2.9 Operadores

Operadores são funções especiais e intrínsecos da linguagem. No Java, temos:

Operador Função Exemplo Resultado

= Atribuição int var = 2, var1 = -1;

var = var1 + 12;

var1 = var2 = 50;

+ Adição 2 + 2 4

- Subtração 1 - 2 -1

* Multiplicação 1.1 * salario

/ Divisão 100 / 40

100 / 40.0

2

2.5

% Resto da divisão 100 % 40 20

== Igual x == 10

!= Diferente 1 != 1 false

< Menor 1 < 2 true

> Maior 1 > 2 false

>= Maior ou igual 2 <= 2 true

<= Menor ou igual 2 >= 3 false

instanceof Pertence à classe // Mamifero m;

m instanceof Animal

true

&& AND (0 < 1) && (12 > 6) true

|| OR (0 > 1) || (12 < 6) false

! NOT !(2 == 3) true

+= Soma e atribui x += 20 // x = 10 x é 30

-= Subtrai e atribui x -= 20 // x = 10 x é -10

*= Multiplica e atribui x *= 2 // x = 10 x é 20

%= Resto e atribui x %= 3 // x = 10 x é 1

/= Divide e atribui x /= 3 // x = 10 x é 3

++ Incremento x++ // x = 10 x é 11

-- Decremento x-- // x = 10 x é 9

Page 14: Apostila - Oficina Java Lecom

9

2.9.1 Precedência de Operadores

Entende-se por precedência a ordem na qual os operadores são executados em uma expressão.

Operadores com mesma precedência são executados da esquerda para a direita, de acordo com a

associatividade. Por exemplo:

int n = 21 / 3 * 5; // n = 35 int n = 21 / (3 * 5); // n = 1

A tabela abaixo mostra as precedências entre diferentes operadores.

Precedência Operadores

1 ++ -- !

2 * / %

3 + -

4 < > <= >= instanceof

5 == !=

6 && ||

7 = += -= /= %=

2.10 Constantes

Uma constante pode tanto ser definida como um atributo de classe como uma variável local. Uma

constante uma vez que foi declarada e atribuído um valor para a mesma, não é permitido que outra

atribuição seja efetuada, ocasionando um erro de compilação caso isso ocorra. A atribuição do valor

inicial pode ser feita no momento da declaração, ou posteriormente em outra parte do programa.

Para declarar uma variável do tipo constante, devemos utilizar o modificador final dessa forma:

final <tipo> <identificador> [= valor];

2.11 Controle de Fluxo

2.11.1 if – else

Sintaxe Exemplo

if (expr_boolean) { // Corpo 1 } else { // Corpo 2 }

if (idade < 18) { System.out.println("Entrada bloqueada"); } else { System.out.println("Entrada permitida"); }

Se a expressão booleana for verdadeira, o Bloco 1 é executado, caso contrário, o Bloco 2 é

executado.

Page 15: Apostila - Oficina Java Lecom

10

2.11.2 switch

O switch é normalmente utilizado para determinar o fluxo a partir de uma expressão com vários

resultados possíveis. A limitação é que a expressão avaliada pode ser apenas dos tipos char, byte,

short, int, String e enumeradores.

Sintaxe Exemplo

switch (expr) { case const1: // Corpo 1 break; case const2: // Corpo 2 break; ... [default: // Corpo n] }

switch (nome) { case "Fanta": System.out.println("Pessoa"); break; case "Lecom": System.out.println("Empresa"); break; default: System.out.println("Desconhecido"); }

É importante notar que:

O case deve ser seguido por um literal ou uma constante.

Todo bloco deve ser finalizado por um break , exceto o bloco default.

2.11.3 while

Executa um bloco de comandos sucessivas vezes até que a condição seja falsa. A

expressão de comparação é avaliada antes que o laço seja executado.

Sintaxe Exemplo

while (expr_boolean) { // Corpo }

while (i < n) { pot *= x; i++; }

2.11.4 for

Em sua forma mais utilizada, o loop possui um trecho inicial com inicialização das variáveis,

seguida por uma expressão de comparação e depois a parte final com o incremento ou decremento

das variáveis do laço.

Sintaxe Exemplo

for (init; expr_boolean; pos) { // Corpo }

for (int i = 0; i < array.length; i++) { double elemento = array[i]; }

Logo ao iniciar, o for executa o trecho <init> e, em seguida, testa a condição <expr_boolean>. Caso

seja verdadeira, executa os comandos no bloco e, ao final, executa o comando em <pos> seguido

pelo teste de condição em <expr_boolean>, <bloco>, <pos>, <expr_boolean>,… até que

<expr_boolean> seja falsa. O funcionamento se aproxima ao trecho abaixo:

init; while (expr_boolean) { // Corpo pos; }

Page 16: Apostila - Oficina Java Lecom

11

2.11.5 continue – break

O break, quando executado, faz com que o laço mais interno seja interrompido e força a saída do

mesmo, como se a condição de repetição estivesse falsa. Os usos mais comuns são no switch –

usado para sinalizar o fim de um case – e para abortar um laço diante de algum gatilho interno (ex:

encontrou o elemento desejado num array).

O continue funciona de maneira análoga, porém oposta. Ele força que o laço seja interrompido,

mas força uma nova repetição do laço e, consequentemente, uma nova avaliação da expressão

lógica.

2.12 Exercícios

Faça:

Um programa que calcula o fatorial de um número real

Um programa que ordena os valores de um vetor de entrada

Um programa que calcula o perímetro do círculo de raio igual ao parâmetro de entrada

realizada

Um programa que imprime os números primos contidos entre os valores passados por

parâmetro

Page 17: Apostila - Oficina Java Lecom

12

3. MÉTODOS

Num programa orientado a objetos, o estado interno de um programa é determinado pelos campos e

o comportamento é definido pelos métodos. Em Java, um método equivale a uma função / subrotina

/ procedimento encontrado em outras linguagens de programação. É importante notar que não

existem métodos globais – todo método deve, obrigatoriamente, estar contido em uma classe.

Sintaxe: [modificadores] tipo_retorno identificador([argumentos]) { // Corpo } Exemplo: public static final int soma(int a, int b) { return a + b; }

3.1 Modificadores de Acesso

O acesso a campos e métodos é controlado por meio do uso dos modificadores de acesso. A tabela

abaixo relaciona os modificadores de acesso com a acessibilidade do membro em diferentes pontos

do código.

public protected <nenhum> private

Mundo Sim Não Não Não

Subclasse Sim Sim Não Não

Mesmo pacote Sim Sim Sim Não

Própria classe Sim Sim Sim Sim

Nota: Os modificadores de acesso não podem ser aplicados a variáveis locais.

3.2 Parâmetros

Métodos podem ter zero ou mais parâmetros sendo que, mesmo na ausência de parâmetros, é

obrigatório informar os parênteses vazios tanto na definição quanto na chamada do método. Ao

nome do método acrescido dos parâmetros dá-se o nome de assinatura do método.

Na definição de um método, a declaração de parâmetros assemelha-se à declaração de variáveis

locais, utilizando uma vírgula separadora entre os parâmetros, como no método soma acima.

3.3 Retorno

Métodos podem (ou não) retornar valores. Para sinalizar que existe um retorno, precisamos definir

de antemão o tipo do valor retornado e, no corpo da função, utilizar a palava reservada return

seguida pela expressão a ser retornada (veja o exemplo do método soma acima). Caso não haja um

retorno, é necessário definir o tipo de retorno como sendo void na assinatura do método.

Quando chamado, o return faz com que o método encerre sua execução e volte para a posição

anterior na pilha de instruções. Mesmo funções declaradas com retorno void podem lançar mão do

return; como uma ferramenta de controle de fluxo. No exemplo abaixo, curto-circuitamos a

execução do método quando o saldo for insuficiente.

if (saldo < 0) { return; }

Page 18: Apostila - Oficina Java Lecom

13

4. PROGRAMAÇÃO ORIENTADA A OBJETOS

4.1 O Antecessor

Anteriormente à programação orientada a objetos, o paradigma dominante era a programação

estruturada. Neste paradigma, a abordagem é decompor um programa em subprogramas, realizando

o particionamento até que a unidade de subprograma alcançada tenha coesão e inteligibilidade.

Neste paradigma, o programador é forçado a fixar atenção nos procedimentos (verbos do problema)

ao invés dos dados (substantivos do problema).

Essa disparidade tem como resultado um aumento na complexidade do software, uma vez a

modelagem de um problema pensando em suas ações não é uma tarefa trivial – um paradigma que

busca representar um problema baseando-se nos substantivos seria mais recomendado. A partir

dessa ideia foi desenvolvido o paradigma de Programação orientada a objetos.

4.2 Conceitos

Os conceitos básicos que permeiam a programação orientada a objetos são:

Abstração;

Encapsulamento;

Classe e Objeto;

Herança;

Polimorfismo;

Modularidade;

Mensagens e métodos.

4.2.1 Abstração

Abstração consiste em ignorar aspectos não-relevantes de um domínio, concentrando-se apenas nos

assuntos principais do problema. Assim, abstrair consiste basicamente no processo de retirar do

domínio do problema os detalhes relevantes e representá-los não mais na linguagem de domínio, e

sim na linguagem de solução, como Java, C++, etc.

Page 19: Apostila - Oficina Java Lecom

14

4.2.2 Encapsulamento

A propriedade de implementar dados e

procedimentos correlacionados em uma

mesma entidade recebe o nome de

Encapsulamento. A ideia por trás do

encapsulamento é a de que um sistema

orientado a objetos não deve depender

da implementação interna, e sim da

interface de seus componentes.

Vejamos o exemplo de um circuito

integrado (CI). Pode-se notar o

encapsulamento de vários componentes

como transistores, resistores,

capacitores e outros interligados por um

circuito. O usuário que utiliza um CI

não precisa se preocupar com os

mecanismos internos de um CI – apenas com o comportamento da interface (os pinos).

4.2.3 Classe e Objeto

Um Objeto é um elemento que formaliza o modo pelo qual compreendemos algo no domínio do

problema, refletindo a capacidade do sistema de guardar informações sobre tal elemento, interagir

com ele, ou ambas as coisas.

Uma Classe descreve (define) um conjunto de objetos semelhantes que compartilham a mesma

semântica. Um relacionamento análogo ao de Classe-Objeto seria a relação entre uma Receita de

Bolo e um Bolo criado com a receita: a receita pode ser encarada como uma fórmula para criação

bolos, mas ela, em si, não é um bolo.

Considere um programa para um banco, uma entidade extremamente importante para o nosso

sistema é a conta – é uma boa prática generalizarmos as informações da conta relevantes ao

domínio do problema, juntamente com as funcionalidades (ações) que toda conta deve possuir.

Page 20: Apostila - Oficina Java Lecom

15

Entre os dados de uma conta que são importantes, podemos listar: número da conta, nome do cliente,

saldo, limite, etc. Entre as ações que gostaríamos de atribuir a uma conta, temos: sacar uma

quantidade x, depositar uma quantidade y, imprimir o nome do dono da conta, retornar o saldo

atual, transferir uma quantidade x para uma outra conta y, etc.

Começando pelos conteúdos de uma conta, podemos traduzir as informações acima para uma classe

que ficaria como no trecho abaixo:

class Conta { int numero; String nome; double saldo; double limite; }

Agora temos a definição da estrutura de uma conta. Não é possível, no entanto, obter o saldo da

conta, pois o que temos é apenas a definição de uma conta – não é uma conta propriamente dita.

Para essa tarefa, precisamos construir uma conta, sua definição, assim conseguiremos manipular a

conta como gostaríamos. A esta definição damos o nome de classe e aos produtos da construção de

uma classe damos o nome de objeto.

Para podermos efetivamente usar um objeto criado a partir da classe Conta, além de construir o

objeto, precisamos também de um ponto de início no programa a partir do qual o sistema

operacional passa o controle a nossa aplicação. Vamos criar um arquivo Programa.java para isso:

class Programa { public static void main(String[] args) { Conta minhaConta; minhaConta = new Conta(); } }

Para criar (construir, instanciar) uma Conta, basta usar a palavra reservada new seguida pelo nome

da classe (neste caso, Conta) e parênteses.

Através da variável minhaConta agora podemos acessar o objeto recém-criado para obter/alterar

seu nome, saldo, etc

class Programa { public static void main(String[] args) { Conta minhaConta; minhaConta = new Conta(); minhaConta.nome = "Fanta"; minhaConta.saldo = 1.99; } }

É importante fixar que o ponto em “minhaConta.saldo” foi utilizado para acessar o campo saldo no

objeto minhaConta. Agora, minhaConta pertence ao Fanta, e tem saldo de R$ 1,99.

Dentro da classe, também iremos declarar o que cada conta faz, e como é feito – os

comportamentos que cada classe tem, isto é, o que ela faz. Por exemplo, de que maneira que uma

Conta saca dinheiro?

Especificaremos isso dentro da própria classe Conta, e não em um local desatrelado das

informações da própria Conta. Essas “funções” declaradas no interior de uma classe são chamadas

de método e recebem este nome, pois, determina a maneira de fazer uma operação com um objeto.

Page 21: Apostila - Oficina Java Lecom

16

Como queremos a possibilidade de sacar dinheiro da conta, iremos criar um método que saca uma

quantidade determinada e não retorna informações.

void saca(double quantidade) { double novoSaldo = this.saldo - quantidade; this.saldo = novoSaldo; }

A palavra reservada void indica que o método não retorna nenhum dado àquele que o invocou.

Métodos exigem a colocação de parênteses tanto nas declarações quanto nas chamadas para

delimitar os parâmetros fornecidos aos mesmos.

Neste exemplo, podemos ver que o método “saca” possui um parâmetro (ou argumento) –

quantidade – que indica a quantia a ser sacada. Essa variável é uma variável comum, chamada

também de temporária ou local, pois ao final da execução desse método, ela deixa de existir (escopo

local). Dentro do método, também estamos declarando uma nova variável que assim como o

argumento, vai morrer no fim do método, pois este é seu escopo. Para fins de escopo, o parâmetro é

tratado como uma variável declarada no corpo do método.

O próximo passo é mandar uma mensagem ao objeto “minhaConta” e pedir que ele execute o

método “saca()”. Para denominar essa execução, utilizamos o termo “invocação de método”.

public static void main(String[] args) { Conta minhaConta; minhaConta = new Conta(); minhaConta.nome = "Fanta"; minhaConta.saldo = 1.99; minhaConta.saca(1.00); }

Objetos interagem e se comunicam através de mensagens. As mensagens identificam os métodos a

serem executados e, quando enviadas a um objeto, sinalizam ao objeto que uma invocação de

método deve ser realizada. Para enviar uma mensagem, precisamos de:

Identificar o objeto que receberá a mensagem

Identificar o método que o objeto deverá executar

Passar os argumentos requeridos pelo método

4.2.4 Herança

A herança possibilita a hierarquização de classes, onde uma classe mais especializada (classe filha

ou subclasse) pode herdar as propriedades (métodos e atributos) e semântica de uma classe mais

geral (classe pai ou superclasse).

No exemplo a seguir dizemos que a classe Gerente herda todos os atributos e métodos da classe

mãe Funcionario. Sendo mais preciso, ela também herda os atributos e métodos privados, porém

não consegue acessá-los diretamente.

class Funcionario { String nome; String cpf; double salario; }

Page 22: Apostila - Oficina Java Lecom

17

class Gerente extends Funcionario { int senha; public boolean autentica(int senha) { if (this.senha == senha) { System.out.println("Acesso Permitido!"); return true; } else { System.out.println("Acesso Negado!"); return false; } } }

4.2.5 Polimorfismo

O termos polimorfismo é originário do grego e quer dizer “possuidor de várias formas”. Na

programação, está atrelado à capacidade de um método assumir várias implementações diferentes

sob um mesmo nome e à capacidade do programa em discernir, dentre métodos homônimos, aquele

que deve ser executado. Uma das maiores vantagens do uso de polimorfismo está na criação de

programas mais claros e flexíveis, pois, elimina a necessidade de replicação de métodos ao mesmo

tempo em que permite a extensão dos já existentes, como podemos observar no exemplo:

class EmpregadoDaFaculdade { private String nome; private double salario; double getGastos() { return this.salario; } } class ProfessorDaFaculdade extends EmpregadoDaFaculdade { private int horasDeAula; double getGastos() { return super.getGastos() + this.horasDeAula * 10; } }

Polimorfismo também está relacionado à capacidade de uma variável em receber objetos de classes

distintas. Veja:

public class Aluno extends Pessoa { .... } Pessoa p; p = new Pessoa(); // OK p = new Aluno(); // OK p = new Object(); // ERRO

Page 23: Apostila - Oficina Java Lecom

18

4.2.6 Modularidade

Em programas grandes, ocasionalmente surge o problema: quero escrever uma classe com

determinado nome, mas o mesmo já está em uso. Por exemplo: Você está integrando o código de

um outro sistema ao seu e uma colisão de nomes ocorre em classes com funcionamentos diferentes.

Para resolver este problema, recorremos a estrutura de diretórios para organizar as classes. Por sua

vez, no Java, estes diretórios são mapeados para pacotes, estruturas que agrupam classes com

objetivos comuns. Veja o pacote java.util – ele contém classes utilitárias.

A utilização de pacotes não só permite uma organização maior do código como também facilita o

compartilhamento do mesmo, já que existem modificadores de acesso para o nível de pacote,

permitindo que determinado método / campo / classe seja visível apenas para classes pertencentes

ao mesmo pacote.

4.3 Benefícios

Observe a classe abaixo de uma simples aplicação de Zoológico:

public class Zoo { private Animal[] lista = new Animal[8]; public Animal[] getLista(){ return this.lista; } public void adicionarAnimal( Animal p){ for(int i=0; i<lista.length; i++){ if (lista[i] == null){ lista[i] = p; break; } } }

Utilizamos a classe Animal para lançar mão do polimorfismo (Répteis, Mamíferos, etc). Não fosse

por ela, teríamos um grande prejuízo ao criar estruturas distintas para receber cada um dos tipos de

Animal: uma para Reptil, uma para Mamifero, etc. Como a estrutura dessas classes tem muito em

comum, podemos generalizar a definição em uma superclasse a fim de evitar a replicação de

código e facilitar a manutenção.

Page 24: Apostila - Oficina Java Lecom

19

4.4 Construtores

Construtores são métodos especiais, utilizados para personalizar a construção de objetos e possuem

as seguintes características:

É o primeiro método executado pelo objeto

Deve possuir o mesmo nome da classe

Não tem um tipo de retorno (nem mesmo void)

É invocado através do uso do operador new (instanciação)

Tem modificador de acesso, normalmente public

Toda classe deve possuir ao menos um construtor. Se omitido, o compilador gerará um construtor

público, com corpo vazio e sem parâmetros, como no exemplo abaixo:

public Reptil() { }

Por serem os primeiros métodos a serem executados, construtores são utilizados para iniciar o

estado interno de um objeto, configurando-o de acordo com os parâmetros fornecidos:

public Reptil(String especie) { this.especie = especie; } public Reptil() { this("Desconhecido"); }

Nota: Caso alguma exception lançada no corpo do construtor não seja tratada, a criação do objeto

falhará.

O exemplo acima demonstra que, assim como ocorre com os métodos, podemos ter sobrecargas de

um construtor. Inclusive, podemos fazê-los chamarem uns aos outros utilizando o this(). Aplicamos

este recurso na definição de sobrecargas de um construtor que vão de um nível mais complexo

(vários parâmetros) para um nível mais simples.

4.5 this & super

Todos os métodos de uma instância recebem os argumentos implícitos this e base que nada mais

são do que referências para o próprio objeto e para o objeto pai, respectivamente. Embora possa

parecer pouco útil a primeira vista, essas referências são indispensáveis em muitas das situações

encontradas pelo desenvolvedor Java:

Desambiguação: O construtor da classe Reptil recebe um parâmetro que possui o mesmo

nome de um campo. Neste caso, utilizamos o this.especie para dizer ao compilador que

queremos a variável membro e não a local. O mesmo vale para uma classe que define um

campo com nome idêntico a um campo presente na superclasse e que deseja utilizar a

variável da superclasse ao invés da própria;

Construtor: Caso seja necessário que uma sobrecarga do construtor chame outra, utilizamos

o this() para sinalizar a intenção. Usando a base(), conseguimos chamar um construtor da

superclasse – útil para situações onde a assinatura do construtor de sua classe difere da

superclasse;

Page 25: Apostila - Oficina Java Lecom

20

Polimorfismo: Muitas vezes, ao sobrescrever um método da superclasse, queremos apenas

ampliar o comportamento original em vez de substituí-lo completamente. Em casos como esse, é

comum invocar a versão da superclasse utilizando base.metodo().

4.6 Exercícios

Crie uma classe Poligono com os métodos calculaPerimetro() e calculaArea() e crie as

classes Triangulo e Quadrado sobrescrevendo ambos os métodos.

4.7 Membros Estáticos

Membros estáticos são aqueles que não pertencem a uma instância específica, mas sim à própria

classe. Como tal, membros estáticos são compartilhados entre todas as instâncias da classe e não

precisam de instanciação para serem usados. Vejamos o exemplo:

class Usuario { public static int tentativas; ... public void login() { tentativas++; // Restante } }

Usuario.tentativas = 0; Usuario c1 = new Usuario(); Usuario c2 = new Usuario(); c1.login(); // tentativas = 1 c2.login(); // tentativas = 2 c1.tentativas = 0; c2.login(); // tentativas = 1

Para tornar um membro estático, basta acrescentar o modificador static à declaração do mesmo.

Note que é possível utilizar o membro estático através da própria classe (Usuario.tentativas) ou

através das instâncias (c1.tentativas). Independentemente da abordagem, a variável acessada é a

mesma em ambos os casos.

Embora úteis, membros estáticos exigem alguns cuidados especiais no manuseio. Primeiramente,

não é possível utilizar as referências this e base, uma vez que o membro estático não existe em uma

instância. Pela mesma razão, membros estáticos só podem referenciar outros membros estáticos.

4.7.1 Ocorrências de membros estáticos

Nas bibliotecas do Java encontramos inúmeros casos de atributos e métodos estáticos. Nosso

conhecido método main(), por exemplo, é um método estático, que é chamado pela JVM quando

uma aplicação é executada. A classe Math prove métodos de classe que executam várias funções

matemáticas, como funções trigonométricas e logaritmos. Um exemplo é o método Math.sqrt() que

calcula a raiz quadrada de um número não negativo. A classe System prove variáveis de classe para

representar o estado do sistema inteiro. System.out é uma variável de classe que faz referência ao

objeto PrintStream, que representa o fluxo padrão de saída. O método println() é um método de

instância da classe PrintStream.

4.8 Exercícios

Refaça os exercícios dos itens 2.12 e 4.6 utilizando seus novos conhecimentos

Crie um programa de perguntas e respostas com reprocessamento onde o usuário deverá

responder uma série de perguntas múltipla escolha.

Ao término da jogada, será apresentado o número de acertos realizados na jogada

Page 26: Apostila - Oficina Java Lecom

21

Após mostrar o número de acertos, imprimir também as 3 questões que mais tiveram

respondidas erradas de todos os tempos (não apenas da jogada atual)

Page 27: Apostila - Oficina Java Lecom

22

5. CLASSES ABSTRATAS E INTERFACES

Em grandes sistemas, é comum que a hierarquia de classes torne-se complexa, onde as classes mais

acima (raiz e proximidades) costumar ser bastante gerais, favorecendo o reuso. Passa a ser

interessante a possibilidade de definir protótipos de classes que serão usadas para guiar a criação de

outras classes. Elas implementam ou apenas definem comportamentos que são genéricos o

suficiente para serem comuns a várias outras classes.

5.1 Classes Abstratas

Voltando ao exemplo da classe Animal, podemos notar que a definição de animal é muito ampla e

mesmo que animais possuam características compartilhadas, o modo como de operar de cada tipo

de animal é muito diferente: alguns se locomovem pelo ar, outros por terra, etc. Sendo assim, temos

que a classe Animal pode ser considerada um modelo que não deve ser criado diretamente.

Uma das maneiras de criar tais modelos se dá através do uso de classes abstratas. Uma classe

abstrata é uma classe incompleta que não pode ser construída, necessitando de subclasses que

forneçam os detalhes necessários para que a classe esteja completa. Vejamos um exemplo da

modelagem de animais:

abstract class Animal { String especie; int idade; public abstract void locomover(); public abstract void alimentar(); public void nascer() { ... } public morrer() { ... } }

Foi utilizada a palavra reservada abstract para definir uma classe abstrata e também métodos

abstratos. Se tentarmos instanciar uma classe abstrata receberemos um erro de compilação.

Analogamente, métodos abstratos não possuem corpo, e devem ser obrigatoriamente

implementados nas classes filhas. Uma classe abstrata pode conter:

Métodos e atributos como em classes convencionais. As classes derivadas de uma classe

abstrata herdam da mesma forma os métodos e atributos. Estes métodos podem ser

sobrescritos nas subclasses mas isto não é obrigatório;

Métodos abstratos, que obrigatoriamente devem ser sobrescritos pelas subclasses.

A existência de métodos abstratos ocorre apenas em classes abstratas. Como uma classe abstrata

está num nível muito alto de abstração, muito frequentemente não possui detalhes suficientes para

implementar determinados comportamentos que serão comuns a todas as suas subclasses. Ao invés

disso, elas apenas definem quais serão estes comportamentos obrigatórios através da criação de

métodos abstratos.

Como pode ser visto no exemplo, para definir um método abstrato devemos prover apenas a

assinatura do método, isto é, seu nome, argumentos e tipo de retorno. A implementação (corpo)

deste método ficará a cargo de cada subclasse concreta, que poderá dar a sua versão para ele.

O uso de classes e métodos abstratos é uma forma bastante comum e flexível para criarmos e

utilizarmos bibliotecas orientadas a objetos: por meio de herança associamos nossas classes e

implementamos os métodos abstratos. Por meio do polimorfismo, temos a garantia de que as nossas

implementações serão compatíveis com os locais que fazem uso da classe abstrata.

Page 28: Apostila - Oficina Java Lecom

23

5.2 Interfaces

Suponhamos que exista a necessidade de fazer com que um animal bote ovos. Uma ideia seria

acrescentar o método abstrato “botarOvo()” na classe Animal, mas nada garante que um Animal

tenha a capacidade de botar ovos.

Uma outra solução seria criar outra classe com este método, mas precisamos que nossa classe seja

descendente de Animal, uma vez que o Java não suporta herança múltipla, como no C++. Devemos

recorrer a interfaces para solucionar este problema:

interface Oviparo { public static final int MAX_OVOS = 10; public void botarOvo(); } class Mamifero extends Animal implements Oviparo, Comparable { ... public void botarOvo() { ... } }

Existe muita semelhança entre interfaces e classes abstratas, mas interfaces possuem limitações em

sua constituição: elas podem conter apenas constantes e métodos, sendo que nenhum destes

métodos pode conter implementação (abstratos). Para uma classe implementar uma interface,

devemos usar a palavra reservada implements (diferente de extends), como no exemplo anterior.

É obrigatório que toda classe ao implementar uma interface implemente todos os métodos

especificados pela mesma. Assim, interfaces fornecem a ideia de um “contrato” que qualquer

subclasse deve obedecer. Outra característica importante é que uma classe pode derivar de apenas

uma única outra classe (herança simples), mas pode implementar um número indeterminado de

interfaces.

Uma concepção errônea de quem está se iniciando no Java é que escrever interfaces é perda de

tempo, uma vez que o código escrito “não serve pra nada”, uma vez que a classe implementadora é

obrigada a fornecer uma implementação. Essa é uma maneira errada de pensar – O objetivo do uso

de uma interface é deixar seu código mais flexível, e possibilitar a mudança de implementação sem

maiores traumas (manutenibilidade).

Não é apenas um código de prototipação, tampouco um cabeçalho – Trata-se de uma definição de

um novo tipo e já podemos observar suas vantagens.

5.3 Exercício

Crie um programa de agenda com:

o Uma classe abstrata Pessoa (codigo, nome)

o Uma interface DoadorSangue com o método String getTipoSangue()

o Uma classe Funcionário que estenda Pessoa e implemente DoadorSangue

Inclua o atributo int cracha com set e get

Adicione um atributo String tipoSangue cujo valor deverá se atribuído pelo

construtor

o Uma classe Fornecedor, subclasse de Pessoa, com o campo String ramo

Page 29: Apostila - Oficina Java Lecom

24

6. EXCEÇÕES

Olhando os Javadocs (e recomendo que olhem com frequência), podemos encontrar alguns métodos

que possuem a palavra reservada throws em sua assinatura, como o método File.createNewFile():

http://docs.oracle.com/javase/7/docs/api/java/io/File.html#createNewFile()

A palavra reservada throws indica que este método realiza operações que podem retornar um ou

mais tipos de Exceptions. Mas, afinal, o que são exceptions no Java?

6.1 Definição de Exception

O termo exception é uma abreviação para “evento excepcional” – um evento ocorrido durante a

execução do programa que rompe o fluxo normal de instruções.

Quando um erro ocorre dentro de um método (como tentar acessar uma posição não existente em

um array), o método cria um objeto e entrega-o ao Runtime – a este objeto damos o nome de

exception. Esta exception carrega dentro de si informações relacionadas ao erro, incluindo o tipo

do erro e algumas variáveis indicadoras do estado do programa no momento em que o erro ocorreu.

O ato de criar um objeto da classe Exception é passá-lo ao Runtime é chamado “lançar uma

exception”.

6.2 Classes de Exceções

Tanto as exceções quanto os erros derivam da classe Throwlable:

Erros: São classes filhas da classe Error e indicam que ocorreu um erro irrecuperável,

geralmente fatal para a execução do programa;

Exceções unchecked: Estas exceções são derivadas da classe RuntimeException e

geralmente estão associadas com erros inerentes da execução do programa: acessar posições

inexistentes de um array, chamar um método de um objeto inexistente (null), etc. É possível

optar por não tratar essas exceções;

Exceções checked: Exceções que derivam da classe Exception. O desenvolvedor deve,

obrigatoriamente, capturar exceções deste tipo ou um erro de compilação ocorrerá.

6.3 Tratamento de Exceções

Quando um método lança uma exception, o Runtime encerra a execução do método no ponto onde a

exceção foi lançada e inicia a busca por alguém que consiga tratá-la. A lista de candidatos é

composta pelos métodos que foram chamados até o ponto onde o erro ocorreu. A esta lista de

métodos damos o nome de call stack.

A exception continua rompendo o fluxo dos métodos na call stack até que encontre um bloco de

tratamento de exceptions. A ordem em que a busca ocorre é do método mais próximo da

ocorrência do erro até o método main. Caso o Runtime não encontre nenhum bloco de tratamento

adequado, o programa é terminado.

As exceções existem em duas modalidades: checked e unchecked. A primeira obrigatoriamente

precisa ser envolta em um bloco try-catch, do contrário, um erro de compilação ocorrerá. Como

desenvolvedor Java, ao encontrar um método que lança exceptions, você tem alternativas:

Capturar a exceção e tratá-la

Deixá-la seguir para o método superior na call stack

Page 30: Apostila - Oficina Java Lecom

25

Capturar a exceção e disparar uma exceção diferente

6.3.1 Capturando Exceções

Se um bloco de código possui um ou mais métodos que podem disparar exceções, basta cercá-lo

com um bloco try-catch para permitir que seu código esteja “escutando” possíveis exceções. É

possível (e comum) que exista mais de um bloco de catch para um dado trecho de código,

permitindo que cada catch trate uma exceção de um tipo específico. Opcionalmente, pode-se

incluir um bloco finally após todos os blocos catch, o que sempre é executado ao final, mesmo que

nenhuma exceção ocorra. Um exemplo de exceção aritmética:

try { int erro = 1 / 0; // Divisão por zero } catch (ArithmeticException e) { // Tratamento do erro }

Nota: Se houvesse algum código após a divisão, ele nunca seria executado.

Alterando o exemplo anterior, teremos os seguintes valores impressos no console:

Código Console

try { int erro = 1 / 0; // Divisão por zero } catch (ArithmeticException e) { System.out.println("passo 1"); } finally { System.out.println("passo 2"); }

passo 1 passo 2

Podemos ir além e remover o bloco de catch, deixando apenas o finally. Com isso, o programa

imprimirá “passo 2” no console antes da exception ser lançada para o Runtime e forçar o

encerramento do programa:

passo 2 Exception in thread "main" java.lang.ArithmeticException: / by zero at lecom.curso.Programa.main(Programa.java:7)

Voltando ao método File.createNewFile(), podemos observar que ele existem três possibilidades de

exceção: IOException (checked), IllegalArgumentException (unchecked) e SecurityException

(unchecked). Por ser uma exceção checked, devemos tratar a IOException, ficando a critério do

desenvolvedor tratar as outras duas. Uma possível implementação ficaria como segue:

File f = null; try { f = File.createTempFile("tmp", ".txt"); // … Bloco de operações com 'f' } catch (IOException e1) { // Tratamento de e1 } catch (SecurityException e2) { // Tratamento de e2 } finally { if (f != null) { f.deleteOnExit(); // Limpeza }

Page 31: Apostila - Oficina Java Lecom

26

}

É importante notar que o polimorfismo do Java nos permite construir estruturas elaboradas de

tratamento de exceptions. Complementando o exemplo do File.createTempFile():

try { f = File.createTempFile("tmp", ".txt"); // … Bloco de operações com 'f' } catch (IOException e1) { // Tratamento de e1 } catch (SecurityException e2) { // Tratamento de e2 } catch (Exception e3) { // Tratamento de exceções inesperadas } finally { if (f != null) { f.deleteOnExit(); // Limpeza } }

Veja que acrescentamos um novo bloco de catch com uma Exception e3. O efeito prático dessa

estrutura é que todas as exceções não tratadas pelos blocos de catch anteriores serão direcionadas

para a variável e3. Isso ocorre porque todas as exceções são subclasses de Exception.

6.3.2 Deixando uma Exceção Passar

Existem casos onde não queremos tratar uma exceção do tipo checked. Felizmente, podemos livrar

o método da obrigação de tratar a exceção acrescentando um “throws NomeDaException” à

assinatura do mesmo. Desse modo, estamos delegando a responsabilidade de tratar a Exception para

os métodos acima.

public void meuMetodo() throws IOException { File f = File.createTempFile("tmp", ".txt"); // Restante do método }

6.3.3 Lançando uma Exceção

Como desenvolvedor, seria interessante podermos criar nossas próprias exceções e lançá-las como

resposta a um comportamento inesperado. Felizmente, isso é possível no Java.

Para criar sua própria exceção do tipo checked, basta criar uma classe que seja filha de Exception.

Caso deseje uma exceção unchecked, a classe deve ser filha de RuntimeException.

Lançar uma exceção é igualmente simples: basta utilizarmos o comando throw (não confundir com

o throws que acompanha a assinatura de um método) seguido pelo objeto da exceção:

throw new MinhaException("Erro mortal");

Dica: Podemos encarar o throw como se fosse um return de exceções.

Page 32: Apostila - Oficina Java Lecom

27

6.4 Exercícios

Refaça o exercício do item 5.3 fazendo com que os dados venham de um arquivo e tratando

as Exceptions e criando uma Exception própria que deve ser lançada ao tentar inserir um

contato com nome idêntico a um já existente na agenda.

7. SERVLETS

Hoje é comum vincularmos a ideia de Web com dinamicidade, mudança, mas essa nem sempre foi a

realidade: já houve um tempo onde sites eram apenas sítios de hipertexto estático ligados por meio

de hiperlinks. Tecnologias da atualidade nos permitiram alterar esse panorama e transformar a Web

no que vemos hoje: CGI, PHP, .NET, e, principalmente, Java.

Java ganhou destaque como linguagem para a Web por ter várias características que favoreciam o

desenvolvimento de páginas dinâmicas:

Portabilidade (JVM);

Produtividade (POO, Garbage Collection)

Comunidade ativa e numerosa (Apache Foundation e várias outras instituições open-source)

Escalabilidade (permite arquitetura distribuída)

Eficiência (Servlets persistentes entre requisições)

Recompilação automática (páginas JSP)

7.1 O Protocolo HTTP

Antes de tratarmos de Servlets, é importante entendermos deste protocolo sobre o qual os Servlets

estão fundamentados.

O protocolo HTTP é um protocolo da camada de aplicação utilizado para distribuição de conteúdo

hipermídia de maneira distribuída e colaborativa e é utilizado na navegação de páginas na internet.

Os browsers utilizam o HTTP para obter conteúdo de servidores remotos e mostrá-los localmente.

Os clientes obtêm conteúdo por meio de requisições enviadas ao servidor que, por sua vez, processa

a requisição e devolve uma resposta ao cliente (possivelmente com algum conteúdo hipermídia).

Por ser um protocolo stateless de comunicação cliente-servidor, nenhuma informação é mantida

sobre os clientes ou requisições previamente recebidas.

Requisições HTTP são compostas pelos seguintes elementos:

Um comando, também conhecido como método ou verbo

O endereço de um recurso no servidor, também chamado de caminho ou path

A versão do protocolo HTTP sendo utilizado

Juntando todos esses dados, teremos uma requisição que se assemelha ao exemplo abaixo:

GET / HTTP/1.1

Host: www.google.com.br

Existem diversos métodos HTTP disponíveis para uso nas requisições, mas os mais comuns são:

GET – utilizado para obter algum conteúdo do servidor, como uma página ou imagem

POST – utilizado para enviar dados de formulário ao servidor

Page 33: Apostila - Oficina Java Lecom

28

HEAD – similar ao GET, mas envia apenas os cabeçalhos de resposta

Com a introdução da versão 1.1 do HTTP, novos métodos foram acrescentados:

PUT – armazena a entidade enviada no corpo da requisição

DELETE – remove o recurso especificados

OPTIONS – lista os métodos suportados pelo servidor no endereço fornecidos

Uma requisição também pode conter parâmetros adicionais, chamados cabeçalhos ou

headers. Os headers mais comuns são:

User-Agent – contém informações sobre o cliente que iniciou a requisição (browser, versão,

etc).

o Chrome: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML,

like Gecko) Chrome/33.0.1750.146 Safari/537.36

Accept – indica quais os tipos de recursos aceitos pelo cliente

o Exemplos: */* (tudo), text/html, image/jpeg, etc.

Exemplo atualizado com os cabeçalhos:

Estrutura Exemplo

<Verbo> <Caminho> <Versão HTTP> GET /ExemploServlet/ImprimeIp HTTP/1.1

Host: <Endereço base>

<Nome do cabeçalho 1>: <Valor 1>

...

<Nome do cabeçalho n>: <Valor n>

Host: localhost:8080

User-Agent: curl/7.30.0

Accept: */*

IMPORTANTE: A ordem precisa ser respeitada para que o servidor entenda a requisição

corretamente.

A padronização também está presente na resposta do servidor. Uma resposta bem formada contém:

Versão do protocolo, como na requisição

Código de status indicando sucesso (ou não) ao processar a requisição, acompanhado por

mensagem auxiliar

Cabeçalhos, com informações adicionais com o tipo do conteúdo sendo retornado,

Corpo da resposta, contendo o conteúdo solicitado

Eis um exemplo de reposta completa:

Estrutura Exemplo

<Versão HTTP> <Código> <Mensagem>

<Nome do cabeçalho 1>: <Valor 1>

<Nome do cabeçalho n>: <Valor n>

HTTP/1.1 200 OK

Server: Apache-Coyote/1.1

Cache-Control: no-cache

Pragma: no-cache

Expires: Thu, 01 Jan 1970 00:00:00 GMT

Transfer-Encoding: chunked

Page 34: Apostila - Oficina Java Lecom

29

Date: Sun, 09 Mar 2013 03:43:12 GMT

<Conteúdo> <html> <body>

<h1>Hello World</h1>

</body> </html>

No exemplo anterior, o código de status 200 indica que a requisição do cliente foi bem-sucedida. Os

cabeçalhos trazem informações adicionais sobre o conteúdo retornado, como instruções para que o

browser não faça cache da resposta. O conteúdo retornado é textual e corresponde a uma página

HTML, porém dados binários também podem fazer parte de uma resposta.

A tabela abaixo contempla os códigos mais comuns e seus significados:

Código da resposta Mensagem Significado

200 OK Requisição processada com sucesso

302 Moved Temporarily Conteúdo solicitado está em outar URL

404 Page Not Found Conteúdo solicitado não foi encontrado

500 Internal Server Error Erro inesperado no processamento da requisição

503 Service Unavailable Serviço indisponível no momento

7.2 Common Gateway Interface

O advento do Common Gateway Inteface, mais conhecido por CGI possibilitou o surgimento de

conteúdo dinâmico na Web. Neste modelo, uma aplicação (processo) era executada a cada

requisição HTTP, passando os parâmetros para a aplicação via Variáveis de Ambiente. A aplicação,

por sua vez, retornava o código HTML que deveria ser mostrado para o browser que iniciou a

requisição.

A utilização de Servlets trouxe várias melhorias ao fluxo acima:

Maior desempenho resultante da persistência do Servlet na memória, que não precisa ser

iniciado a cada nova solicitação. Além disso, conexões ociosas ao banco de dados são

mantidas abertas para evitar o overhead de iniciar novas conexões (pool de recursos);

Implantação facilitada pelo uso de uma máquina virtual que abstrai os detalhes do hardware

subjacente aumentando o nível de padronização e portabilidade;

Distribuição facilitada em ambientes heterogêneos em função do uso de uma máquina

virtual.

7.3 O que são Servlets?

Servlets são classes Java usadas para estender as capacidades dos servidores que hospedam

aplicações acessadas por meio de um modelo de requisição-resposta (como o HTTP). Embora

Servlets possam ser usadas para responder qualquer tipo de requisição, o uso mais comum é para

estender a capacidade de aplicações hospedadas por servidores Web. Para aplicações deste tipo, a

tecnologia de Servlets Java oferece classes específicas para uso com HTTP.

Para que um servidor possa executar um Servlet, é preciso que ele implemente um Servlet

Container, também conhecido como Servidor de Aplicações Java. Um Servlet Container é um

Page 35: Apostila - Oficina Java Lecom

30

servidor que suporta as tecnologias JSP, Servlet, JSTL e JSF mas não o Java EE completo. Um dos

mais conhecido é o Apache Tomcat.

No contexto Web, o Servlet é reponsável por receber requisições HTTP feitas ao servidor e, a partir

dos parâmetros recebidos, realizar o processamento relevante para finalmente retornar uma resposta

ao cliente solicitante – seja uma página HTML, uma imagem JPEG, um arquivo JSON, etc.

Os pacotes javax.servlet e javax.servlet.http fornecem as interfaces e classes necessárias para que

possamos iniciar o desenvolvimento de Servlets para Web. Todos os Servlets precisam implementar

a interface Servlet, a qual define os métodos para gestão do ciclo de vida. A classe HttpServlet

oferece métodos como doGet() e doPost() para lidar com requisições HTTP.

7.4 Funcionamento da Servlet

Para ilustrar o modo de operação do Servlet, começaremos com um exemplo simples. O servlet

abaixo faz com que todas as requisições HTTP GET direcionadas para a URL <endereço do

host>/<nome do servlet>/ImprimeIp recebam uma página HTML exibindo o IP do solicitante.

package org.exemplo; import java.io.*; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*;

@WebServlet("/ImprimeIp") public class ImprimeIp extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter();

out.println("<html> <body>"); out.printf("<h1>Seu IP: %s</h1>", request.getRemoteAddr()); out.println("</body> </html>"); out.flush();

}

}

Quando o HttpServlet recebe a requisição, ele verifica o verbo HTTP utilizado (GET, POST,

PUT, ...) e busca o método doXXX() correspondente. Caso exista, o método é chamado com dois

parâmetros:

Um objeto da classe HttpServletRequest, que encapsula a requisição recebida; e

Um objeto da classe HttpServletResponse, que encapsula a resposta do servlet.

Para devolver uma resposta ao cliente que iniciou a requisição, precisamos obter a instância do

PrintWriter associado a resposta. O programa utiliza este PrintWriter para escrever no Stream de

resposta vinculado ao cliente que iniciou a requisição.

A instância do PrintWriter é obtida utilizando o método getWriter() presente no objeto response. A

classe PrintWriter possui métodos que facilitam a escrita de texto num Stream, além de realizar a

bufferização automática do output. No exemplo, utilizamos os métodos println() e printf() para

adicionar Strings o Stream do servlet e, ao final, utilizamos o método flush() para forçar a escrita

dos dados no Stream de saída.

No exemplo, não estamos tratando a IOException lançada pelo getWriter(). No entanto, é

considerada uma boa prática capturar exceções lançadas para a geração de logs no servidor.

try { PrintWriter out = response.getWriter();

out.println("<html> <body>");

Page 36: Apostila - Oficina Java Lecom

31

out.printf("<h1>Seu IP: %s</h1>", request.getRemoteAddr()); out.println("</body> </html>"); out.flush();

} catch (IOException e) { ServletContext context = getServletContext();

context.log("Erro ao obter writer", e); }

7.5 Respostas

Servlets realizam trabalho por trás das cortinas durante o processamento de uma requisição. Embora

não esteja visível no exemplo anterior, o texto que escrevemos no Stream de saída passou por

alguns processamentos até finalmente chegar ao formato final. Antes de chegar ao cliente, a

resposta precisa ser envelopada numa mensagem HTTP válida. O Servlet se encarrega de

acrescentar os cabeçalhos HTTP à nossa resposta. Eis a resposta retornada pelo Servlet escrito no

exemplo anterior:

HTTP/1.1 200 OK

Server: Apache-Coyote/1.1

Transfer-Encoding: chunked

Date: Sun, 09 Mar 2013 03:01:16 GMT

Cabeçalhos: Populados automaticamente

<html> <body>

<h1>Seu IP: 0:0:0:0:0:0:0:1</h1></body> </html>

Corpo: Populado pelo doGet()

Quando aplicações Web precisam de controle sobre os cabeçalhos retornados, é possível utilizar o

método setHeader() do objeto de response para definir ou modificar cabeçalhos HTTP. Um caso

de uso comum é acrescentar cabeçalhos que instruam o browser do cliente a não fazer cache das

respostas. Existem também as variações setDateHeader() e setIntHeader(), usadas para headers com

valores de data e inteiros, respectivamente.

Voltemos ao exemplo Java, agora com setHeader():

response.setHeader("Cache-Control","no-cache"); // HTTP 1.1 response.setHeader("Pragma","no-cache"); // HTTP 1.0 response.setDateHeader ("Expires", 0); // Proxy response.setDateHeader("Last-Modified", System.currentTimeMillis()); PrintWriter out = response.getWriter();

out.println("<html>"); ...

E os cabeçalhos da nova resposta:

HTTP/1.1 200 OK

Server: Apache-Coyote/1.1

Cache-Control: no-cache

Pragma: no-cache

Expires: Thu, 01 Jan 1970 00:00:00 GMT

Last-Modified: Sun, 09 Mar 2013 03:43:12 GMT

Transfer-Encoding: chunked

Date: Sun, 09 Mar 2013 03:43:12 GMT

IMPORTANTE: A alteração dos cabeçalhos deve ser feita ANTES de que qualquer conteúdo de

saída seja escrito. A ordem dos elementos na resposta é crítica para obter o resultado desejado.

Primeiro o status (HTTP/1.1 200 OK), depois os cabeçalhos e por fim o corpo da mensagem. Violar

Page 37: Apostila - Oficina Java Lecom

32

esta regra fará com que seja lançada uma IllegalStateException, consequentemente interrompendo

a geração de uma resposta ao cliente.

O header Content-Type é usado para sinalizar ao cliente o tipo de conteúdo sendo retornado e é útil

para auxiliar os browsers a mostrar o conteúdo de maneira inteligente. Entre os possíveis valores

para esse header, temos: text/html para páginas HTML, image/jpeg para imagens no formato JPEG,

application/octet-stream para dados binários, etc. Devido à grande utilização, foi criado o método

setContentType(), próprio para definir valores ao header Content-Type.

Exemplo:

FileInputStream in = null; try { response.setContentType("image/jpeg"); in = new FileInputStream("imagem.jpg"); // Obtem stream de saída binária do Servlet ServletOutputStream out = response.getOutputStream();

byte[] buffer = new byte[1024]; int bytes = 0; // Copia conteúdo binário para saída while ((bytes = in.read(buffer)) >= 0) { // write() pode lançar IOException out.write(buffer);

}

out.flush();

in.close();

}

catch (IOException io) { // Tratamento de erro }

Nota: O trecho acima pode demorar alguns segundos para finalizar a execução, pois, os dados são

enviados gradualmente para o cliente solicitante à medida que o Servlet escreve na

ServletOutputStream. Caso a conexão seja encerrada (ex: browser foi fechado durante a

execução), o método write() lançará uma IOException.

7.5.1 Exercícios

Crie uma Servlet que retorne uma página HTML com uma mensagem de boas-vindas caso o

IP do cliente seja igual ao IP contido em um arquivo.

o No Eclipse, crie um novo Dynamic Web Project

7.5.2 Status HTTP

Como já vimos, toda resposta a uma requisição HTTP começa com o status da resposta. O status

segue o formato <versão do http> <código da resposta> <mensagem auxiliar> e é responsável

por indicar se a requisição foi bem-sucedida (ou não).

Podemos controlar o status das respostas geradas por nossa aplicação assim como fazemos com os

cabeçalhos – basta utilizarmos o método setStatus() do HttpServletResponse. A fim de melhorar a

legibilidade do código, a classe HttpServletResponse define constantes para cada um dos códigos de

status. Caso o setStatus() não seja utilizado, considera-se que houve sucesso no processamento e o

código 200 é retornado.

Código Constante

200 SC_OK

302 SC_MOVED_TEMPORARILY

Page 38: Apostila - Oficina Java Lecom

33

404 SC_NOT_FOUND

500 SC_INTERNAL_SERVER_ERROR

503 SC_SERVICE_UNAVAILABLE

7.5.3 Exercícios

Utilizando o exercício do item 7.5.1 como base, altere o status da resposta para 404 quando

o arquivo não for encontrado

7.6 Requisições

7.6.1 Parâmetros da requisição

Para um Web efetivamente dinâmica, o cliente precisa de meios de enviar dados para que o servidor

consiga produzir conteúdos variados. Formulários HTML são uma das opções, uma vez que é

possível utilizá-los para enviar dados ao servidor por meio do método HTTP Post. Os dados a

serem enviados são incorporados como parâmetros ao corpo da requisição, podendo ser recuperados

posteriormente no servidor.

Outra forma de enviar parâmetros ao servidor é através da concatenação dos mesmos à URL de uma

requisição GET. Para isso, precisamos acrescentar o caractere interrogação ( ? ) ao final da URL

e, em seguida, acrescentar os parâmetros no formato <nome parâmetro>=<valor parâmetro>

separados entre si por um caractere & . Exemplo:

<URL base>/ExemploServlet/?nome=fanta&idade=26

A API de Servlets disponibiliza diversos métodos para capturar os parâmetros de uma requisição:

String HttpServletRequest.getParameter(String paramName) – Retorna o parâmetro

especificado em paramName, ou null caso o parâmetro não exista

Enumeration HttpServletRequest.getParameterNames() – Retorna um enumerador com

os nomes de todos os parâmetros

String HttpServletRequest.getQueryString() – Retorna a parte da URL de requisição que

vem após o caractere interrogação ( ? ). Ex: nome=fanta&idade=26

7.6.2 Exercícios

Crie uma Servlet que receba os parâmetros altura e peso de uma requisição GET. Responda

com uma página contendo o cálculo do Índice de Massa Corporal (IMC). Caso algum dos

parâmetros não esteja presente, responda com o código de status 500 (ver item 7.5.2)

o Cálculo do IMC: peso / (altura * altura)

Crie uma página HTML com um formulário de login e senha que envie uma requisição

POST para uma Servlet. A Servlet retornará uma página de boas vindas em caso de sucesso.

Caso contrário, responda com o código de status 401 (Forbidden).

7.6.3 Cabeçalhos de Requisição

Vimos que uma mensagem de resposta HTTP é composta pelo status, cabeçalhos e corpo.

Requisições possuem uma estrutura similar, como podemos ver no exemplo abaixo:

Estrutura Exemplo

<Verbo> <URL> <Versão HTTP> GET /ExemploServlet/ImprimeIp HTTP/1.1

Page 39: Apostila - Oficina Java Lecom

34

<Nome do cabeçalho 1>: <Valor 1>

<Nome do cabeçalho 2>: <Valor 2>

<Nome do cabeçalho n>: <Valor n>

User-Agent: curl/7.30.0

Host: localhost:8080

Accept: */*

A classe HttpServletRequest fornece métodos para obter mais informações sobre a requisição:

String HttpServletRequest.getHeader(String name) – Retorna o valor cabeçalho

especificado em name, ou null caso o cabeçalho não exista

long HttpServletRequest.getDateHeader(String name) – Retorna o valor do cabeçalho

como um long que representa uma data. O valor retornado equivale ao número de

milissegundos desde 1o de Janeiro de 1970 ou -1, caso não o cabeçalho não exista. Se o

valor do cabeçalho não for uma data, uma IllegalArgumentException é lançada

int HttpServletRequest.getIntHeader(String name) – Retorna o valor do cabeçalho como

um int. Caso o cabeçalho não exista, retorna 01. Se o valor do cabeçalho não puder ser

convertido para um int, uma NumberFormatException é lançada

Enumeration HttpServletRequest.getHeaderNames() – Retorna um enumerador com os

nomes de todos os cabeçalhos presentes na requisição

Um cabeçalho bastante utilizado é o User-Agent, pois nele estão contidas informações sobre o

cliente que iniciou a requisição (software e versão). Estas informações são úteis para que o Servlet

possa gerar uma versão de conteúdo especialmente adaptada para o cliente, como um site que

oferece uma versão para smartphones e outra para desktops.

Page 40: Apostila - Oficina Java Lecom

35

8. COOKIES

Por ser um protocolo stateless, o HTTP não mantém informações sobre requisições passadas e,

portanto, é incapaz de agrupar requisições de um mesmo cliente. Isso representa um problema para

aplicações que dependam de ações executadas anteriormente para poder operar, como é o caso de

sistemas que possuem algum tipo de autenticação (e-commerce, webmail, etc).

Uma das possibilidades é o uso de Cookies para realizar a persistência de informações (estado)

associadas a um cliente.

8.1 Definição

Cookies são pacotes de dados gerados pelo servidor e enviados ao cliente juntamente com a

resposta da requisição. Esses dados são armazenados pelo browser do usuário, que se encarrega de

enviá-los a cada requisição efetuada após o recebimento do cookie. Com isso, o servidor é capaz de

fazer a distinção entre clientes e recuperar outras informações necessárias para a geração de uma

resposta.

8.2 Estrutura

Além do nome, valor e caminho, cookies possuem os seguintes campos:

Comment: Comentário descrevendo o propósito do cookie

MaxAge: Intervalo de tempo (em segundos) no qual o cookie é considerado válido

Domain: Define todos os servidores abaixo de um mesmo domínio

Path: Define os recursos abaixo do diretório virtual do recurso

8.3 Adicionando Cookies

Para a manipulação de cookies, a API de Servlets disponibiliza a classe javax.servlet.http.Cookie

que encapsula dados e operações de um cookie. Os campos de um cookie podem ser recuperados /

alterados utilizando os vários getters e setters disponíveis na classe.

O primeiro passo para utilizar um cookie é criá-lo passando ao construtor o nome e o valor do

mesmo. O próximo passo é definir os campos (Comment, MaxAge, ...) relevantes ao objeto criado.

Por fim, o cookie precisa ser adicionado ao objeto HttpServletResponse para que seja enviado ao

browser do cliente, como mostra o exemplo:

Cookie cookie = new Cookie("Nome", "Valor"); cookie.setMaxAge(120);

cookie.setComment("Comentario sem acento"); response.addCookie(cookie);

Importante: NÃO utilize caracteres acentuados tanto em cookies quanto em cabeçalhos.

O trecho acima cria um cookie com nome “Nome” e valor “Valor”. Ele será válido por 120

segundos a partir do instante em que for recebido e será excluído pelo browser após expirar. A

resposta é acrescida do cabeçalho abaixo:

Set-Cookie: Nome=Valor; Version=1; Comment="Comentario sem acento"; Max-Age=120;

Expires=Sun, 09-Mar-2013 18:30:04 GMT

Caso o valor fornecido para MaxAge seja negativo, o cookie será mantido até que o browser seja

encerrado. Se o valor for 0, o browser removerá o cookie imediatamente.

Page 41: Apostila - Oficina Java Lecom

36

Assim como ocorre com todo cabeçalho, a adição de cookies na resposta do Servlet deve ocorrer

antes que o conteúdo da resposta comece a ser escrito no Stream de saída.

8.4 Recuperando Cookies

Cookies podem ser extraídos das requisições utilizando o método getCookies() da classe

HttpServletRequest. O método retorna um array de objetos da classe Cookie, ou null caso não

haja nenhum. Não existe um método que recupere um cookie específico a partir do nome, ficando

para o desenvolvedor interar pelo array retornado em busca do cookie desejado.

8.5 Exercícios

Utilizando como base o Servlet de login do item 7.6.2, utilize um cookie para persistir as

informações de login, evitando que o usuário precise digitar suas credenciais novamente

Page 42: Apostila - Oficina Java Lecom

37

9. SESSÕES

Além de cookies, podemos utilizar Sessões, ou Sessions, para persistir informações de estado entre

requisições de um mesmo cliente. A API de Servlets possui um módulo de Gerenciamento de

sessões de usuário onde podemos encontrar a classe HttpSession que possui métodos para

manipulação de sessões.

9.1 Funcionamento

É criado, no primeiro acesso, um identificador de sessão, ao qual é associado um objeto da classe

javax.servlet.http.HttpSession na memória do container. O container, por sua vez, encarrega-se de

carregar este identificador para todas as requisições oriundas daquele usuário. Para isso, utiliza-se 1)

Cookies ou 2) URLs reescritas (informações adicionadas ao caminho) caso a opção (1) esteja

disponível (usuário desabilitou os cookies, por exemplo). Com o identificador em mãos, a API

disponibiliza o objeto HttpSession automaticamente para o Servlet.

O Servlet usa o objeto HttpSession em memória para armazenar informações associadas a um

usuário específico que acessa a aplicação. Essas informações estarão disponíveis em todas as

requisições posteriores a todos os Servlets que compartilham o mesmo contexto. Para obter uma

referência ao objeto da classe HttpSession, um Servlet deve utilizar o método getSession() da classe

HttpServletRequest. Olhando a documentação, é possível verificar que existem duas sobrecargas:

HttpSession getSession(boolean create) – Retorna a HttpSession associada a requisição ou,

se não houver uma sessão e create for true, retorna uma nova sessão, caso contrário, retorna

null

HttpSession getSession() – Equivale a getSession(true)

O trecho a seguir obtém o objeto de sessão, se houver, ou cria um novo, caso ainda não exista:

HttpSession session = request.getSession();

if (session.isNew()) { // Acabou de ser criada getServletContext().log("ID: " + session.getId()); // Inicializa session }

else { // Recupera dados da session }

O método isNew() é utilizado para determinar se o identificador de sessão já foi enviado para o

browser cliente. Caso seja uma sessão recém-criada, nós efetuamos a inicialização da mesma com

dados que gostaríamos de recuperar em requisições futuras (usuário, senha, etc). Além deste método,

a classe HttpSession oferece vários outros métodos. Entre eles estão:

void setAttribute(String attributeName, Object attributeValue)

Object getAttribute(String attributeName)

void removeAttribute(String attributeName)

Enumeration getAttributeNames()

Estes métodos permitem que o desenvolvedor controle os objetos vinculados à sessão do usuário de

maneira similar ao funcionamento de um HashMap:

sessao.setAttribute("Contador", new Integer(contador)); ...

Integer contador = (Integer) sessao.getAttribute("Contador");

Page 43: Apostila - Oficina Java Lecom

38

9.2 Exercícios

Substitua o uso de cookies por sessões no exercício do item 8.5

9.3 Validade da Sessão

É possível definir um tempo máximo de inatividade que, se ultrapassado, faz com que a sessão

expire – um recurso bastante utilizado pelos sites de Internet Banking para aumentar a segurança do

usuário. Para que a sessão expire, basta que o cliente não execute nenhuma requisição durante o

tempo limite. Quando isso ocorre, o usuário precisa de uma nova sessão válida, geralmente obtida

por meio de um novo login.

O desenvolvedor também pode revogar a validade de uma sessão manualmente. É este o caso em

lugares onde o usuário efetua logout. Para controlar a validade da sessão, utilizamos os seguintes

métodos da classe HttpSession:

int getMaxInactiveInterval() – obtêm o intervalo máximo de inatividade em segundos

void setMaxInactiveInterval(int interval) – atribui o intervalo máximo de inatividade

invalidate() – invalida sessão manualmente

9.4 Exercícios

Personalize a página de boas-vindas do exercício no item 9.2 mostrando o nome do usuário

autenticado e acrescente um botão de logout

Page 44: Apostila - Oficina Java Lecom

39

10. CICLO DE VIDA DA SERVLET

O ciclo de vida de um Servlet é composto de 3 fases: inicialização, atendimento de requisições e

finalização.

10.1 Inicialização

Processo onde o Servlet é carregado pelo Servlet Container. O instante em que a inicialização

ocorre depende do campo loadOnStartup na annotation @WebServlet: caso o valor seja um

inteiro positivo, o Servlet é inicializado automaticamente pelo Container quando a aplicação é

iniciada, começando pelos menores valores. Caso contrário, a inicialização ocorre quando é

recebida a primeira requisição a ser mapeada para o Servlet. Exemplo de annotation:

@WebServlet(urlPatterns = "/MeuServlet", loadOnStartup = 1)

Na inicialização, o Servlet Container executa o método init() do Servlet, dando chance ao Servlet

de executar quaisquer passos necessários para sua inicialização, tais como:

Leitura de parâmetros de configuração

Inicialização de variáveis de classe (variáveis estáticas)

Inicialização de conexões ao banco de dados, etc

Ao sobrescrever o init() em seu Servlet, utilize o método getServletConfig() para obter uma

instância da classe ServletConfig, a qual guarda os parâmetros de inicialização do Servlet. Em

seguida, invoque o método getInitParameter() do ServletConfig para obter o parâmetro desejado.

public void init() throws ServletException { super.init(); ServletConfig config = getServletConfig();

String smtp = config.getInitParameter("Email.SMTP"); if (smtp != null) { // Logica de inicialização }

}

Também é possível obter um enumerador contendo o nome de todos os parâmetros do Servlet

Config por meio de uma chamada ao método getInitParameterNames().

O Servlet somente poderá receber requisições após a conclusão de seu processo de inicialização.

Para indicar que houve um problema durante a inicialização, o desenvolvedor deve lançar uma

exception da classe ServletException ou UnavailableExcetion. Nestes casos, o Servlet Container

deixará o Servlet em estado inativo, incapaz de receber requisições.

Observando o construtor da UnavailableException, pode-se notar que uma das sobrecargas possui

um parâmetro do tipo int. Este parâmetro recebe a estimativa, em segundos, de quanto tempo o

Servlet deverá ficar inativo.

10.2 Atendendo as Requisições

Após o término bem-sucedido do método init(), o Servlet é marcado como ativo pelo Servlet

Container e está pronto para receber requisições. Na classe GenericServlet, utilizada para Servlets

genéricos e superclasse da HttpServet, o método service() centraliza o processamento de

requisições.

A cada nova requisição recebida, o Servlet Container faz uma chamada ao método service()

Page 45: Apostila - Oficina Java Lecom

40

passando como parâmetros um objeto que encapsula a requisição feita pelo cliente e outro objeto

que encapsula a resposta que deverá ser encaminhada ao cliente. Felizmente, como vimos no item

7.4, a classe HttpServlet já cuida de encaminhar a requisição para o método relevante: doGet(),

doPost(), etc.

10.3 Finalização

O Servlet é finalizado quando o servidor é finalizado ou quando a aplicação se torna inativa pelo

Servlet Container. A imagem abaixo traz uma ilustração do ciclo de vida nos vários estágios de uma

aplicação.

A finalização de um Servlet deve ser tratada através da implementação do método destroy(). No

instante em que o Servlet inicia a sua finalização, o método destroy() é chamado, permitindo a

execução de rotinas de finalização como: Encerramento de conexões com bancos de dados,

Finalização de threads que tenham sido lançados, etc. Exemplo:

public void destroy() { super.destroy(); // Logica de finalização }

10.4 Servlet Context

O objeto ServletContext contém os atributos e informações sobre o contexto em que o Servlet está

sendo executado e contém métodos úteis para Servlets que desejam se comunicar com o Servlet

Container para, por exemplo, escrever num arquivo de log.

Existe um ServletContext por aplicação web por JVM e, portanto, todos os Servlets de uma mesma

aplicação compartilham o mesmo ServletContext. O contexto é retornado a partir da chamada do

método getServletContext() presente nas Servlets.

Page 46: Apostila - Oficina Java Lecom

41

A classe define métodos para recuperar os parâmetros iniciais do contexto definidos no Deployment

Descriptor: getInitParameterNames() e getInitParameter(). É importante notar que existem

diferenças entre os parâmetros iniciais do contexto e os parâmetros iniciais do Servlet.

O objeto ServletContext também possui métodos que podem ser usados para atribuir e recuperar

atributos compartilhados por todos os Servlets do contexto:

Object getAttribute(String name)

Enumeration getAttributeNames()

void removeAttribute(String name)

void setAttribute(String name, Object value)

O funcionamento destes métodos é análogo aos métodos estudados no item 9.1.

Um recurso bastante utilizado do ServletContext e presente em vários exemplos nesta apostila é o

método log(). Ele permite que você adicione mensagens em um arquivo de log do Servidor de

Aplicações. Você poderá utilizar esse método para depurar seus Servlets, gerar alertas de problemas

na sua execução etc.

No Tomcat, as mensagens geradas por meio do método log() são adicionadas a um arquivo de log

chamado localhost.<aaaa-mm-ddd>.log , onde o bloco < > é substituído pela data da geração do

log.

10.5 Exercícios

Implemente os métodos init() e destroy() da Servlet do exercício no item 9.4:

o O init() deverá ler o arquivo que contém os dados do usuário e senha e inseri-los

num array de usuários para evitar operações de leitura de arquivo em toda requisição.

Além disso, também deverá abrir um arquivo para escrita e armazenar a instância

num campo do Servlet.

o O destroy() deverá fechar o arquivo que foi aberto para escrita durante o init()

Page 47: Apostila - Oficina Java Lecom

42

11. VISÃO GERAL SOBRE JSP

A tecnologia Java Server Pages, também conhecida com JSP, facilita a criação de conteúdo web

que contenha partes estáticas e dinâmicas. O JSP disponibiliza todas as capacidades dinâmicas da

tecnologia de Servlets, mas possui uma abordagem mais natural para a criação de conteúdo estático.

A principal motivação para o uso da tecnologia JSP é evitar a formatação de saídas de texto em

Servlets, concentrando no Servlet a lógica de controle e mantendo a responsabilidade sobre

formatação de conteúdo em outro arquivo. Além de facilitar a manutenção, conseguimos paralelizar

o desenvolvimento em duas frentes.

11.1 O que é uma página JSP?

Uma página JSP é um documento texto que mescla dois tipos de texto: dados estáticos, que podem

ser expressos em qualquer formato baseado em texto (como HTML, SVG, XML, etc) e elementos

JSP, utilizados para a geração de conteúdo dinâmico. As páginas JSP podem ser reconhecidas pela

sua extensão “.jsp” e podem ser encontradas na pasta “WebContent” do projeto Java Web.

Os elementos dinâmicos que disponibilizados pelo JSP são:

Elementos Sintaxe

Comentários <%--.. --%>

Declarações <%! ..%>

Diretivas <%@ include .. %>

<%@ page .. %>

<%@ taglib .. %>

Expressões <%= ..%>

Scriptlets <% ..%>

11.2 Diretivas

Diretivas são elementos que encaminham mensagens para o Container JSP e afetam a compilação

da página JSP. As diretivas não aparecem no XML de saída.

Formato Exemplo

<%@ diretiva nomeAtributo1 = “valorAtributo1” nomeAtributo2 = ”valorAtributo2” ... %>

<%@ page language = "java" contentType = "text/html" pageEncoding = "ISO-8859-1" %>

Nota: Cada diretiva possui seu próprio conjunto de atributos específicos.

Existem três diretivas: page, include e taglib (não contemplada nesta apostila)

page – Define propriedades relacionadas ao formato e linguagem da página atual. Este

elemento precisa ser filho direto do nó raiz. Alguns dos atributos são: language,

contentType, pageEncoding, import, errorPage e isErrorPage

include – Utilizando para inserir o conteúdo de outro arquivo (seja texto estático ou outra

página JSP) no documento atual. Este elemento pode ser colocado em qualquer lugar do

documento e seu possui apenas o atributo file, que deve conter o caminho para o arquivo a

ser incluído. O funcionamento é similar ao da diretiva <include> do C / C++

Page 48: Apostila - Oficina Java Lecom

43

11.2.1 Diretiva page

O atributo info é usado para armazenar texto informativo sobre a página e podemos obter o

conteúdo utilizando o método getServletInfo() do Servlet. Exemplo:

<%@ page info="Autor: Fanta" %>

O atributo contentType informa o tipo de conteúdo gerado pelo documento JSP. O propósito é

permitir que o browser consiga interpretar a página corretamente. Exemplo:

<%@ page contentType="text/html" %>

O atributo pageEncoding informa a codificação do texto utilizado na página. Sem esse atributo, o

conteúdo pode ser exibido incorretamente no browser.

<%@ page pageEncoding="ISO-8859-1" %>

O atributo import funciona de maneira análoga ao import do Java. Todos os pacotes utilizados no

documento JSP devem ser declarados utilizando este atributo. Exemplo:

<%@ page import="java.util.*" %>

O atributo errorPage é usado para indicar a página JSP que deverá ser exibida caso ocorra algum

erro durante o processamento da página que contém este elemento. Para habilitar esse

comportamento, a página que fará o tratamento de erros deverá declarar a diretiva page com o

atributo isErrorPage = true.

11.2.2 Diretiva include

A diretiva include nos permite compartilhar o conteúdo comum a várias páginas JSP, seja ele

dinâmico ou estático, facilitando a manutenção das mesmas. Pode-se, por exemplo, construir novas

páginas JSP que incluem os arquivos cabecalho.jsp e rodape.html. Caso seja necessário mudar o

cabeçalho ou rodapé, não precisaremos alterar todas as páginas, apenas estas duas. Exemplo:

<%@ include file=“cabecalho.jsp” %> <!-- Conteúdo -->

<%@ include file=“rodape.html” %>

11.3 Expressões

Expressões utilizam a sintaxe <%= ..%> para imprimir o resultado de um comando Java durante a

geração do conteúdo. Um trecho de código que imprime o IP do cliente que iniciou a requisição

seria:

<p>O seu endereço IP é "<%= request.getRemoteAddr()%>"<p>

Importante: O resultado da expressão deve ser do tipo String. Algumas alternativas são utilizar o

método toString() do objeto ou o método estático String.format()

11.4 Exercícios

Utilize elementos dinâmicos para melhorar o exercício no item 10.5:

Page 49: Apostila - Oficina Java Lecom

44

o Crie uma página JSP de cabeçalho que imprima o nome do usuário autenticado

o Crie uma página JSP de rodapé que imprima a data atual (dd/mm/aaaa)

o Transfira a geração de HTML para uma página JSP

Dica: Na Servlet de autenticação, utilize o método sendRedirect() para

enviar o usuário para a página .JSP de boas-vindas

11.5 Scriptlets

Scriptlets permitem a inserção de um bloco de código Java diretamente no corpo da página JSP e

possuem o seguinte formato:

Formato Exemplo

<!-- HTML --> <% /* Bloco Java */ %> <!-- HTML -->

<p><% String arg = request.getParameter("r"); if (arg != null && arg.equals("42")) { out.println("Found!"); }

else { out.println("Nothing here"); }

out.flush();

%></p>

11.6 Objetos Implícitos

Para facilitar o trabalho do desenvolvedor, alguns objetos são disponibilizados pelo JSP Container

sem que seja necessária a sua declaração (como o objeto request do exemplo anterior). Os mais

comuns são:

Objeto Classe Função

request HttpServletRequest Encapsula a request enviada à página

response HttpServletResponse Encapsula a response que será devolvida ao cliente

out JspWriter Utilizada para escrever na Stream de saída

session HttpSession Encapsula a sessão associada à request

config ServletConfig ServletConfig associado à página

application ServletContext Contexto da Servlet

11.7 Declarações

O elemento de declaração é usado para definir variáveis e métodos que deverão ser acrescentados à

definição do Servlet JSP. Membros declarados num elemento de declaração ficam disponíveis para

uso nas Scriptlets e Expressões, assim como os objetos implícitos.

Formato Exemplo

<%! /* Declaração */ %> <%!

public void erro(String msg) { getServletContext().log("ERRO: " + msg); }

%>

...

<%

Page 50: Apostila - Oficina Java Lecom

45

if (request.getParameter("url") == null) { erro("Parâmetro 'url' não encontrado"); }

%>

As declarações também podem ser usadas para a declaração dos métodos public void jspInit() e

public void jspDestroy(), usados para inicializar a página JSP (ler dados de configuração, por

exemplo) e liberar recursos, respectivamente.