Você está na página 1de 431

Módulo 1

Introdução à Programação I

Lição 1
Introdução à Programação de Computadores

Versão 1.01 - Jan/2008


JEDITM

Autor Necessidades para os Exercícios


Florence Tiu Balagtas Sistemas Operacionais Suportados
NetBeans IDE 5.5 para os seguintes sistemas operacionais:
• Microsoft Windows XP Profissional SP2 ou superior
• Mac OS X 10.4.5 ou superior
Equipe • Red Hat Fedora Core 3
Joyce Avestro • Solaris™ 10 Operating System (SPARC® e x86/x64 Platform Edition)
Florence Balagtas NetBeans Enterprise Pack, poderá ser executado nas seguintes plataformas:
• Microsoft Windows 2000 Profissional SP4
Rommel Feria • Solaris™ 8 OS (SPARC e x86/x64 Platform Edition) e Solaris 9 OS (SPARC e
Reginald Hutcherson x86/x64 Platform Edition)
Rebecca Ong • Várias outras distribuições Linux
John Paul Petines
Configuração Mínima de Hardware
Sang Shin
Nota: IDE NetBeans com resolução de tela em 1024x768 pixel
Raghavan Srinivas
Sistema Operacional Processador Memória HD Livre
Matthew Thompson
Microsoft Windows 500 MHz Intel Pentium III 512 MB 850 MB
workstation ou equivalente
Linux 500 MHz Intel Pentium III 512 MB 450 MB
workstation ou equivalente
Solaris OS (SPARC) UltraSPARC II 450 MHz 512 MB 450 MB
Solaris OS (x86/x64 AMD Opteron 100 Série 1.8 GHz 512 MB 450 MB
Platform Edition)
Mac OS X PowerPC G4 512 MB 450 MB

Configuração Recomendada de Hardware

Sistema Operacional Processador Memória HD Livre


Microsoft Windows 1.4 GHz Intel Pentium III 1 GB 1 GB
workstation ou equivalente
Linux 1.4 GHz Intel Pentium III 1 GB 850 MB
workstation ou equivalente
Solaris OS (SPARC) UltraSPARC IIIi 1 GHz 1 GB 850 MB
Solaris OS (x86/x64 AMD Opteron 100 Series 1.8 GHz 1 GB 850 MB
Platform Edition)
Mac OS X PowerPC G5 1 GB 850 MB

Requerimentos de Software
NetBeans Enterprise Pack 5.5 executando sobre Java 2 Platform Standard Edition
Development Kit 5.0 ou superior (JDK 5.0, versão 1.5.0_01 ou superior), contemplando
a Java Runtime Environment, ferramentas de desenvolvimento para compilar, depurar,
e executar aplicações escritas em linguagem Java. Sun Java System Application Server
Platform Edition 9.
• Para Solaris, Windows, e Linux, os arquivos da JDK podem ser obtidos para sua
plataforma em http://java.sun.com/j2se/1.5.0/download.html
• Para Mac OS X, Java 2 Plataform Standard Edition (J2SE) 5.0 Release 4, pode ser
obtida diretamente da Apple's Developer Connection, no endereço:
http://developer.apple.com/java (é necessário registrar o download da JDK).

Para mais informações: http://www.netbeans.org/community/releases/55/relnotes.html

Introdução à Programação I 2
JEDITM

Colaboradores que auxiliaram no processo de tradução e revisão


Alexandre Mori Hugo Leonardo Malheiros Ferreira Mauro Regis de Sousa Lima
Alexis da Rocha Silva Ivan Nascimento Fonseca Namor de Sá e Silva
Aline Sabbatini da Silva Alves Jacqueline Susann Barbosa Néres Chaves Rebouças
Allan Wojcik da Silva Jader de Carvalho Belarmino Nolyanne Peixoto Brasil Vieira
André Luiz Moreira João Aurélio Telles da Rocha Paulo Afonso Corrêa
Andro Márcio Correa Louredo João Paulo Cirino Silva de Novais Paulo José Lemos Costa
Antoniele de Assis Lima João Vianney Barrozo Costa Paulo Oliveira Sampaio Reis
Antonio Jose R. Alves Ramos José Augusto Martins Nieviadonski Pedro Antonio Pereira Miranda
Aurélio Soares Neto José Leonardo Borges de Melo Pedro Henrique Pereira de Andrade
Bruno da Silva Bonfim José Ricardo Carneiro Renato Alves Félix
Bruno dos Santos Miranda Kleberth Bezerra G. dos Santos Renato Barbosa da Silva
Bruno Ferreira Rodrigues Lafaiete de Sá Guimarães Reyderson Magela dos Reis
Carlos Alberto Vitorino de Almeida Leandro Silva de Morais Ricardo Ferreira Rodrigues
Carlos Alexandre de Sene Leonardo Leopoldo do Nascimento Ricardo Ulrich Bomfim
Carlos André Noronha de Sousa Leonardo Pereira dos Santos Robson de Oliveira Cunha
Carlos Eduardo Veras Neves Leonardo Rangel de Melo Filardi Rodrigo Pereira Machado
Cleber Ferreira de Sousa Lucas Mauricio Castro e Martins Rodrigo Rosa Miranda Corrêa
Cleyton Artur Soares Urani Luciana Rocha de Oliveira Rodrigo Vaez
Cristiano Borges Ferreira Luís Carlos André Ronie Dotzlaw
Cristiano de Siqueira Pires Luís Octávio Jorge V. Lima Rosely Moreira de Jesus
Derlon Vandri Aliendres Luiz Fernandes de Oliveira Junior Seire Pareja
Fabiano Eduardo de Oliveira Luiz Victor de Andrade Lima Sergio Pomerancblum
Fábio Bombonato Manoel Cotts de Queiroz Silvio Sznifer
Fernando Antonio Mota Trinta Marcello Sandi Pinheiro Suzana da Costa Oliveira
Flávio Alves Gomes Marcelo Ortolan Pazzetto Tásio Vasconcelos da Silveira
Francisco das Chagas Marco Aurélio Martins Bessa Thiago Magela Rodrigues Dias
Francisco Marcio da Silva Marcos Vinicius de Toledo Tiago Gimenez Ribeiro
Gilson Moreno Costa Maria Carolina Ferreira da Silva Vanderlei Carvalho Rodrigues Pinto
Givailson de Souza Neves Massimiliano Giroldi Vanessa dos Santos Almeida
Gustavo Henrique Castellano Mauricio Azevedo Gamarra Vastí Mendes da Silva Rocha
Hebert Julio Gonçalves de Paula Mauricio da Silva Marinho Wagner Eliezer Roncoletta
Heraldo Conceição Domingues Mauro Cardoso Mortoni

Auxiliadores especiais
Revisão Geral do texto para os seguintes Países:
• Brasil – Tiago Flach
• Guiné Bissau – Alfredo Cá, Bunene Sisse e Buon Olossato Quebi – ONG Asas de Socorro

Coordenação do DFJUG
• Daniel deOliveira – JUGLeader responsável pelos acordos de parcerias
• Luci Campos - Idealizadora do DFJUG responsável pelo apoio social
• Fernando Anselmo - Coordenador responsável pelo processo de tradução e revisão,
disponibilização dos materiais e inserção de novos módulos
• Regina Mariani - Coordenadora responsável pela parte jurídica
• Rodrigo Nunes - Coordenador responsável pela parte multimídia
• Sérgio Gomes Veloso - Coordenador responsável pelo ambiente JEDITM (Moodle)

Agradecimento Especial
John Paul Petines – Criador da Iniciativa JEDITM
Rommel Feria – Criador da Iniciativa JEDITM

Introdução à Programação I 3
JEDITM

1. Objetivos
Nesta seção, vamos discutir os componentes básicos de um computador, tanto em relação a
hardware como a software. Também veremos uma pequena introdução sobre linguagens de
programação e sobre o ciclo de vida do desenvolvimento. Por fim, mostraremos os diferentes
sistemas numéricos e as conversões entre eles.
Ao final desta lição, o estudante será capaz de:
• Identificar os diferentes componentes de um computador.
• Conhecer as linguagens de programação e suas categorias.
• Entender o ciclo de vida de desenvolvimento de programas e aplicá-lo na solução de
problemas.
• Conhecer os diferentes sistemas numéricos e as conversões entre eles.

Introdução à Programação I 4
JEDITM

2. Introdução
O computador é uma máquina que realiza uma variedade de tarefas de acordo com instruções
específicas. É uma máquina de processamento de dados, que recebe dados através de um
dispositivo de entrada e o processador os manipula de acordo com um programa.
O computador tem dois componentes principais. O primeiro é o Hardware que é a parte palpável
(que se pode tocar) do computador. Ele é composto de partes eletrônicas e mecânicas.
O segundo componente principal é o Software que é a parte impalpável (não se pode tocar) do
computador. Ele é composto de dados e dos programas de computador.

Introdução à Programação I 5
JEDITM

3. Componentes Básicos de um Computador


3.1. Hardware

3.1.1. Unidade Central de Processamento (CPU - Central Processing Unit)


O processador é o “cérebro” do computador. Ele possui milhões de partes elétricas muito
pequenas. Ele faz as operações fundamentais dentro do sistema. Alguns exemplos de
processadores são o Pentium, Athlon e SPARC.

Figura 1: Processador de um PC

3.1.2. Memória
A memória, onde se encontram os dados e as instruções que a CPU precisa para realizar suas
tarefas, dividida em diversos locais de armazenamento que possuem seus respectivos endereços
lógicos. A CPU acessa a memória pelo uso destes endereços.
1. Memória Principal
A memória principal, às vezes, chamada de RAM (Random Access Memory ou Memória de Acesso
Randômico) está fortemente ligada ao processador. Ela é utilizada para armazenar programas e
dados, com os quais o processador está trabalhando no momento e não é utilizada para
armazenamento de longo prazo, por este motivo seu armazenamento é considerado volátil. Isto
significa que assim que o computador é desligado, toda a informação armazenada na memória
principal será perdida.

Figura 2: Pente de memória

2. A Memória Secundária
A memória secundária está ligada à memória principal. Ela é usada para armazenar programas e
dados para uso de longo prazo. Exemplos de memória secundária são discos rígidos e cd-rom.

Introdução à Programação I 6
JEDITM

Figura 3: Interior de um Disco rígido do computador

A memória secundária é considerada um tipo de armazenamento não-volátil. Isto significa que


as informações nela armazenadas não serão perdidas após o computador ser desligado.

Memória Principal Memória Secundária Propriedade


Rápida Lenta Velocidade
Cara Barata Preço
Baixa Alta Capacidade
Sim Não Volátil
Tabela 1: Comparação entre a memória principal e a memória secundária

3.1.3. Dispositivos de Entrada e Saída


Os dispositivos de entrada e saída permitem que o computador interaja com o mundo exterior
pela movimentação de dados para dentro e para fora do sistema.
Exemplos de dispositivos de entradas são teclados, mouses, microfones, etc. Exemplos de
dispositivos de saída são monitores, impressoras, alto-falantes, etc.

3.2. Software
O software é um programa que o computador usa para funcionar. Ele é armazenado em algum
dispositivo de hardware como um disco rígido, mas é em si mesmo intangível. Os dados que o
computador usa podem ser qualquer coisa que o programa precise. Os programas agem como
instruções para o processador.
Alguns tipos de programas de computador:
1. Programas de Sistemas
Programas necessários para que o hardware e o software funcionem juntos corretamente.
Exemplos:
• Sistemas Operacionais como Linux, Windows, Unix, Solaris, MacOS
2. Aplicativos
Programas que as pessoas usam para realizar determinado trabalho.
Exemplos:
• Processadores de Textos
• Jogos
• Planilhas Eletrônicas
3. Compiladores
O computador entende apenas uma linguagem: linguagem de máquina. Linguagem de máquina

Introdução à Programação I 7
JEDITM

está na forma de zeros e uns. Já que é totalmente impraticável para as pessoas criarem
programas usando zeros e uns, é preciso haver uma maneira de traduzir ou converter a
linguagem que entendemos em linguagem de máquina, para isto, existem os compiladores.

Introdução à Programação I 8
JEDITM

4. Visão Geral sobre Linguagens de Programação


4.1. O que é uma linguagem de programação?
Uma linguagem de programação é uma técnica de comunicação padronizada para se expressar
instruções para um computador. Assim como os idiomas utilizados pelos seres humanos, cada
linguagem tem sua própria sintaxe e gramática.
Linguagens de programação possibilitam ao programador especificar precisamente com quais
dados o computador irá interagir, como estes dados serão gravados/transmitidos, e precisamente
quais ações serão tomadas de acordo com as circunstâncias.
Existem diferentes tipos de linguagens de programação que podem ser usadas para a criação de
programas, mas, independente da linguagem utilizada, essas instruções são traduzidas em
linguagem de máquina, e podem ser entendidas por computadores.

4.2. Categorias das Linguagens de Programação


1. Linguagens de Programação de Alto Nível
Uma linguagem de programação de alto nível é uma linguagem de programação que é mais
amigável para o usuário, em alguns casos independente de plataforma, e que abstrai operações
de baixo nível como acesso a memória. Uma instrução de programação pode ser traduzida em
uma ou várias instruções de máquina por um compilador.
Exemplos são Java, C, C++, Basic, Fortran
2. Linguagens de Montagem de Baixo Nível
Linguagens de montagem são similares às linguagens de máquina, são mais simples de
programar pois possuem poucos comandos e permitem ao programador substituir nomes por
números. Linguagens de montagem estão disponíveis em cada família de CPU, e cada instrução
de montagem é traduzida em uma instrução de máquina por um programa montador.
Nota: Os termos "alto nível" e "baixo nível" são relativos. Originalmente, linguagens de
montagem eram consideradas de baixo nível e COBOL, C, etc. eram consideradas de alto nível.
Muitos programadores, hoje em dia, podem se referir a estas últimas como linguagens de baixo
nível.

Introdução à Programação I 9
JEDITM

5. O Ciclo de Vida de Desenvolvimento de Programas


Programadores não sentam e simplesmente começam a escrever código de uma vez, quando
estão tentando fazer um programa de computador. Ao invés disto, eles seguem um planejamento
organizado ou metodologia, que quebra o processo em uma série de tarefas.
Este é o ciclo de vida quando se tenta resolver um problema no computador:

Figura 4: Ciclo de vida para a resolução de problemas

Para entendermos o funcionamento deste ciclo na solução de problemas no computador, vamos


definir um problema exemplo que iremos resolver passo a passo enquanto discutimos as
metodologias para resolução de problemas em detalhe.

5.1. Definir o problema


Geralmente, um programador recebe uma tarefa na forma de um problema. Antes do programa
poder ser projetado para resolver um problema em particular, o problema deve, em primeiro
lugar, ser bem e claramente definido em termos dos seus requisitos de entrada e saída.
Um problema claramente definido já é metade da solução. Programação de computadores requer
que o problema seja primeiro definido antes de se pensar em criar a solução.
Vamos definir o problema exemplo:
“Crie um programa que irá determinar o número de vezes que um nome aparece em uma lista.”

5.2. Analisar o problema


Depois do problema ter sido definido adequadamente, o mais simples e também o mais eficiente
e efetivo meio de se resolver será visualizá-lo através de uma representação clara e objetiva.
Geralmente, este passo se dá com a quebra do problema em sub-problemas menores e mais
simples.
Problema Exemplo:
Determinar o número de vezes que um nome aparece em uma lista
Entrada para o programa:
Lista de nomes, nome que se deseja procurar
Saída do programa:
O número de vezes que o nome aparece em uma lista

5.3. Projetar e representar o algoritmo


Logo que o problema estiver sido claramente definido, podemos nos concentrar em desenvolver a
solução. Na programação de computadores, geralmente é requirido que expressemos a solução
passo a passo.

Introdução à Programação I 10
JEDITM

Um Algoritmo é uma especificação clara e não ambígua dos passos necessários para se resolver o
problema. Ele pode ser expresso tanto em linguagem humana (Inglês, Tagalog e Português),
como através de representação gráfica como fluxograma ou através de pseudocódigo, que é um
meio termo entre a linguagem humana e a linguagem de programação.
Dado o problema definido na seção anterior, como podemos expressar a solução de uma maneira
simples e que possa ser entendida?
Expressando a solução através da linguagem humana:
1. Obter a lista de nomes, vamos chamá-la de NomeLista
2. Obter o nome a ser procurado, vamos chamá-lo de NomeChave
3. Criar um contador, vamos chamá-lo de Conta
4. Pegar cada nome em NomeLista
5. Se NomeChave for igual ao nome selecionado em NomeLista
6. Adicionar 1 a Conta
7. Repetir 4 até que todos os nomes já tiverem sido comparados
8. Exibir o valor de Conta

Expressando a solução através de um fluxograma:

Figura 5: Exemplo de um fluxograma

Expressando a solução através de pseudocódigo:

Introdução à Programação I 11
JEDITM

Fazer NomeLista = Lista de Nomes


Fazer NomeChave = o nome a ser procurado
Fazer conta = 0
Para cada nome em NomeLista fazer
Se nome é igual a NomeChave
Fazer Conta = Conta + 1
Mostrar Conta
Figure 6: Exemplo de pseudocódigo

5.3.1. Símbolos do Fluxograma e o seu significado


Um fluxograma é uma ferramenta de projeto usada para representar graficamente a lógica de
uma solução. Os fluxogramas, tipicamente, não mostram comandos de linguagem de
programação. Ao invés disto, eles mostram o conceito em Português ou em notação matemática.
Aqui estão algumas dicas dos símbolos mais usados para a criação de fluxogramas. Pode-se
utilizar quaisquer símbolos quando criar os seus fluxogramas, desde que use-os de maneira
consistente.

Símbolo Nome Significado


Representa o processo de se executar uma
operação definida ou grupo de operações que
resultam em mudança de valor, forma ou
Símbolo de Processo
localização da informação. Também funciona
como símbolo padrão quando nenhum outro
símbolo estiver disponível.
Representa a função de E/S que faz com que os
Símbolo de dados fiquem disponíveis para processamento
Entrada/Saída (E/S) (entrada) ou para a exibição (saída) das
informações processadas.

Representa a seqüência de informações


disponíveis e operações executáveis. As linhas
Símbolo de Linha conectam outros símbolos, e as setas são
obrigatórias somente em fluxos com orientação
da direita para esquerda e de baixo para cima.
Representa a adição de informação descritiva,
comentários, ou notas explicativas para
esclarecimentos. A linha vertical e a linha
Símbolo de Anotação
pontilhada podem ser colocadas à esquerda,
como mostrado, ou à direita.

Representa a decisão que determina qual das


alternativas será seguida.
Símbolo de Decisão

Representa o começo, o final, um ponto de


interrupção ou um atraso em um programa.
Símbolo Terminal

Representa qualquer entrada, ou saída, a outra


parte do fluxograma. Também serve como um
Símbolo Conector
conector fora de página.

Introdução à Programação I 12
JEDITM

Símbolo Nome Significado


Representa um processo nomeado consistindo de
Símbolo de Processo uma ou mais operações ou passos de programa
Pré-definido especificados em algum outro lugar.

Tabela 2: Símbolos do Fluxograma

5.4. Codificar e Depurar


Depois de construir o algoritmo, será possível criar o código fonte. Usando o algoritmo como
base, o código fonte pode ser escrito usando a linguagem de programação escolhida.
Na maioria das vezes, depois do programador ter escrito o programa, este poderá não estar
funcionando 100% no início. O programador deve corrigir o programa no caso de erros (também
conhecidos como Erros de Compilação) que ocorrem no programa. Este processo é chamado de
depuração de erros (debug).
Existem dois tipos de erros que os programadores poderão encontrar. O primeiro é o erro em
tempo de compilação e o outro é o erro em tempo de execução.
Erro em tempo de compilação ocorre se há um erro de sintaxe no código. O compilador irá
detectar o erro e o programa nem mesmo compilará. Neste ponto, o programador estará inapto a
criar um executável que possa ser executado pelo usuário até que o erro seja corrigido.
Esquecer um ponto-e-vírgula no final de uma instrução ou escrever um comando erroneamente,
por exemplo, são erros em tempo de compilação. É algo que o compilador pode detectar como
sendo um erro.
Compiladores não são perfeitos e então não podem detectar todos os erros em tempo de
compilação. Isso é especialmente verdadeiro para erros de lógica como as repetições (loops)
infinitos. Este tipo de erro é chamado de erro em tempo de execução.
Por exemplo, a sintaxe do código pode estar correta. Entretanto, ao seguir a lógica do código, o
mesmo pedaço de instrução é executado várias e várias vezes, infinitamente. Neste caso, os
compiladores não são espertos o suficiente para pegar todos estes tipos de erro em tempo de
compilação, conseqüentemente, o programa compila corretamente em um arquivo executável.
Entretanto, quando o usuário final roda o programa, o programa (ou mesmo o computador
inteiro) congela devido a uma repetição infinita. Outros tipos de erro em tempo de execução são:
um valor errado a ser computado, uma instrução errada a ser executada, etc.

Introdução à Programação I 13
JEDITM

6. Sistemas Numéricos e Conversões


Números podem ser representados de várias maneiras. A representação depende do que é
chamado de BASE. As que seguem são quatro das representações mais comuns.

6.1. Decimal
Normalmente representamos os números na forma decimal. Números na forma decimal estão na
base 10. Isto significa que os únicos dígitos que aparecem são 0-9. Aqui estão alguns exemplos
de números escritos na forma decimal:
12610 (normalmente escrito somente como 126)
1110 (normalmente escrito somente como 11)

6.2. Binário
Números na forma binária estão na base 2. Isto significa que os únicos dígitos aceitos são 0 e 1.
Precisamos escrever a subscrição 2 para indicar que o número é um número binário. Aqui estão
alguns exemplos de números escritos na forma binária:
11111102
10112

6.3. Octal
Números na forma octal estão na base 8. Isto significa que os únicos dígitos aceitos são 0-7.
Precisamos escrever a subscrição 8 para indicar que o número é um número octal. Aqui estão
alguns exemplos de números escritos na forma octal:
1768
138

6.4. Hexadecimal
Números na forma hexadecimal estão na base 16. Isto significa que os únicos dígitos aceitos são
0-9 e as letras A-F (ou a-f, minúsculas ou maiúsculas não importam). Precisamos escrever a
subscrição 16 para indicar que o número é um número hexadecimal. Aqui estão alguns exemplos
de números escritos na forma hexadecimal:
7E16
B16

Hexadecimal 0 1 2 3 4 5 6 7 8 9 A B C D E F
Decimal Equivalente 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Tabela 3: Números Hexadecimais e sua equivalência para números decimais

Decimal Binário Octal Hexadecimal


12610 11111102 1768 7E16
1110 10112 138 B16
Tabela 4: Sumário dos exemplos

6.5. Conversões

6.5.1. Decimal para Binário / Binário para Decimal


Para converter um número decimal em binário, deve-se dividir continuamente este número por 2
e separar o resto (que será ou 0 ou 1), considerando-o como um dígito da forma binária do
número. Obter o quociente e dividir novamente por 2, repetir o processo até que o quociente
atinja 0 ou 1. Ao término, agrupar todos os restos começando pelo último resto. O resultado é a
forma binária do número.

Introdução à Programação I 14
JEDITM

NOTA: O último dígito menor que o divisor (2) será o primeiro número do resultado.
Por Exemplo:
12610 = ? 2

Quociente Resto
126 / 2 = 63 0
63 / 2 = 31 1
Escreva
31 / 2 = 15 1
nesta
15 / 2 = 7 1 direção
7 / 2 = 3 1
3 / 2 = 1 1
1 / 2 = 1

Então, escrevendo os restos de baixo para cima, obtemos o número binário 11111102.
Para converter um número binário para decimal, multiplicar o dígito binário por “2 elevado a
posição deste número binário”. Adicionar todos os produtos para obter o número decimal
resultante.
Por Exemplo:
11111102 = ? 10

Posição 6 5 4 3 2 1 0
Dígitos
1 1 1 1 1 1 0
Binários
0 x 20 = 0
1 x 21 = 2
1 x 22 = 4
1 x 2 3= 8
1 x 24= 16
1 x 25 = 32
1 x 26 = 64
TOTAL: 126

6.5.2. Decimal Para Octal (ou Hexadecimal)/Octal (ou Hexadecimal) para Decimal
Converter números decimais para octal ou hexadecimal é basicamente o mesmo que converter
decimal para binário. Entretanto, ao invés de utilizar o 2 como divisor, substituí-lo por 8 (para
octal) ou 16 (para hexadecimal).
Por Exemplo (Octal):
12610 = ? 8

Quociente Resto
Escreva
15 6 nesta
126 / 8 =
direção
15 / 8 = 1 7
1/8= 1

Então, escrevendo os restos de baixo para cima, obtemos o número octal 1768.
Por Exemplo (Hexadecimal):
12610 = ? 16

Introdução à Programação I 15
JEDITM

Quociente Resto
14 (igual ao dígito Escreva
hexadecimal E) nesta
126 / 16 = 7 direção
7 / 16 = 7

Então, escrevendo os restos de baixo para cima, obtemos o número hexadecimal 7E16
Converter números octais ou hexadecimais é um processo semelhante a converter números de
binários para decimal. Para fazer isto, substituímos o número 2 pelo 8 para octal ou pelo 16 para
hexadecimal.
Por Exemplo (Octal):
1768 = ? 10

Posição 2 1 0
Dígitos Octais 1 7 6
6 x 80 = 6
7 x 81 = 56
1 x 82 = 64
TOTAL: 126

Por Exemplo (Hexadecimal):


7E16 = ? 10

Posição 1 0
Dígitos
7 E
Hexadecimais
14 x 160 = 14
7 x 161 = 112
TOTAL: 126

6.5.3. Binário para Octal / Octal para Binário


Para conveter números binários para octal, partimos o número binário em grupos de 3 dígitos (da
direita para esquerda), e o preenchemos com zeros se o número de dígitos não for divisível por 3.
Então, convertemos cada partição em seu correspondete dígito octal. A tabela abaixo mostra a
representação binária de cada dígito octal.

Dígito Octal Representação


Binária
0 000
1 001
2 010
3 011
4 100
5 101
6 110
7 111
Tabela 5: Dígitos Octais e sua representação binária correspondente

Por Exemplo:

Introdução à Programação I 16
JEDITM

11111102 = ? 8

0 0 1 1 1 1 1 1 0

1 7 6
Número octal equivalente

Converter números octais para binário é o oposto do que foi explicado acima. Simplesmente
converta cada dígito octal na sua representação binária (conforme a tabela) e concatene-os. O
resultado é a representação binária.

6.5.4. Binário para Hexadecimal / Hexadecimal para Binário


Para converter números binários para hexadecimal, partimos o número binário em grupos de 4
dígitos (da direita para a esquerda), e o preenchemos com zero se o número de dígitos não for
divisível por 4. Então convertemos cada partição em seu dígito hexadecimal correspondente. A
tabela abaixo mostra a representação binária de cada dígito hexadecimal.

Dígito Representação
Hexadecimal Binária
0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001
A 1010
B 1011
C 1100
D 1101
E 1110
F 1111
Tabela 6: Dígitos Hexadecimais e sua representação binária correspondente

Por Exemplo:
11111102 = ? 16

0 1 1 1 1 1 1 0

7 E

Número hexadecimal equivalente

Introdução à Programação I 17
JEDITM

Converter números hexadecimais para binário é o oposto do que foi explicado acima.
Simplesmente converta cada dígito hexadecimal na sua representação binária (conforme a
tabela) e concatene-os. O resultado é a representação binária.

Introdução à Programação I 18
JEDITM

7. Exercícios
7.1. Escrevendo Algoritmos
Dado o seguinte conjunto de tarefas, crie um algoritmo para realizar cada uma das tarefas
abaixo. Escreva os algoritmos usando pseudocódigo ou fluxogramas.
1. Assar pão
2. Acessar o computador
3. Obter a média de três números

7.2. Conversão de Números


Converta os números abaixo:
1. 198010 para binário, hexadecimal e octal
2. 10010011012 para decimal, hexadecimal e octal
3. 768 para binário, hexadecimal e decimal
4. 43F16 para binário, decimal e octal

Introdução à Programação I 19
Módulo 1
Introdução à Programação I

Lição 2
Histórico de Java

Versão 1.0 - Jan/2007


JEDITM

1. Objetivos

Nesta lição iremos discutir um pouco da história de Java e o que é a tecnologia Java. Também
iremos discutir as fases de um programa Java.
Ao final desta lição, o estudante será capaz de:
• Descrever as características da tecnologia Java como a JVM - Máquina Virtual Java,
Garbage Collection e segurança do código;
• Descrever as diferentes fases de um programa Java.

Introdução à Programação I 4
JEDITM

2. Explorando o Java
2.1. Um pouco da história

Java foi criado em 1991 por James Gosling da Sun Microsystems. Inicialmente chamada OAK
(Carvalho), em homenagem à uma árvore de janela do Gosling, seu nome foi mudado para Java
devido a existência de uma linguagem com o nome OAK.

Figura 1: James Gosling criador do Java

A motivação original do Java era a necessidade de uma linguagem independente de plataforma


que podia ser utilizada em vários produtos eletrônicos, tais como torradeiras e refrigeradores. Um
dos primeiros projetos desenvolvidos utilizando Java era um controle remoto pessoal chamado *7
(Star Seven).

Figura 2: Star Seven

Ao mesmo tempo, a World Wide Web e a Internet foram ganhando popularidade. Gosling achava
que a linguagem Java poderia ser usada para programação da Internet.

2.2. O que é a tecnologia Java?

2.2.1. Uma linguagem de programação


Como linguagem de programação, Java pode ser utilizado para criar todos os tipos de aplicações
existentes, de programas de Inteligência Artificial para Robôs até programas para aparelhos
celulares.

Introdução à Programação I 5
JEDITM

2.2.2. Um ambiente de desenvolvimento


Como ambiente de desenvolvimento, a tecnologia Java fornece um grande conjunto de
ferramentas: um compilador, um interpretador, um gerador de documentação, ferramenta de
empacotamento de classes de arquivos e outros.

2.2.3. Um ambiente de aplicação


Aplicações de tecnologia Java são tipicamente programas de propósito geral que executam sobre
uma máquina onde o Java Runtime Environment é instalado.

2.2.4. Um ambiente de distribuição


Há dois ambientes de distribuição principais: Primeiro, o JRE, fornecido através do Java 2
Software Development Kit (SDK), contém um conjunto completo de arquivos de classes para
todos pacotes de tecnologia Java. Outro ambiente de distribuição é o navegador web, ou seja, o
browser. Os navegadores web atuais fornecem interpretação à tecnologia e ambiente Java em
tempo de execução.

Figura 3: JDK e JRE

2.3. Algumas características do Java

2.3.1. Máquina Virtual Java


A Máquina Virtual Java é uma máquina imaginária que é implementada através de um software
emulador em uma máquina real. A JVM provê especificações de plataforma de hardware na qual
compila-se todo código de tecnologia Java. Essas especificações permitem que o software Java
seja uma plataforma independente pois a compilação é feita por uma máquina genérica
conhecida como JVM.

O bytecode é uma linguagem de máquina especial que pode ser entendida pela Máquina
Virtual Java (JVM). O bytecode é independente de qualquer hardware de computador
particular. Assim, qualquer computador com o interpretador Java pode executar um programa
Java compilado, não importando em que tipo de computador o programa foi compilado.

Introdução à Programação I 6
JEDITM

2.3.2. Garbage Collection


Muitas linguagens de programação permitem ao programador alocar memória durante o tempo
de execução. Entretanto, após utilizar a memória alocada, deve existir uma maneira para
desalocar o bloco de memória de forma que os demais programas a utilizem novamente. Em C,
C++ e outras linguagens o programador é o responsável por isso. Isso, às vezes, pode ser difícil
já que instâncias podem ser esquecidas de serem desalocadas da memória pelos programadores
e resultar no que chamamos de escapes da memória.

Em Java, o programador não possui a obrigação da retirar uma variável criada das áreas de
memória, isto é feito por uma parte da JVM específica que chamamos de Garbage Collection. O
Garbage Collection é o grande responsável pela liberação automática do espaço em memória.
Isso acontece automaticamente durante o tempo de vida do programa Java.

2.3.3. Segurança do Código

Segurança do Código é alcançada em Java através da implementação da Java Runtime


Environment (JRE). A JRE roda códigos compilados para a JVM e executa o carregamento de
classes (através do Class Loader), verificação de código (através do verificador de bytecode) e
finalmente o código executável.

O Class Loader é responsável por carregar todas as classes necessárias ao programa Java. Isso
adiciona segurança através da separação do namespace entre as classes do sistema de arquivos
local e aquelas que são importadas pela rede. Isso limita qualquer ação de programas que podem
causar danos, pois as classes locais são carregadas primeiro. Depois de carregar todas as classes,
a quantidade de memória que o executável irá ocupar é determinada. Isto acrescenta,
novamente, uma proteção ao acesso não autorizado de áreas restritas ao código pois a
quantidade de memória ocupada é determinada em tempo de execução.

Após carregar as classes e definir a quantidade de memória, o verificador de bytecode verifica


o formato dos fragmentos de código e pesquisa nestes fragmentos por códigos ilegais que
possam violar o direito de acesso aos objetos.

Depois que tudo isso tiver sido feito, o código é finalmente executado.

2.4. Fases do Programa Java


A figura seguinte descreve o processo de compilação e execução de um programa Java.

Figura 1: Fases de um Programa Java.

O primeiro passo para a criação de um programa Java é escrever os programas em um editor de


texto. Exemplos de editores de texto que podem ser utilizados: bloco de notas, vi, emacs, etc.
Esses arquivos são armazenados no disco rígido com a extensão .java.

Introdução à Programação I 7
JEDITM

Após o programa Java ter sido criado e salvo, compile o programa utilizando o Compilador Java.
A saída desse processo é um arquivo de bytecode com extensão .class.

O arquivo .class é então lido pelo Interpretador Java que converte os bytecodes em linguagem de
máquina do computador que se está usando.

Tarefa Ferramenta utilizada Saída


Escrever o programa Qualquer editor de texto Arquivo com extensão .java
Compilar o programa Compilador Java Arquivo com extensão .class
(Java bytecode)
Executar o programa Interpretador Java Saída do programa
Tabela 1: Resumo das fases de um programa Java.

Introdução à Programação I 8
Módulo 1
Introdução à Programação I

Lição 3
Primeiros passos no ambiente de programação

Versão 1.0 - Jan/2007


JEDITM

1. Objetivos
Nesta lição discutiremos como escrever, compilar e rodar os programas em Java. Existem duas
maneiras para se fazer isso: a primeira é por intermédio de uma console e um editor de texto e a
segunda é utilizando a IDE NetBeans como ambiente integrado de desenvolvimento.

Ao final desta lição, o estudante será capaz de:

• Criar programas usando o editor de texto com uma console de desenvolvimento do Linux
(sugerimos o Ubuntu Dapper) ou Windows
• Diferenciar entre erros de sintaxe e de tempo de execução (Run Time)
• Criar programas utilizando a IDE NetBeans

Introdução à Programação I 4
JEDITM

2. Introdução
Uma IDE é um ambiente de desenvolvimento integrado. É um software aplicativo que provê um
construtor de interfaces GUI, um editor de códigos, um compilador e/ou interpretador e um
depurador.

Nesta lição utilizaremos o Ubuntu Dapper como sistema operacional ou o Windows. Antes de
realizar esta tenha certeza de que já tenha instalado no sistema operacional a Java JDK e o
NetBeans. Instruções como instalar o Java JDK e o NetBeans podem ser vistas no Apêndice A e
para os ambientes na versão Windows XP no Apêndice B.

Antes de entrar em detalhes, veremos o primeiro programa Java que poderemos escrever.

Introdução à Programação I 5
JEDITM

3. Primeiro Programa Java


Antes de explicar o que o programa significa, vamos escrevê-lo e executá-lo.

3.1 Utilizando a console e um editor de texto


Neste exemplo utilizaremos um simples editor de texto, que pode ser o gedit do Linux ou o
notepad do Windows, para editar o código fonte. Em seguida será necessário abrir uma janela
terminal para compilar e executar os programas.

Passo 1: executar um editor de texto

Para iniciar um editor de texto no Linux selecione Applications ⇒ Accessories ⇒ Text Editor.

Para iniciar um editor de texto no Windows selecione Start ⇒ Programs ⇒ Accessories ⇒


Notepad.

Passo 2: Abrir a janela de console

Para abrir o terminal no Linux, selecione Applications ⇒ Accessories ⇒ Terminal.

Para abrir o terminal no Windows, selecione Start ⇒ Run... e na janela que se apresenta, digite
cmd e pressione o botão OK.

Passo 3: Escrever as instruções utilizando o Editor de Texto

Digite as seguintes instruções no editor de textos:

public class Hello


{
/**
* Meu primeiro programa Java
*/
public static void main(String[] args) {
// Mostra na tela o texto "Hello world"
System.out.println("Hello world!");
}
}

Passo 4: Salvar o programa Java

Chamaremos o programa de "Hello.java" e o colocaremos em uma pasta denominada


"myJavaPrograms".

Caso esta pasta não tenha sido criada, retorne à janela de terminal aberta e insira as seguintes
instruções:

Para o Linux:

$ md myJavaPrograms

Para o Windows:

C:\> md myJavaPrograms

Retorne ao Editor de textos e salve o programa. Para abrir a caixa de diálogo salvar selecione a

Introdução à Programação I 6
JEDITM

opção "File" localizada na barra de menus e depois clique na opção "Save".

Selecione a nova pasta criada como myJavaPrograms para entrar nela. A pasta deve estar vazia
porque ainda não salvamos nada dentro dela.

Na caixa de texto "Name", digite o nome do programa (Hello.java), e depois clique no botão
salvar.

ATENÇÃO: Para o Notepad no Windows, mude o Tipo para "All Files" (em Save as Type).

Após salvar o arquivo observe que o título da janela mudou de "Untitled" para "Hello.java", caso
deseje alterar novamente o arquivo basta editá-lo e depois salvá-lo novamente clicando em File
⇒ Save.
Passo 5: Entrar na pasta que contém o programa

O próximo passo deve ser o de compilar o programa. Inicialmente, precisamos entrar na pasta
que o contém. Retorne à janela do terminal.

Em Linux:

Normalmente, quando abrimos uma janela terminal, ela vai diretamente para sua pasta home
(identificada por $). Para ver o que tem dentro do diretório digite ls (LS em minúscula,
significando "List Sources") e pressione ENTER. Isso fará com que sejam listados os arquivos e
pastas da pasta home.

Verifique a existência de uma pasta chamada "myJavaPrograms", criada a pouco, sendo esta o
local em que foi salvo o programa "Hello.java". Mudaremos o contexto para esta pasta.

Para entrar nesta pasta devemos utilizar o comando: cd [nome da pasta]. O comando "cd"
significa "Change Directory". Digitaremos:

$ cd myJavaPrograms

Agora que estamos dentro da pasta onde o arquivo do programa está, poderemos então compilá-
lo. Certifique-se de que o arquivo está realmente dentro desta, executando o comando ls (LS em
minúscula) novamente.

Em Windows:

Normalmente, quando abrimos uma janela terminal ela vai diretamente para sua pasta raiz
(identificada por C:\). Para conhecer o conteúdo do diretório digite dir (significando "directory") e
pressione ENTER. Isso fará com que sejam listados os arquivos e pastas da pasta principal.

Verifique a existência de uma pasta chamada "myJavaPrograms", criada a pouco, sendo esta o
local em que foi salvo o programa "Hello.java". Mudaremos o contexto para esta pasta.

Para entrar nesta pasta devemos utilizar o comando: cd [nome da pasta]. O comando "cd"
significa "Change Directory". Digitaremos:

C:\>cd myJavaPrograms

Agora que estamos dentro da pasta onde o arquivo do programa está, poderemos então compilá-
lo. Certifique-se de que o arquivo está realmente dentro desta, executando o comando dir
novamente.

Passo 6: Compilar o programa

Introdução à Programação I 7
JEDITM

Para compilar o programa, utilizamos o comando: javac [Nome do Arquivo]. Ou seja:

javac Hello.java

Durante a compilação, é criado o arquivo: [Nome do Arquivo].class, neste caso, Hello.class,


que contém o código em linguagem de máquina (chamado de bytecode).

Passo 7: Executar o programa

Assumindo que não ocorreu problemas na compilação (caso tenha ocorrido qualquer problema
refaça os passos realizados), estamos prontos para executar o programa.

Para executar o programa, utilizamos o comando: java [nome do arquivo sem a extensão].
No caso do exemplo, digite:

java Hello

Veremos na mesma tela, em que foi executado o comando, a seguinte mensagem:

Hello world!

3.2 Erros
Vimos um pequeno programa Java, geralmente não encontraremos qualquer problema para
compilar e executar esses programas, entretanto nem sempre este é o caso, como mencionamos
na primeira parte deste curso, ocasionalmente encontramos erros durante esse processo.

Como mencionamos antes, há dois tipos de erros: o primeiro pode ocorrer durante a compilação,
chamado de erro de sintaxe, o segundo pode ocorrer durante a execução, chamado runtime
error.

3.2.1 Erros de Sintaxe

Os erros de sintaxe normalmente são erros de digitação, ocasionados pelo programador que pode
ter se equivocado e digitar uma instrução errada, ou por esquecimento de alguma parte da
instrução, por exemplo, um ponto e vírgula. O Compilador tenta isolar o erro exibindo a linha de
instrução e mostrando o primeiro caractere incorreto naquela linha, entretanto, um erro pode não
estar exatamente neste ponto.
Outros erros comuns são a troca de letras, troca de letras maiúscula por minúscula (a linguagem
Java é completamente case-sensitive, ou seja, o caractere "a" é completamente diferente do
caractere "A", e o uso incorreto da pontuação.

Vamos retornar ao exemplo, o programa Hello.java. Intencionalmente, escreveremos a palavra-


chave "static" de forma errada e omitiremos o ponto-e-vírgula em uma instrução e a deixaremos
errada.

public class Hello


{
/**
* Meu primeiro programa Java
*/
public statict void main(String[] args) {
// A linha abaixo foi retirado o ;
System.out.println("Hello world!")
}

Introdução à Programação I 8
JEDITM

Salve o programa e execute os passos necessários para compilá-lo. Observe a mensagem de erro
gerada ao se tentar compilar novamente o programa:

Hello.java:6: <identifier> expected


public statict void main(String[] args) {
^
Hello.java:10: ';' expected
}
^
1 error

A primeira mensagem de erro sugere que existe um erro na linha 6 do programa apontado para a
palavra void, entretanto esta palavra está correta. O erro é na palavra anterior statict que deve
ser digitada como static.

A segunda mensagem de erro sugere que faltou um ponto-e-vírgula na linha 10, entretanto, esta
contém simplesmente o comando de fechar o bloco do método main. O erro está exatamente na
linha anterior.

Como regra, ao encontrar muitas mensagens de erros devemos corrigir o primeiro erro da lista e
tente novamente compilar o programa. Deste modo reduziremos o número total de mensagens
de erro dramaticamente, pois podem existir o que chamamos de erros derivados, ou seja, um
erro que tem por causa a instrução anterior.

3.2.2 Erros em tempo de execução (Erros de run-time)

Os erros em tempo de execução são erros que não aparecerão até que tentemos executar o
programa. Os programas são compilados com sucesso, mas apresentarão respostas erradas, que
podem ter como causa se o programador não obedeceu uma lógica coerente ou no caso em erro
de estruturas do programa.

Introdução à Programação I 9
JEDITM

4. Usando NetBeans
Construímos o programa sem utilizar nenhum recurso sofisticado, iremos aprender como fazer
todo o processo da seção anterior utilizando uma IDE.

Nesta parte da lição utilizaremos o NetBeans que é um Ambiente de Desenvolvimento Integrado


(IDE - Integrated Development Environment).

Um ambiente de desenvolvimento integrado é um software aplicativo que possui uma interface


construtora, um editor de texto, um editor de código, um compilador e/ou interpretador e um
depurador.

Passo 1 : executar o NetBeans

Existem duas formas de executar o NetBeans: a primeira é utilizando a linha de comandos de


uma janela terminal e segunda é selecionar o ícone de atalho encontrado na janela da área de
trabalho.

Para executar o NetBeans por intermédio da linha de comando, abra uma janela terminal (Os
passos para abrir a janela terminal foram discutidos anteriormente) e digite:

Figura 1: Executando o NetBeans pela linha de comandos

Para o Windows, este comando deve ser executado na pasta em que o NetBeans foi instalado,
por exemplo:

C:\Program Files\netbeans-5.5\bin>netbeans

A segunda maneira de executar o NetBeans é clicando no ícone de atalho encontrado na área de


trabalho do computador.

Figura 2: Ícone do NetBeans 5.5 no Desktop

Depois de abrir a IDE NetBeans será mostrada a interface gráfica GUI, conforme à Figura 3:

Introdução à Programação I 10
JEDITM

Figura 3: Janela de Welcome do NetBeans

Passo 2: construir o projeto

Clique em File ⇒ New Project, depois de fazer isso, uma janela de diálogo aparecerá. Neste
momento deve-se clicar em "Java Application" e em seguida clicar no botão "Next >".

Figura 4: Escolhendo o tipo do projeto

Introdução à Programação I 11
JEDITM

Será mostrada uma nova janela de diálogo, conforme a figura 5.

Figura 5: Inserindo as informações do projeto

Troque o local da aplicação clicando no botão "Browse...". Aparecerá uma janela de diálogo para
localização do diretório. Dê um clique duplo no seu diretório home.

Figura 6: Acertando a Localização do Projeto

Introdução à Programação I 12
JEDITM

O conteúdo da raiz do diretório será apresentado. Dê um clique duplo no diretório


MYJAVAPROGRAMS e depois dê um clique no botão "Open".

Veja que a localização do projeto mudou para /home/florence/MYJAVAPROGRAMS.


Finalmente, no campo "Create Main Class", digite "Hello", que será o nome da classe principal, e
em seguida clique no botão "Finish".

Figura 7: Definindo o Nome da Classe Principal

Introdução à Programação I 13
JEDITM

Passo 3: escrever os detalhes do programa

Antes de escrever o programa descreveremos a janela principal.

Como mostrado na figura 8, automaticamente, o NetBeans cria um código básico para o


programa Java. Poderemos adicionar as declarações neste código gerado. No lado esquerdo da
janela visualizamos uma lista de pastas e arquivos que o NetBeans gerou antes de criar o projeto.
Tudo se encontra dentro da sua pasta MYJAVAPROGRAMS, onde foi configurado o local do
projeto. No lado direito, visualizamos o código gerado.

Figura 8: Visão do projeto criado

Modifique o código gerado pelo NetBeans, por hora ignoraremos as outras partes das instruções
discutindo os detalhes destas posteriormente. Insira a seguinte instrução:

System.out.println("Hello world!");

Isto significa que você deseja que seja mostrada a mensagem "Hello world!" na saída padrão do
computador, em seguida seja feito um salto de linha. Poderíamos substituir esta instrução por
duas equivalentes:

System.out.print("Hello");
System.out.println(" world!");

O método print() faz com que não seja provocado o salto de linha, utilizaremos para este
exemplo a primeira instrução. Insira esta instrução após a linha de comentário (que será
desprezada pelo compilador):

//TODO code application logic here.

Introdução à Programação I 14
JEDITM

Figura 9: Inserindo sua instrução

Passo 4 : compilar o projeto


Para compilar o programa, a partir do Menu Principal selecione Build ⇒ Build Main Project, ou
utilize a tecla de atalho F11, ou utilize o botão de atalho para compilar o código.

Figura 10: Botão de Atalho para executar o Projeto

Introdução à Programação I 15
JEDITM

Se não existir erros no programa, veremos a mensagem de sucesso na janela de saída.

Figura 11: Verificando o Sucesso da Compilação

Passo 5: Executar o projeto


Para executar o programa, clique em Run ⇒ Run Main Project, ou utilize a tecla de atalho F6, ou
utilize o botão de atalho para executar o programa.

Figura 12: Executando o projeto

Introdução à Programação I 16
JEDITM

O resultado final do programa, será mostrado na janela de saída.

Figura 13: Resultado final da execução do projeto

Introdução à Programação I 17
JEDITM

5. Exercícios
5.1 Melhorando o Hello World!
Utilizando o NetBeans crie uma classe chamada [SeuNome], o programa deverá mostrar como
resultado a mensagem:

Welcome to Java Programming [SeuNome]!!!

5.2 A árvore
Utilizando o NetBeans, crie uma classe chamada TheTree. O programa deverá mostrar as
seguintes linhas na saída:

I think that I shall never see,


[Eu acho que nunca verei,]
a poem as lovely as a tree.
[um poema tão adorável quanto uma árvore.]
A tree whose hungry mouth is pressed
[Uma árvore cuja boca faminta é pressionada]
Against the Earth’s sweet flowing breast.
[Contra a Terra fluindo em seu seio docemente.]

Introdução à Programação I 18
Módulo 1
Introdução à Programação I

Lição 4
Fundamentos da programação

Versão 1.01 - Jan/2008


JEDITM

1. Objetivos
Nesta lição discutiremos as partes básicas de um programa em Java. Começaremos explicando
as partes do programa Hello.java mostrado na última lição. Discutiremos ao longo desta lição
também dicas e convenções para se escrever programas de fácil entendimento.

Ao final desta lição, o estudante será capaz de:

• Identificar e entender as partes básicas de um programa escrito em Java.


• Diferenciar, em um programa, o que são: os tipos primitivos de dados, variáveis,
identificadores e operadores.
• Desenvolver, em Java, um programa usando os conceitos compreendidos nesta lição.

Introdução à Programação I 4
JEDITM

2. Entendendo meu primeiro programa em Java


Tentaremos compreender este primeiro programa.

public class Hello


{
/**
* Meu primeiro programa em Java
*/
public static void main(String[] args) {
// Exibir a mensagem "Hello world" na tela
System.out.println("Hello world!");
}
}

Esta primeira linha do código:

public class Hello

Indica o nome da classe, que neste caso é Hello. Em Java, todo e qualquer código deverá ser
escrito dentro da declaração de uma classe. Fazemos isso usando a palavra-chave class. Além
disso, a classe usa um identificador de acesso public, indicando que a classe é acessível para
outras classes de diferentes pacotes (pacotes são coleções de classes). Trataremos de pacotes
e identificadores de acesso mais tarde, ainda neste módulo.

A próxima linha contém uma chave {. Indica o início de um bloco de instruções. Neste
programa posicionamos a chave na linha após a declaração da classe, entretanto, poderíamos
também colocá-la na mesma linha em que a declaração foi feita. Então, o código seria escrito
da seguinte forma:

public class Hello


{
ou
public class Hello {

As próximas 3 linhas indicam um comentário em Java. Um comentário é uma explicação do


programador usada na documentação de uma parte do código. Este comentário não é
propriamente uma parte do código, é usado apenas para fins de documentação do programa.
É uma boa prática de programação adicionar comentários relevantes ao código.

/**
* Meu primeiro programa em Java
*/

Um comentário pode ser indicado pelos delimitadores “/*” e “*/”. Qualquer coisa entre estes
delimitadores é ignorado pelo compilador Java e é tratado como comentário. A próxima linha,

public static void main(String[] args) {

que também pode ser escrita da seguinte forma:

public static void main(String[] args)


{

indica o nome de um método no programa que é o método principal main. O método main é
o ponto de partida para qualquer programa feito em Java. Todo e qualquer programa escrito

Introdução à Programação I 5
JEDITM

em Java, com exceção de Applets, inicia com o método main. Certifique-se de que a
assinatura do método (conforme descrita acima) está correta.

A linha seguinte é também um comentário em Java,

// exibe a mensagem "Hello world" na tela

Até agora, já aprendemos duas maneiras de fazer comentários em Java. Uma é posicionar o
comentário entre “/*” e “*/”, e a outra é colocar “//” antes do comentário. A linha de instrução
abaixo,

System.out.println("Hello world!");

escreve o texto "Hello World!" na tela. O comando System.out.println( ), escreve na saída


padrão do computador o texto situado entre aspas duplas.

As últimas duas linhas, que contêm somente uma chave em cada, simbolizam,
respectivamente, o fechamento do método main e da classe.

Dicas de programação :

1. Os programas em Java devem sempre conter a terminação .java no nome do


arquivo.
2. O nome do arquivo deve sempre ser idêntico ao nome da classe pública. Então,
por exemplo, se o nome da classe pública é Hello o arquivo deverá ser salvo
com o nome: Hello.java.
3. Inserir comentários sobre o que a classe ou método realiza, isso facilitará o
entendimento de quem posteriormente ler o programa, incluindo o próprio autor.

Introdução à Programação I 6
JEDITM

3. Comentários em Java
Comentários são notas escritas pelo programador para fins de documentação. Estas notas não
fazem parte do programa e não afetam o fluxo de controle.

Java suporta três tipos de comentários: comentário de linha estilo C++, comentário de bloco
estilo C e um comentário estilo Javadoc (utilizado compor a documentação do programa).

3.1. Comentário de linha

Comentários com estilo em C++ se iniciam por "//". Todo e qualquer texto colocado após as
// é ignorado pelo compilador e tratado como comentário. Por exemplo:

// Este é um comentário estilo C++ ou comentário de linha

3.2. Comentário de bloco

Comentários com estilo em C, também chamados de comentários multi-linhas, se iniciam com


/* e terminam com */. Todo o texto posto entre os dois delimitadores é tratado como
comentário. Diferente do comentário estilo C++, este pode se expandir para várias linhas. Por
exemplo:

/*
* Este é um exemplo de comentário
* estilo C ou um comentário de bloco
*
*/

3.3. Comentário estilo Javadoc

Este comentário é utilizado na geração da documentação em HTML dos programas escritos em


Java. Para se criar um comentário em estilo Javadoc deve se iniciar o comentário com /** e
terminá-lo com */. Assim como os comentários estilo C, este também pode conter várias
linhas. Este comentário também pode conter certas tags que dão mais informações à
documentação. Por exemplo:

/**
Este é um exemplo de um comentário especial usado para \n
gerar uma documentação em HTML. Este utiliza tags como:
@author Florence Balagtas
@version 1.2
*/

Este tipo de comentário deve ser utilizado antes da assinatura da classe:

public class Hello {

Para documentar o objetivo do programa ou antes da assinatura de métodos:

public static void main(String[] args) {

Para documentar a utilidade de um determinado método.

Introdução à Programação I 7
JEDITM

4. Instruções e Blocos em Java

Uma instrução é composta de uma ou mais linhas terminadas por ponto-e-vírgula. Um


exemplo de uma simples instrução pode ser:

System.out.println("Hello world");

Um bloco é formado por uma ou mais instruções agrupadas entre chaves indicando que
formam uma só unidade. Blocos podem ser organizados em estruturas aninhadas
indefinidamente. Qualquer quantidade de espaços em branco é permitida. Um exemplo de
bloco pode ser:

public static void main(String[] args) {


System.out.print("Hello ");
System.out.println("world");
}

Dicas de programação:

1. Na criação de blocos, a chave que indica o início pode ser colocada ao final da linha
anterior ao bloco, como no exemplo:

public static void main(String [] args) {

ou na próxima linha, como em:

public static void main(String [] args)


{

2. É uma boa prática de programação organizar as instruções que serão colocadas após
o início de um bloco, como por exemplo:

public static void main(String [] args) {


System.out.print("Hello ");
System.out.println("world");
}

Introdução à Programação I 8
JEDITM

5. Identificadores em Java

Identificadores são representações de nomes de variáveis, métodos, classes, etc. Exemplos de


identificadores podem ser: Hello, main, System, out.

O compilador Java difere as letras maiúsculas de minúsculas (case-sensitive). Isto significa que
o identificador Hello não é o mesmo que hello. Os identificadores em Java devem começar
com uma letra, um underscore “_”, ou um sinal de cifrão “$”. As letras podem estar tanto em
maiúsculo quanto em minúsculo. Os caracteres subseqüentes podem usar números de 0 a 9.

Os identificadores não podem ter nomes iguais às palavras-chave ou palavras reservadas do


Java, como: class, public, void, int, etc. Discutiremos mais sobre estas palavras mais tarde.

Dicas de programação:

1. Para nomes de classes, a primeira letra deve ser maiúscula. Nomes de métodos ou
variáveis devem começar com letra minúscula. Por exemplo:

ExemploDeNomeDeUmaClasse
exemploDeNomeDeUmMetodo

2. No caso de identificadores com mais de uma palavra, a primeira letra de cada palavra,
com exceção da primeira, deve vir em maiúsculo. Por exemplo:

charArray – fileNumber - className

3. Evite o uso de undescores no início de um identificador. Por exemplo:

_NomeDeClasse.

Introdução à Programação I 9
JEDITM

6. Palavras-chave em Java

Palavras-chave são identificadores que, em Java, foram pré-definidas para propósitos


específicos. Não se pode usar esses identificadores como nomes de variáveis, métodos,
classes, etc. A seguir, temos a lista com as palavras-chave em Java.

Figura 1: Palavras-Chave em Java

Ao longo dos tópicos seguintes, iremos abordar os significados destas palavras-chave e como
são usadas nos programas em Java.

Nota: true, false e null não são palavras-chave, porém, são palavras-reservadas, e, da
mesma maneira, não é permitido seu uso na atribuição a nomes de variáveis, métodos ou
classes.

Introdução à Programação I 10
JEDITM

7. Tipos de Dados em Java

Java possui 4 tipos de dados. Estes tipos de dados são divididos em: boolean, character,
integer e float-point.

7.1. Boolean

Um dado boolean poderá assumir somente dois valores: true ou false.

7.2. Character

Os characters são representações da tabela Unicode. Um símbolo da tabela Unicode é um


valor de 16 bits que pode substituir os símbolos da tabela ASCII (que possuem 8 bits). A
tabela Unicode permite a inserção de símbolos especiais ou de outros idiomas. Para
representar um caractere usam-se aspas simples. Por exemplo, a letra "a" será representada
como 'a'. Para representar caracteres especiais, usa-se a "\" seguido pelo código do caractere
especial. Por exemplo, '\n' para o caractere de nova linha, '\'' representar o character ' (aspas
simples) e '\u0061' representação Unicode do símbolo 'a'.

7.3. Integer

Os dados do tipo integer vêm em diferentes formatos: decimal (base 10), hexadecimal
(base 16), e octal (base 8). Ao usar estes diferentes tipos de dados Integer nos programas é
necessário seguir algumas notações preestabelecidas. Para dados decimais não existe notação,
basta escrever o número. Os números hexadecimais deverão ser precedidos por "0x" ou "0X".
E os octais deverão ser precedidos por "0".

Por exemplo, considere o número 12. Sua representação em decimal é apenas o número 12,
sem nenhuma notação adicional, enquanto que sua representação em hexadecimal é 0xC
(pois o número 12 em hexadecimal é representado pela letra C), e em octal ele é representado
por 014. O valor padrão para tipos de dados Integer é o tipo int. Um int é um valor, com
sinal, de 32 bits.

Em alguns casos pode ser necessário forçar o dado Integer a ser do tipo long, para fazer isso
basta colocar a letra "l" (L minúscula) ou "L" após o número. Um dado do tipo long é um valor
com sinal de 64 bits. Falaremos mais sobre os tipos de dados mais tarde.

7.4. Float-Point

Os tipos de float-point representam dados Integer com parte fracionária. Um exemplo é o


número 3.1415 (lembrando que o padrão inglês utiliza o "." como divisor da parte fracionária).
Esses tipos podem ser expressos em notação científica ou padrão. Um exemplo de notação
padrão é o número 583.45 enquanto que em notação científica ele seria representado por
5.8345e2. O valor padrão para um dado ponto-flutuante é o double, que é um valor de 64 bits.
Se for necessário usar um número com uma precisão menor (32 bits) usa-se o float, que é
finalizado pela letra "f" ou "F" acrescida ao número em questão, por exemplo, 583.45f.

Introdução à Programação I 11
JEDITM

8. Tipos de Dados Primitivos

A linguagem Java possui 8 tipos de dados primitivos. Eles são divididos nas seguintes
representações:

Representação Tipo de Dado Dado Primitivo


lógico Boolean boolean
inteiro Integer e Character char, byte, short e int
inteiro longo Integer long
número fracionário Float-point float e double
Tabela 1: Representações dos dados primitivos

8.1. Lógico

O tipo boolean pode representar dois estados: true (verdadeiro) ou false (falso). Um
exemplo é:

boolean resultado = true;

No exemplo demonstrado acima, é declarado um atributo chamado resultado do tipo


boolean e atribuído a este o valor verdadeiro.

8.2. Inteiro

Os inteiros em Java podem ser representados em 5 formas, como já foi visto, e estas são:
decimal, octal, hexadecimal, ASCII e Unicode. Como por exemplo:

2 // valor 2 em decimal
077 // 0 indica que ele está representado em octal.
0xBACC // 0x indica que ele está representado em hexadecimal.
'a' // representação ASCII
'\u0061' // representação Unicode

O dado do tipo char é um inteiro especial, sendo exclusivamente positivo e representa um


único Unicode. Ele deve ser, obrigatoriamente, colocado entre aspas simples (''). Sua
representação como inteiro pode ser confusa para o iniciante, entretanto, o tempo e a prática
farão com que se acostume com este tipo. Por exemplo:

char c = 97; // representa o símbolo 'a'


byte b = 'a'; // em inteiro representa o número 97

É possível definir para qualquer inteiro nas formas mostradas. O que difere o tipo char dos
demais inteiros é que a sua saída sempre será mostrada como um valor ASCII. Enquanto que
os inteiros serão sempre mostrados por números decimais. Por exemplo:

char c = 97;
byte b = 'a';
System.out.println("char = " + c + " - byte = " + b);

Resultará:

char = a - byte = 97

Introdução à Programação I 12
JEDITM

Um cuidado deve ser tomado quanto aos inteiros: qualquer operação efetuada entre eles terá
sempre como resultado um tipo int. Por exemplo:

byte b1 = 1;
byte b2 = 2;
byte resultado = b1 + b2;

Esta instrução final causará um erro de compilação, devendo ser modificada para:

int resultado = b1 + b2;

8.3. Inteiro Longo

Os inteiros têm por padrão o valor representado pelo tipo primitivo int. Pode-se representá-los
como long adicionando, ao final do número, um "l" ou "L". Os tipos de dados inteiros
assumem valores nas seguintes faixas:

Tamanho em memória Dado primitivo Faixa

8 bits byte 7 7
-2 até 2 -1

16 bits char 16
0 até 2 -1

16 bits short 15 15
-2 até 2 -1

32 bits int 31 31
-2 até 2 -1

64 bits long 63 63
-2 até 2 -1

Tabela 2: Tipos e faixa de valores dos Inteiros e Inteiro Longo

Dicas de programação:

1. Para declarar um número como sendo um long é preferível usar “L” maiúsculo, pois, se
este estiver em minúsculo, pode ser difícil distinguí-lo do dígito 1.

8.4. Número Fracionário


Os dados do tipo ponto-flutuante possuem o valor double como padrão. Os números flutuantes
possuem um ponto decimal ou um dos seguintes caracteres:
E ou e // expoente
F ou f // float
D ou d // double
São exemplos,
3.14 // tipo double
6.02E23 // double com expoente
2.718F // float
123.4E+306D // double

No exemplo acima, o número 23 após o E é implicitamente positivo. É equivalente a 6.02E

Introdução à Programação I 13
JEDITM

+23. Os dados de tipo ponto-flutuante podem assumir valores dentro das seguintes faixas:

Tamanho em memória Dado primitivo Faixa

32 bits float 38 38
-10 até 10 -1
64 bits double 308 308
-10 até 10 -1
Tabela 3: Tipos e faixa de valores dos Número Fracionários

Introdução à Programação I 14
JEDITM

9. Variáveis
Uma variável é um espaço na memória usado para armazenar o estado de um objeto.

Uma variável deve ter um nome e um tipo. O tipo da variável indica o tipo de dado que ela
pode conter. O nome das variáveis deve seguir as mesmas regras de nomenclatura que os
identificadores.

9.1. Declarando e inicializando Variáveis


A seguir, vemos como é feita a declaração de uma variável:

<tipo do dado> <nome> [= valor inicial];

nota: os valores colocados entre < > são obrigatórios, enquanto que os valores contidos entre
[ ] são opcionais.

Aqui vemos um exemplo de programa que declara e inicializa algumas variáveis:

public class VariableSamples {


public static void main( String[] args ){
// declara uma variável com nome result e tipo boolean
boolean result;

// declara uma variável com nome option e tipo char


char option;
// atribui o símbolo C para a variável
option = 'C';

// declara uma variável com nome grade e tipo double


// e a inicializa com o valor 0.0
double grade = 0.0;
}
}

Dicas de programação:

1. É sempre preferível que se inicialize uma variável assim que ela for declarada.

2. Use nomes com significado para suas variáveis. Se usar uma variável para
armazenar a nota de um aluno, declare-a com o nome 'nota' e não
simplesmente com uma letra aleatória 'x'.

3. É preferível declarar uma variável por linha, do que várias na mesma linha. Por
exemplo:
int variavel1;
int variavel2;
E não:
int variavel1, variavel2;

9.2. Exibindo o valor de uma Variável

Introdução à Programação I 15
JEDITM

Para exibirmos em qualquer dispositivo de saída o valor de uma variável, fazemos uso dos
seguintes comandos:

System.out.println()
System.out.print()

Aqui está um simples programa como exemplo:

public class OutputVariable {


public static void main( String[] args ){
int value = 10;
char x;
x = 'A';

System.out.println(value);
System.out.println("The value of x = " + x );
}
}
A saída deste programa será a seguinte:

10
The value of x = A

9.3. System.out.println( ) e System.out.print( )

Qual é a diferença entre os comandos System.out.println( ) e o System.out.print( )? O


primeiro faz iniciar uma nova linha após ser exibido seu conteúdo, enquanto que o segundo
não.

Considere as seguintes instruções:

System.out.print("Hello ");
System.out.print("world!");

Essas instruções apresentarão a seguinte saída:

Hello world!

Considere as seguintes:

System.out.println("Hello ");
System.out.println("world!");

Estas apresentarão a seguinte saída:

Hello
world!

9.4. Referência de Variáveis e Valor das Variáveis

Iremos diferenciar os dois tipos de variáveis suportados pelo Java. Estes podem ser de
referência ou de valor.

As variáveis de “valor”, ou primitivas, são aquelas que armazenam dados no exato espaço
de memória onde a variável está.

Introdução à Programação I 16
JEDITM

As variáveis de referência são aquelas que armazenam o endereço de memória onde o dado
está armazenado. Ao declarar uma variável de certa classe (variável de classe), se declara
uma variável de referência a um objeto daquela classe.

Por exemplo, vamos supor que se tenha estas duas variáveis do tipo int e da classe String.

int num = 10;


String nome = “Hello”;

Suponha que o quadro abaixo represente a memória do computador, com seus endereços de
memória, o nome das variáveis e os tipos de dados que ele pode suportar.

Endereço de memória Nome da variável Dado


1001 num 10
: :
1563 nome Endereço (2000)
: :
:
:
2000 "Hello"

A variável (do tipo int) num o dado é o atual valor contido por ela e, a referência da variável
(do tipo string) nome somente é armazenado o endereço de memória que contém o valor da
variável.

Introdução à Programação I 17
JEDITM

10. Operadores

Em Java temos diferentes tipos de operadores. Existem operadores aritméticos,


operadores relacionais, operadores lógicos e operadores condicionais. Estes
operadores obedecem a uma ordem de precedência para que o compilador saiba qual operação
executar primeiro, no caso de uma sentença possuir grande variedade destes.

10.1. Operadores Aritméticos

Aqui temos a lista dos operadores aritméticos que podem ser utilizados na criação de
expressões matemáticas:

Operador Uso Descrição

* op1 * op2 Multiplica op1 por op2

/ op1 / op2 Divide op1 por op2

% op1 % op2 Resto da divisão de op1 por op2

- op1 - op2 Subtrai op2 de op1

+ op1 + op2 Soma op1 e op2

Tabela 4: Operadores aritméticos e suas funções

Aqui temos um programa que exemplifica o uso destes operadores:

public class ArithmeticDemo {


public static void main(String[] args) {
// alguns números
int i = 37;
int j = 42;
double x = 27.475;
double y = 7.22;
System.out.println("Variables values...");
System.out.println(" i = " + i);
System.out.println(" j = " + j);
System.out.println(" x = " + x);
System.out.println(" y = " + y);

// adição dos números


System.out.println("Adding...");
System.out.println(" i + j = " + (i + j));
System.out.println(" x + y = " + (x + y));

// subtração dos números


System.out.println("Subtracting...");
System.out.println(" i - j = " + (i - j));
System.out.println(" x - y = " + (x - y));

// multiplicação dos números


System.out.println("Multiplying...");
System.out.println(" i * j = " + (i * j));
System.out.println(" x * y = " + (x * y));

Introdução à Programação I 18
JEDITM

// divisão dos números


System.out.println("Dividing...");
System.out.println(" i / j = " + (i / j));
System.out.println(" x / y = " + (x / y));

// resto da divisão
System.out.println("Comuting the remainder...");
System.out.println(" i % j = " + (i % j));
System.out.println(" x % y = " + (x % y));

// misturando operações
System.out.println("Mixing types...");
System.out.println(" j + y = " + (j + y));
System.out.println(" i * x = " + (i * x));
}
}

e como saída, temos:

Variables values...
i = 37
j = 42
x = 27.475
y = 7.22
Adding...
i + j = 79
x + y = 34.695
Subtracting...
i - j = -5
x - y = 20.255
Multiplying...
i * j = 1554
x * y = 198.37
Dividing...
i / j = 0
x / y = 3.8054
Comuting the remainder...
i % j = 37
x % y = 5.815
Mixing types...
j + y = 49.22
i * x = 1016.58

Nota: Quando um número de tipo inteiro e um outro de número fracionário são usados numa
única operação, o resultado será dado pela variável de maior tipo, no caso, valor de número
fracionário. O número inteiro é implicitamente convertido para o número fracionário antes da
operação ter início.

Introdução à Programação I 19
JEDITM

11. Operadores de Incremento e Decremento


Além dos operadores aritméticos básicos, Java dá suporte ao operador unário de incremento
(++) e ao operador unário de decremento (--). Operadores de incremento ou decremento
aumentam ou diminuem em 1 o valor da variável. Por exemplo, a expressão,

count = count + 1; // incrementa o valor de count em 1

é equivalente a,

count++;

Operador Uso Descrição

Incrementa op em 1; Avalia a
++ op++
expressão antes do valor ser acrescido

Incrementa op em 1; Incrementa o
++ ++op
valor antes da expressão ser avaliada
Decrementa op em 1; Avalia a
-- op-- expressão antes do valor ser
decrescido
Decrementa op em 1; Decrementa op
-- --op
em 1 antes da expressão ser avaliada

Tabela 5: Operadores de incremento e decremento

Como visto na tabela acima, os operadores de incremento e decremento podem ser usados
tanto antes como após o operando. E sua utilização dependerá disso. Quando usado antes do
operando, provoca acréscimo ou decréscimo de seu valor antes da avaliação da expressão em
que ele aparece. Por exemplo:

int i = 10,
int j = 3;
int k = 0;
k = ++j + i; //resultará em k = 4+10 = 14

Quando utilizado depois do operando, provoca, na variável, acréscimo ou decréscimo do seu


valor após a avaliação da expressão na qual ele aparece. Por exemplo:

int i = 10,
int j = 3;
int k = 0;
k = j++ + i; //resultará em k = 3+10 = 13

Dicas de programação:

1. Mantenha sempre as operações incluindo operadores de incremento ou


decremento de forma simples e de fácil compreensão.

Introdução à Programação I 20
JEDITM

12. Operadores Relacionais


Os operadores relacionais são usados para comparar dois valores e determinar o
relacionamento entre eles. A saída desta avaliação será fornecida com um valor lógico: true
ou false.

Operador Uso Descrição

> op1 > op2 op1 é maior do que op2

>= op1 >= op2 op1 é maior ou igual a op2

< op1 < op2 op1 é menor do que op2

<= op1 <= op2 op1 é menor ou igual a op2

== op1 == op2 op1 é igual a op2

!= op1 != op2 op1 não igual a op2

Tabela 6: Operadores relacionais

O programa a seguir, mostra a utilização destes operadores:

public class RelationalDemo {


public static void main(String[] args) {
// alguns números
int i = 37;
int j = 42;
int k = 42;
System.out.println("Variables values...");
System.out.println(" i = " + i);
System.out.println(" j = " + j);
System.out.println(" k = " + k);

// maior que
System.out.println("Greater than...");
System.out.println(" i > j = " + (i > j)); //false
System.out.println(" j > i = " + (j > i)); //true
System.out.println(" k > j = " + (k > j)); //false

// maior ou igual a
System.out.println("Greater than or equal to...");
System.out.println(" i >= j = " + (i >= j)); //false
System.out.println(" j >= i = " + (j >= i)); //true
System.out.println(" k >= j = " + (k >= j)); //true

// menor que
System.out.println("Less than...");
System.out.println(" i < j = " + (i < j)); //true
System.out.println(" j < i = " + (j < i)); //false
System.out.println(" k < j = " + (k < j)); //false

// menor ou igual a
System.out.println("Less than or equal to...");
System.out.println(" i <= j = " + (i <= j)); //true
System.out.println(" j <= i = " + (j <= i)); //false

Introdução à Programação I 21
JEDITM

System.out.println(" k <= j = " + (k <= j)); //true

// igual a
System.out.println("Equal to...");
System.out.println(" i == j = " + (i == j)); //false
System.out.println(" k == j = " + (k == j)); //true

// diferente
System.out.println("Not equal to...");
System.out.println(" i != j = " + (i != j)); //true
System.out.println(" k != j = " + (k != j)); //false

}
}

A seguir temos a saída deste programa:

Variables values...
i = 37
j = 42
k = 42
Greater than...
i > j = false
j > i = true
k > j = false
Greater than or equal to...
i >= j = false
j >= i = true
k >= j = true
Less than...
i < j = true
j < i = false
k < j = false
Less than or equal to...
i <= j = true
j <= i = false
k <= j = true
Equal to...
i == j = false
k == j = true
Not equal to...
i != j = true
k != j = false

Introdução à Programação I 22
JEDITM

13. Operadores Lógicos


Operadores lógicos avaliam um ou mais operandos lógicos que geram um único valor final
true ou false como resultado da expressão. São seis os operadores lógicos: && (e lógico), &
(e binário), || (ou lógico), | (ou binário), ^ (ou exclusivo binário) e ! (negação).

A operação básica para um operador lógico é:

x1 op x2

Onde x1 e x2 podem ser expressões, variáveis ou constantes lógicas, e op pode tanto ser &&,
&, ||, | ou ^.

13.1. && (e lógico) e & (e binário)

x1 x2 Resultado
VERDADEIRO VERDADEIRO VERDADEIRO
VERDADEIRO FALSO FALSO
FALSO VERDADEIRO FALSO
FALSO FALSO FALSO
Tabela 7: Tabela para && e &

A diferença básica do operador && para & é que o && suporta uma avaliação de curto-circuito
(ou avaliação parcial), enquanto que o & não. O que isso significa?

Dado o exemplo:

exp1 && exp2

o operador e lógico irá avaliar a expressão exp1, e, imediatamente, retornará um valor false
se a operação exp1 for falsa. Se a expressão exp1 resultar em um valor false o operador
nunca avaliará a expressão exp2, pois o valor de toda a expressão será falsa mesmo que o
resultado isolado de exp2 seja verdadeiro. Já o operador & sempre avalia as duas partes da
expressão, mesmo que a primeira tenha o valor false.

O programa a seguir, mostra a utilização destes operadores:

public class TestAND {


public static void main( String[] args ) {
int i = 0;
int j = 10;
boolean test = false;

// demonstração do operador &&


test = (i > 10) && (j++ > 9);
System.out.println(i);
System.out.println(j);
System.out.println(test);

// demonstração do operador &


test = (i > 10) & (j++ > 9);
System.out.println(i);
System.out.println(j);
System.out.println(test);

Introdução à Programação I 23
JEDITM

}
}

Como resultado, o programa produzirá a seguinte saída:

0
10
false
0
11
false

Note que o comando j++, na linha contendo &&, nunca será executado, pois o operador não o
avalia, visto que a primeira parte da expressão (i>10) retorna um valor booleano false.

13.2. || ( ou lógico) e | ( ou binário)

x1 x2 Resultado
VERDADEIRO VERDADEIRO VERDADEIRO
VERDADEIRO FALSO VERDADEIRO
FALSO VERDADEIRO VERDADEIRO
FALSO FALSO FALSO
Tabela 8: Tabela para || e |

A diferença básica entre os operadores || e |, é que, semelhante ao operador &&, o || também


suporta a avaliação parcial. O que isso significa?

Dada a expressão,
exp1 || exp2
o operador ou lógico irá avaliar a expressão exp1, e, imediatamente, retornará um valor
lógico true para toda a expressão se a primeira parte for avaliada como verdadeira. Se a
expressão exp1 resultar em verdadeira a segunda parte exp2 nunca será avaliada, pois o
valor final da expressão será true independentemente do resultado da segunda expressão.

O programa a seguir, mostra a utilização destes operadores:

public class TestOR {


public static void main( String[] args ){

int i = 0;
int j = 10;
boolean test = false;

// demonstração do operador ||
test = (i < 10) || (j++ > 9);
System.out.println(i);
System.out.println(j);
System.out.println(test);

// demonstração do operador |
test = (i < 10) | (j++ > 9);
System.out.println(i);
System.out.println(j);
System.out.println(test);
}

Introdução à Programação I 24
JEDITM

Como resultado, o programa produzirá a seguinte saída:

0
10
true
0
11
true

Note que a expressão j++ nunca será avaliada na instrução que usa o operador ||, pois a
primeira parte da expressão (i<10) já retorna true como valor final da expressão.

13.3. ^ (ou exclusivo binário)

x1 x2 Resultado
VERDADEIRO VERDADEIRO FALSO
VERDADEIRO FALSO VERDADEIRO
FALSO VERDADEIRO VERDADEIRO
FALSO FALSO FALSO
Tabela 9: Tabela para o operador ^

O resultado de uma expressão usando o operador ou exclusivo binário terá um valor true
somente se uma das expressões for verdadeira e a outra falsa. Note que ambos os operandos
são necessariamente avaliados pelo operador ^.

O programa a seguir, mostra a utilização deste operador:

public class TestXOR {


public static void main( String[] args ){

boolean val1 = true;


boolean val2 = true;
System.out.println(val1 ^ val2);

val1 = false;
val2 = true;
System.out.println(val1 ^ val2);

val1 = false;
val2 = false;
System.out.println(val1 ^ val2);

val1 = true;
val2 = false;
System.out.println(val1 ^ val2);
}
}

Como resultado, o programa produzirá a seguinte saída:

false
true
false
true

Introdução à Programação I 25
JEDITM

13.4. ! (negação)

x1 Resultado
VERDADEIRO FALSO
FALSO VERDADEIRO
Tabela 10: Tabela para o operador !

O operador de negação inverte o resultado lógico de uma expressão, variável ou constante,


ou seja, o que era verdadeiro será falso e vice-versa.

O programa a seguir, mostra a utilização deste operador:


public class TestNOT {
public static void main( String[] args ){
boolean val1 = true;
boolean val2 = false;
System.out.println(!val1);
System.out.println(!val2);
}
}

Como resultado, o programa produzirá a seguinte saída:

false
true

Introdução à Programação I 26
JEDITM

14. Operador Condicional ( ?: )


O operador condicional é também chamado de operador ternário. Isto significa que ele tem
3 argumentos que juntos formam uma única expressão condicional. A estrutura de uma
expressão utilizando um operador condicional é a seguinte:

exp1?exp2:exp3

Onde exp1 é uma expressão lógica que deve retornar true ou false. Se o valor de exp1 for
verdadeiro, então, o resultado será a expressão exp2, caso contrário, o resultado será exp3.

O programa a seguir, mostra a utilização deste operador:

public class ConditionalOperator {


public static void main( String[] args ){

String status = "";


int grade = 80;

//status do aluno
status = (grade >= 60)?"Passed":"Fail";

//print status
System.out.println( status );
}
}

Como resultado, o programa produzirá a seguinte saída:

Passed

Veremos na Figura 2 um fluxograma que demonstra como o operador condicional funciona.

Figura 2: Fluxograma utilizando o operador condicional

Veremos outro programa que também utiliza o operador condicional:


public class ConditionalOperator {
public static void main( String[] args ){
int score = 0;
char answer = 'a';

Introdução à Programação I 27
JEDITM

score = (answer == 'a') ? 10 : 0;


System.out.println("Score = " + score );
}
}

Como resultado, o programa produzirá a seguinte saída:

Score = 10

Introdução à Programação I 28
JEDITM

15. Precedência de Operadores


A precedência serve para indicar a ordem na qual o compilador interpretará os diferentes tipos
de operadores, para que ele sempre tenha como saída um resultado coerente e não ambíguo.

Ordem Operador
1 ( ) parênteses
2 ++ pós-incremento e -- pós-decremento
3 ++ pré-incremento e -- pré-decremento
4 ! negação lógica
5 * multiplicação e / divisão
6 % resto da divisão
7 + soma e – subtração
8 < menor que, <= menor ou igual, > maior que e >= maior ou igual
9 == igual e != não igual
10 & e binário
11 | ou binário
12 ^ ou exclusivo binário
13 && e lógico
14 || ou lógico
15 ?: condicional
16 = atribuição
Tabela 11: Precedência de operadores

No caso de dois operadores com mesmo nível de precedência, terá prioridade o que estiver
mais à esquerda da expressão. Dada uma expressão complexa como:

6%2*5+4/2+88-10

O ideal seria fazer uso de parênteses para reescrevê-la de maneira mais clara:

((6%2)*5)+(4/2)+88-10

Dicas de programação:

1. Para evitar confusão na avaliação de suas expressões matemáticas, deixe-as o


mais simples possível e use parênteses.

Introdução à Programação I 29
JEDITM

16. Exercícios
16.1. Declarar e mostrar variáveis

Dada a tabela abaixo, declare as variáveis que se seguem de acordo com seus tipos
correspondentes e valores iniciais. Exiba o nomes e valor das variáveis.

Nome das Variáveis Tipo do dado Valor inicial


number integer 10
letter character a
result boolean true
str String hello

O resultado esperado do exercício é:

number = 10
letter = a
result = true
str = hello

16.2. Obter a média entre três números

Crie um programa que obtenha a média de 3 números. Considere o valor para os três números
como sendo 10, 20 e 45. O resultado esperado do exercício é:

número 1 com o valor 10


número 2 com o valor 20
número 3 com o valor 45
A média é 25

16.3. Exibir o maior valor

Dados três números, crie um programa que exiba na tela o maior dentre os números
informados. Use o operador ?: que já foi estudado nesta sessão (dica: será necessário utilizar
dois operadores ?: para se chegar ao resultado). Por exemplo, dados os números 10, 23 e 5,
o resultado esperado do exercício deve ser:

número 1 com o valor 10


número 2 com o valor 23
número 3 com o valor 5
O maior número é 23

16.4. Precedência de operadores

Dadas as expressões abaixo, reescreva-as utilizando parênteses de acordo com a forma como
elas são interpretadas pelo compilador.

1. a / b ^ c ^ d – e + f – g * h + i
2. 3 * 10 *2 / 15 – 2 + 4 ^ 2 ^ 2
3. r ^ s * t / u – v + w ^ x – y++

Introdução à Programação I 30
Módulo 1
Introdução à Programação I

Lição 5
Capturando entrada de dados através do
teclado

Versão 1.0 - Jan/2007


JEDITM

1. Objetivos
Agora que já estudamos alguns conceitos básicos e escrevemos alguns códigos simples, vamos
fazer as aplicações ficarem mais interativas começando com a captura de dados digitados pelo
usuário. Nesta lição, discutiremos três modos de obter dados de entrada (input). O primeiro é
através do uso da classe BufferedReader do pacote java.util; o segundo, através do uso da
nova classe Scanner no mesmo pacote; e, por fim, envolveremos a utilização da interface
gráfica utilizando JOptionPane.

Ao final desta lição, o estudante será capaz de:

• Criar códigos para a captura de dados pelo teclado.


• Usar a classe BufferedReader para captura, através de uma janela de console, dos dados
digitados no teclado.
• Utilizar a classe Scanner para captura, através de uma janela de console, dos dados
digitados no teclado.
• Utilizar a classe JOptionPane para captura, através da uma interface gráfica, dos dados
digitados no teclado.

Introdução à Programação I 4
JEDITM

2. BufferedReader para capturar dados


Primeiramente, utilizaremos a classe BufferedReader do pacote java.io para capturar dados
de entrada através do teclado.

Passos para capturar os dados digitados, tomemos por base o programa visto na lição
anterior:

1. Digite a seguinte instrução no início do programa:

import java.io.*;

2. Adicione as seguintes instruções no corpo do método main:

BufferedReader dataIn = new BufferedReader(


new InputStreamReader(System.in));

3. Declare uma variável temporária do tipo String para gravar os dados digitados pelo
usuário e chame o método readLine() que vai capturar linha por linha do que o usuário digitar.
Isso deverá ser escrito dentro de um bloco try-catch para tratar possíveis exceções.

try {
String temp = dataIn.readLine();
} catch (IOException e) {
System.out.println("Error in getting input");
}

Abaixo, segue o programa completo:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class GetInputFromKeyboard {


public static void main(String[] args) {
BufferedReader dataIn = new BufferedReader(new
InputStreamReader(System.in));
String name = "";
System.out.print("Please Enter Your Name:");
try {
name = dataIn.readLine();
} catch (IOException e) {
System.out.println("Error!");
}
System.out.println("Hello " + name +"!");
}
}

Faremos uma análise deste programa linha por linha:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

Estas linhas acima mostram que estamos utilizando as classes BufferedReader,


InputStreamReader e IOException cada qual dentro do pacote java.io. Essas APIs ou

Introdução à Programação I 5
JEDITM

Interfaces de Programação de Aplicações (Application Programming Interface) contêm


centenas de classes pré-definidas que se pode usar nos programas. Essas classes são
organizadas dentro do que chamamos de pacotes.

Pacotes contêm classes que se relacionam com um determinado propósito. No exemplo, o


pacote java.io contém as classes que permitem capturar dados de entrada e saída. Estas
linhas poderiam ser reescritas da seguinte forma:

import java.io.*;

que importará todas as classes encontradas no pacote java.io, deste modo é possível utilizar
todas classes desse pacote no programa.

As próximas linhas:

public class GetInputFromKeyboard {


public static void main( String[] args ) {

já foram discutidas na lição anterior. Isso significa que declaramos uma classe nomeada
GetInputFromKeyboard e, em seguida, iniciamos o método principal (main).

Na instrução:

BufferedReader dataIn = new BufferedReader(new


InputStreamReader(System.in));

declaramos a variável dataIn do tipo BufferedReader. Não se preocupe com o significado da


sintaxe, pois será abordado mais à frente.

A seguir, declaramos a variável name do tipo String:

String name = "";

na qual armazenaremos a entrada de dados digitada pelo usuário. Note que foi inicializada
como uma String vazia "". É uma boa prática de programação inicializar as variáveis quando
declaradas.

Na próxima instrução, solicitamos que o usuário escreva um nome:

System.out.print("Please Enter Your Name:");

As seguinte linhas definem um bloco try-catch:

try {
name = dataIn.readLine();
} catch (IOException e) {
System.out.println("Error!");
}

que asseguram, caso ocorram exceções serão tratadas.

Falaremos sobre o tratamento de exceções na última parte deste curso. Por hora, é necessário
adicionar essas linhas para utilizar o método readLine() e receber a entrada de dados do
usuário.

Em seguida:

Introdução à Programação I 6
JEDITM

name = dataIn.readLine();

capturamos a entrada dos dados digitados pelo usuário e as enviamos para a variável String
criada anteriormente. A informação é guardada na variável name.

Como última instrução:

System.out.println("Hello " + name + "!");

montamos a mensagem final para cumprimentar o usuário.

Introdução à Programação I 7
JEDITM

3. Classe Scanner para capturar dados


Vimos uma maneira para obter dados de entrada através do teclado. O JDK 5.0 lançou uma
nova classe chamada Scanner que engloba diversos métodos para facilitar este serviço.

Abaixo, segue o programa completo utilizando esta classe:

import java.util.Scanner;

public class GetInputFromScanner


{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Please Enter Your Name:");
String name = sc.next();
System.out.println("Hello " + name +"!");
}
}

Compare-o com o programa visto anteriormente. Percebe-se que fica mais simples conseguir a
mesma funcionalidade.

Inicialmente, definimos a chamada ao pacote que contém a classe Scanner:

import java.util.Scanner;

Em seguida, as instruções que define a classe e o método main:

public class GetInputFromScanner


{
public static void main(String[] args) {

Definimos uma variável, denominada sc, que será criada a partir da classe Scanner e
direcionada para a entrada padrão:

Scanner sc = new Scanner(System.in);

De forma semelhante, mostramos uma mensagem solicitando informação do usuário:

System.out.println("Please Enter Your Name:");

Utilizamos a variável sc para chamarmos o método que fará o recebimento dos dados
digitados:

String name = sc.nextLine();

A classe Scanner possui diversos métodos que podem ser utilizados para realizar este serviço.
Os principais métodos que podemos utilizar, neste caso, são:

Método Finalidade
next() Aguarda uma entrada em formato String
nextInt() Aguarda uma entrada em formato Inteiro
nextByte() Aguarda uma entrada em formato Inteiro

Introdução à Programação I 8
JEDITM

nextLong() Aguarda uma entrada em formato Inteiro Longo


nextFloat() Aguarda uma entrada em formato Número Fracionário
nextDouble() Aguarda uma entrada em formato Número Fracionário
Tabela 1: Métodos da Classe Scanner para obter dados

Por fim, mostramos o resultado e encerramos o método main e a classe:

System.out.println("Hello " + name +"!");


}
}

Introdução à Programação I 9
JEDITM

4. Utilizando a JOptionPane para receber dados


Um outro modo de receber os dados de entrada é utilizar a classe JOptionPane, que pertence
ao pacote javax.swing. A JOptionPane possui métodos que conseguem criar caixas de
diálogo na qual o usuário pode informar ou visualizar algum dado.

Dado o seguinte código:

import javax.swing.JOptionPane;

public class GetInputFromKeyboard {


public static void main( String[] args ){
String name = "";
name = JOptionPane.showInputDialog("Please enter your name");
String msg = "Hello " + name + "!";
JOptionPane.showMessageDialog(null, msg);
}
}

esta classe apresentará o seguinte resultado:

Figura 1: Aguardando dados no JOptionPane

Figura 2: Digitando florence no JOptionPane

Figura 3: Respondendo com JOptionPane

A primeira instrução:

import javax.swing.JOptionPane;

mostra que estamos importando a classe JOptionPane do pacote javax.swing.

Poderíamos, de forma semelhante, escrever estas instruções do seguinte modo:

Introdução à Programação I 10
JEDITM

import javax.swing.*;

A instrução seguinte:

name = JOptionPane.showInputDialog("Please enter your name");

cria uma caixa de entrada que exibirá um diálogo com uma mensagem, um campo de texto
para receber os dados do usuário e um botão OK, conforme mostrado na figura 1. O resultado
será armazenado na variável do tipo String name.

Na próxima instrução, criamos uma mensagem de cumprimento, que ficará armazenada na


variável msg:

String msg = "Hello " + name + "!";

Finalizando a classe, exibiremos uma janela de diálogo que conterá a mensagem e o botão de
OK, conforme mostrado na figura 3.

JOptionPane.showMessageDialog(null, msg);

Introdução à Programação I 11
JEDITM

5. Exercícios
5.1. As 3 palavras (versão Console)
Utilizando a classe BufferedReader ou Scanner, capture três palavras digitadas pelo usuário
e mostre-as como uma única frase na mesma linha. Por exemplo:
Palavra 1: Goodbye
Palavra 2: and
Palavra 3: Hello

Goodbye and Hello

5.2. As 3 palavras (versão Interface Gráfica)


Utilizando a classe JOptionPane, capture palavras em três caixas de diálogos distintas e
mostre-as como uma única frase. Por exemplo:

Figura 4: Primeira Palavra

Figura 5: Segunda Palavra Figura 7: Mostrando a Mensagem

Figura 6: Terceira Palavra

Introdução à Programação I 12
Módulo 1
Introdução à Programação I

Lição 6
Estruturas de controle

Versão 1.01 - Fev/2008


JEDITM

1. Objetivos
Nas lições anteriores, foram mostrados programas seqüenciais, onde as instruções foram
executadas uma após a outra de forma fixa. Nesta lição, discutiremos estruturas de controle
que permitem mudar a ordem na qual as instruções são executadas.

Ao final desta lição, o estudante será capaz de:

• Usar estruturas de controle de decisão (if e switch) que permitem a seleção de partes
específicas do código para execução
• Usar estruturas de controle de repetição (while, do-while e for) que permitem a
repetição da execução de partes específicas do código
• Usar declarações de interrupção (break, continue e return) que permitem o
redirecionamento do fluxo do programa

Introdução à Programação I 4
JEDITM

2. Estruturas de controle de decisão


Estruturas de controle de decisão são instruções em linguagem Java que permitem que blocos
específicos de código sejam escolhidos para serem executados, redirecionando determinadas
partes do fluxo do programa.

2.1. Declaração if
A declaração if especifica que uma instrução ou bloco de instruções seja executado se, e
somente se, uma expressão lógica for verdadeira.

A declaração if possui a seguinte forma:

if (expressão_lógica)
instrução;

ou:

if (expressão_lógica) {
instrução1;
instrução2
...
}

onde, expressão_lógica representa uma expressão ou variável lógica.

Figura 1: Fluxograma da declaração if

Por exemplo, dado o trecho de código:


int grade = 68;
if (grade > 60) System.out.println("Congratulations!");

ou:
int grade = 68;
if (grade > 60) {
System.out.println("Congratulations!");
System.out.println("You passed!");
}

Introdução à Programação I 5
JEDITM

Dicas de programação:

1. Expressão lógica é uma declaração que possui um valor lógico. Isso significa que
a execução desta expressão deve resultar em um valor true ou false.
2. Coloque as instruções de forma que elas façam parte do bloco if. Por exemplo:

if (expressão_lógica) {
// instrução1;
// instrução2;
}

2.2. Declaração if-else

A declaração if-else é usada quando queremos executar determinado conjunto de instruções


se a condição for verdadeira e outro conjunto se a condição for falsa.

Possui a seguinte forma:

if (expressão_lógica)
instrução_caso_verdadeiro;
else
instrução_caso_falso;

Também podemos escrevê-la na forma abaixo:

if (expressão_lógica) {
instrução_caso_verdadeiro1;
instrução_caso_verdadeiro2;
...
} else {
instrução_caso_falso1;
instrução_caso_falso2;
...
}

Por exemplo, dado o trecho de código:

int grade = 68;


if (grade > 60)
System.out.println("Congratulations! You passed!");
else
System.out.println("Sorry you failed");

ou:

int grade = 68;


if (grade > 60) {
System.out.print("Congratulations! ");
System.out.println("You passed!");
} else {
System.out.print("Sorry ");
System.out.println("you failed");
}

Introdução à Programação I 6
JEDITM

Figura 2: Fluxograma da declaração if-else

Dicas de programação:

1. Para evitar confusão, sempre coloque a instrução ou instruções contidas no


bloco if ou if-else entre chaves {}.
2. Pode-se ter declarações if-else dentro de declarações if-else, por exemplo:

if (expressão_lógica) {
if (expressão_lógica) {
...
} else {
...
}
} else {
...
}

2.3. Declaração if-else-if


A declaração else pode conter outra estrutura if-else. Este cascateamento de estruturas
permite ter decisões lógicas muito mais complexas.

A declaração if-else-if possui a seguinte forma:

if (expressão_lógica1)
instrução1;
else if(expressão_lógica2)
instrução2;
else
instrução3;

Podemos ter várias estruturas else-if depois de uma declaração if. A estrutura else é opcional
e pode ser omitida. No exemplo mostrado acima, se a expressão_lógica1 é verdadeira, o
programa executa a instrução1 e salta as outras instruções. Caso contrário, se a
expressão_lógica1 é falsa, o fluxo de controle segue para a análise da expressão_lógica2.
Se esta for verdadeira, o programa executa a instrução2 e salta a instrução3. Caso
contrário, se a expressão_lógica2 é falsa, então a instrução3 é executada.

Introdução à Programação I 7
JEDITM

Figura 3: Fluxograma da declaração if-else-if

Observe um exemplo da declaração if-else-if no seguinte trecho de código:

public class Grade {


public static void main( String[] args ) {
double grade = 92.0;
if (grade >= 90) {
System.out.println("Excellent!");
} else if((grade < 90) && (grade >= 80)) {
System.out.println("Good job!");
} else if((grade < 80) && (grade >= 60)) {
System.out.println("Study harder!");
} else {
System.out.println("Sorry, you failed.");
}
}
}

2.4. Erros comuns na utilização da declaração if

1. A condição na declaração if não avalia um valor lógico. Por exemplo:

// ERRADO
int number = 0;
if (number) {
// algumas instruções aqui
}

a variável number não tem valor lógico.

2. Usar = (sinal de atribuição) em vez de == (sinal de igualdade) para comparação. Por


exemplo:

Introdução à Programação I 8
JEDITM

// ERRADO
int number = 0;
if (number = 0) {
// algumas instruções aqui
}

3. Escrever elseif em vez de else if.

// ERRADO
int number = 0;
if (number == 0) {
// algumas instruções aqui
} elseif (number == 1) {
// algumas instruções aqui
}

2.5. Declaração switch

Outra maneira de indicar uma condição é através de uma declaração switch. A construção
switch permite que uma única variável inteira tenha múltiplas possibilidades de finalização.

A declaração switch possui a seguinte forma:

switch (variável_inteira) {
case valor1:
instrução1; //
instrução2; // bloco 1
... //
break;
case valor2:
instrução1; //
instrução2; // bloco 2
... //
break;
default:
instrução1; //
instrução2; // bloco n
... //
break;
}

onde, variável_inteira é uma variável de tipo byte, short, char ou int. valor1, valor2, e
assim por diante, são valores constantes que esta variável pode assumir.

Quando a declaração switch é encontrada, o fluxo de controle avalia inicialmente a


variável_inteira e segue para o case que possui o valor igual ao da variável. O programa
executa todas instruções a partir deste ponto, mesmo as do próximo case, até encontrar uma
instrução break, que interromperá a execução do switch.

Se nenhum dos valores case for satisfeito, o bloco default será executado. Este é um bloco
opcional. O bloco default não é obrigatório na declaração switch.

Introdução à Programação I 9
JEDITM

Notas:

1. Ao contrário da declaração if, múltiplas instruções são executadas sem a


necessidade das chaves que determinam o início e término de bloco {}.
2. Quando um case for selecionado, todas as instruções vinculadas ao case serão
executadas. Além disso, as instruções dos case seguintes também serão
executadas.
3. Para prevenir que o programa execute instruções dos outros case
subseqüentes, utilizamos a declaração break após a última instrução de cada
case.

Dicas de Programação:

1. A decisão entre usar uma declaração if ou switch é subjetiva. O programador


pode decidir com base na facilidade de entendimento do código, entre outros
fatores.
2. Uma declaração if pode ser usada para decisões relacionadas a conjuntos,
escalas de variáveis ou condições, enquanto que a declaração switch pode ser
utilizada para situações que envolvam variável do tipo inteiro. Também é
necessário que o valor de cada cláusula case seja único.

Figura 4: Fluxograma da declaração switch

2.6. Exemplo para switch


public class Grade {
public static void main(String[] args) {

Introdução à Programação I 10
JEDITM

int grade = 92;


switch(grade) {
case 100:
System.out.println("Excellent!");
break;
case 90:
System.out.println("Good job!");
break;
case 80:
System.out.println("Study harder!");
break;
default:
System.out.println("Sorry, you failed.");
}
}
}

Compile e execute o programa acima e veremos que o resultado será:

Sorry, you failed.

pois a variável grade possui o valor 92 e nenhuma das opções case atende a essa condição.
Note que para o caso de intervalos a declaração if-else-if é mais indicada.

Introdução à Programação I 11
JEDITM

3. Estruturas de controle de repetição


Estruturas de controle de repetição são comandos em linguagem Java que permitem executar
partes específicas do código determinada quantidade de vezes. Existem 3 tipos de estruturas
de controle de repetição: while, do-while e for.

3.1. Declaração while


A declaração while executa repetidas vezes um bloco de instruções enquanto uma
determinada condição lógica for verdadeira.

A declaração while possui a seguinte forma:

while (expressão_lógica) {
instrução1;
instrução2;
...
}

Figura 5: Fluxograma da declaração while

As instruções contidas dentro do bloco while são executadas repetidas vezes enquanto o valor
de expressão_lógica for verdadeira.

Por exemplo, dado o trecho de código:

int i = 4;
while (i > 0){
System.out.print(i);
i--;
}

O código acima irá imprimir 4321 na tela. Se a linha contendo a instrução i-- for removida,
teremos uma repetição infinita, ou seja, um código que não termina. Portanto, ao usar laços
while, ou qualquer outra estrutura de controle de repetição, tenha a certeza de utilizar uma
estrutura de repetição que encerre em algum momento.

Abaixo, temos outros exemplos de declarações while:

Exemplo 1:

int x = 0;
while (x<10) {
System.out.println(x);

Introdução à Programação I 12
JEDITM

x++;
}

Exemplo 2:

// laço infinito
while (true)
System.out.println("hello");

Exemplo 3:

// a instrução do laço não será executada


while (false)
System.out.println("hello");

3.2. Declaração do-while


A declaração do-while é similar ao while. As instruções dentro do laço do-while serão
executadas pelo menos uma vez.

A declaração do-while possui a seguinte forma:

do {
instrução1;
instrução2;
...
} while (expressão_lógica);

Figura 6: Fluxograma da declaração do-while

Inicialmente, as instruções dentro do laço do-while são executadas. Então, a condição na


expressão_lógica é avaliada. Se for verdadeira, as instruções dentro do laço do-while serão
executadas novamente.

A diferença entre uma declaração while e do-while é que, no laço while, a avaliação da
expressão lógica é feita antes de se executarem as instruções nele contidas enquanto que, no
laço do-while, primeiro se executam as instruções e depois realiza-se a avaliação da
expressão lógica, ou seja, as instruções dentro em um laço do-while são executadas pelo
menos uma vez.

Abaixo, temos alguns exemplos que usam a declaração do-while:

Exemplo 1:

int x = 0;

Introdução à Programação I 13
JEDITM

do {
System.out.println(x);
x++;
} while (x<10);

Este exemplo terá 0123456789 escrito na tela.

Exemplo 2:

// laço infinito
do {
System.out.println("hello");
} while(true);

Este exemplo mostrará a palavra hello escrita na tela infinitas vezes.

Exemplo 3:

// Um laço executado uma vez


do
System.out.println(“hello”);
while (false);

Este exemplo mostrará a palavra hello escrita na tela uma única vez.

Dicas de programação:

1. Erro comum de programação ao utilizar o laço do-while é esquecer o ponto-e-


vírgula (;) após a declaração while.

do {
...
} while (boolean_expression) // ERRADO -> faltou ;

2. Como visto para a declaração while, tenha certeza que a declaração do-while
poderá terminar em algum momento.

3.3. Declaração for


A declaração for, como nas declarações anteriores, permite a execução do mesmo código uma
quantidade determinada de vezes.

A declaração for possui a seguinte forma:

for (declaração_inicial; expressão_lógica; salto) {


instrução1;
instrução2;
...
}

onde:

declaração_inicial – inicializa uma variável para o laço


expressão_lógica – compara a variável do laço com um valor limite

Introdução à Programação I 14
JEDITM

salto – atualiza a variável do laço

Figura 7: Fluxograma da declaração for

Um exemplo para a declaração for é:

for (int i = 0; i < 10; i++) {


System.out.print(i);
}

Neste exemplo, uma variável i, do tipo int, é inicializada com o valor zero. A expressão lógica
"i é menor que 10" é avaliada. Se for verdadeira, então a instrução dentro do laço é
executada. Após isso, a expressão i terá seu valor adicionado em 1 e, novamente, a condição
lógica será avaliada. Este processo continuará até que a condição lógica tenha o valor falso.

Este mesmo exemplo, utilizando a declaração while, é mostrado abaixo:

int i = 0;
while (i < 10) {
System.out.print(i);
i++;
}

Introdução à Programação I 15
JEDITM

4. Declarações de Interrupção
Declarações de interrupção permitem que redirecionemos o fluxo de controle do programa. A
linguagem Java possui três declarações de interrupção. São elas: break, continue e return.

4.1. Declaração break


A declaração break possui duas formas: unlabeled (não identificada - vimos esta forma com
a declaração switch) e labeled (identificada).

4.1.1. Declaração unlabeled break


A forma unlabeled de uma declaração break encerra a execução de um switch e o fluxo de
controle é transferido imediatamente para o final deste. Podemos também utilizar a forma
para terminar declarações for, while ou do-while.

Por exemplo:

String names[] = {"Beah", "Bianca", "Lance", "Belle",


"Nico", "Yza", "Gem", "Ethan"};
String searchName = "Yza";
boolean foundName = false;
for (int i=0; i < names.length; i++) {
if (names[i].equals(searchName)) {
foundName = true;
break;
}
}
if (foundName) {
System.out.println(searchName + " found!");
} else {
System.out.println(searchName + " not found.");
}

Neste exemplo, se a String “Yza” for encontrada, a declaração for será interrompida e o
controle do programa será transferido para a próxima instrução abaixo da declaração for.

4.1.2. Declaração labeled break


A forma labeled de uma declaração break encerra o processamento de um laço que é
identificado por um label especificado na declaração break.

Um label, em linguagem Java, é definido colocando-se um nome seguido de dois-pontos,


como por exemplo:

teste:

esta linha indica que temos um label com o nome teste.

O programa a seguir realiza uma pesquisa de um determinado valor em um array


bidimensional. Dois laços são criados para percorrer este array. Quando o valor é encontrado,
um labeled break termina a execução do laço interno e retorna o controle para o laço mais
externo.

int[][] numbers = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};


int searchNum = 5;

Introdução à Programação I 16
JEDITM

boolean foundNum = false;


searchLabel: for (int i=0; i<numbers.length; i++) {
for (int j=0; j<numbers[i].length; j++) {
if (searchNum == numbers[i][j]) {
foundNum = true;
break searchLabel;
}
} // final do laço j
} // final do laço i
if (foundNum) {
System.out.println(searchNum + " found!");
} else {
System.out.println(searchNum + " not found!");
}

A declaração break, ao terminar a declaração for, não transfere o controle do programa ao


final de seu laço, controlado pela variável j. O controle do programa segue imediatamente
para a declaração for marcada com o label, neste caso, interrompendo o laço controlado pela
variável i.

4.2. Declaração continue


A declaração continue tem duas formas: unlabeled e labeled. Utilizamos uma declaração
continue para saltar a repetição atual de declarações for, while ou do-while.

4.2.1. Declaração unlabeled continue


A forma unlabeled salta as instruções restantes de um laço e avalia novamente a expressão
lógica que o controla.

O exemplo seguinte conta a quantidade de vezes que a expressão "Beah" aparece no array.

String names[] = {"Beah", "Bianca", "Lance", "Beah"};


int count = 0;
for (int i=0; i < names.length; i++) {
if (!names[i].equals("Beah")) {
continue; // retorna para a próxima condição
}
count++;
}
System.out.println(count + " Beahs in the list");

4.2.2. Declaração labeled continue


A forma labeled da declaração continue interrompe a repetição atual de um laço e salta para
a repetição exterior marcada com o label indicado.

outerLoop: for (int i=0; i<5; i++) {


for (int j=0; j<5; j++) {
System.out.println("Inside for(j) loop"); // mensagem1
if (j == 2)
continue outerLoop;
}
System.out.println("Inside for(i) loop"); // mensagem2
}

Neste exemplo, a mensagem 2 nunca será mostrada, pois a declaração continue outerloop
interromperá este laço cada vez que j atingir o valor 2 do laço interno.

Introdução à Programação I 17
JEDITM

4.3. Declaração return


A declaração return é utilizada para sair de um método. O fluxo de controle retorna para a
declaração que segue a chamada do método original. A declaração de retorno possui dois
modos: o que retorna um valor e o que não retorna nada.

Para retornar um valor, escreva o valor (ou uma expressão que calcula este valor) depois da
palavra chave return. Por exemplo:

return ++count;
ou
return "Hello";

Os dados são processados e o valor é devolvido de acordo com o tipo de dado do método.
Quando um método não tem valor de retorno, deve ser declarado como void. Use a forma de
return que não devolve um valor. Por exemplo:

return;

Abordaremos as declarações return nas próximas lições, quando falarmos sobre métodos.

Introdução à Programação I 18
JEDITM

5. Exercícios
5.1. Notas
Obtenha do usuário três notas de exame e calcule a média dessas notas. Reproduza a média
dos três exames. Junto com a média, mostre também um :-) no resultado se a média for
maior ou igual a 60; caso contrário mostre :-(

Faça duas versões deste programa:

1. Use a classe BufferedReader (ou a classe Scanner) para obter as notas do usuário, e
System.out para mostrar o resultado.
2. Use JOptionPane para obter as notas do usuário e para mostrar o resultado.

5.2. Número por Extenso


Solicite ao usuário para digitar um número, e mostre-o por extenso. Este número deverá
variar entre 1 e 10. Se o usuário introduzir um número que não está neste intervalo, mostre:
"número inválido".

Faça duas versões deste programa:

1. Use uma declaração if-else-if para resolver este problema


2. Use uma declaração switch para resolver este problema

5.3. Cem vezes


Crie um programa que mostre seu nome cem vezes. Faça três versões deste programa:

1. Use uma declaração while para resolver este problema


2. Use uma declaração do-while para resolver este problema
3. Use uma declaração for para resolver este problema

5.4. Potências
Receba como entrada um número e um expoente. Calcule este número elevado ao expoente.
Faça três versões deste programa:

1. Use uma declaração while para resolver este problema


2. Use uma declaração do-while para resolver este problema
3. Use uma declaração for para resolver este problema

Introdução à Programação I 19
Módulo 1
Introdução à Programação I

Lição 7
Array em Java

Versão 1.01 - Fev/2008


JEDITM

1. Objetivos
Nesta lição, abordaremos Array em Java. Primeiro, definiremos o que é array e, então,
discutiremos como declará-los e usá-los.

Ao final desta lição, o estudante será capaz de:

• Declarar e criar array


• Acessar elementos de um array
• Determinar o número de elementos de um array
• Declarar e criar array multidimensional

Introdução à Programação I 4
JEDITM

2. Introdução a Array
Em lições anteriores, discutimos como declarar diferentes variáveis usando os tipos de dados
primitivos. Na declaração de variáveis, freqüentemente utilizamos um identificador ou um
nome e um tipo de dados. Para se utilizar uma variável, deve-se chamá-la pelo nome que a
identifica.

Por exemplo, temos três variáveis do tipo int com diferentes identificadores para cada
variável:

int number1;
int number2;
int number3;

number1 = 1;
number2 = 2;
number3 = 3;

Como se vê, inicializar e utilizar variáveis pode torna-se uma tarefa tediosa, especialmente se
elas forem utilizadas para o mesmo objetivo. Em Java, e em outras linguagens de
programação, pode-se utilizar uma variável para armazenar e manipular uma lista de dados
com maior eficiência. Este tipo de variável é chamado de array.

Figura 1: Exemplo de um array de inteiros

Um array armazena múltiplos itens de um mesmo tipo de dado em um bloco contínuo de


memória, dividindo-o em certa quantidade de posições. Imagine um array como uma variável
esticada – que tem um nome que a identifica e que pode conter mais de um valor para esta
mesma variável.

Introdução à Programação I 5
JEDITM

3. Declarando Array
Array precisa ser declarados como qualquer variável. Ao declarar um array, defina o tipo de
dados deste seguido por colchetes [] e pelo nome que o identifica. Por exemplo:

int [] ages;

ou colocando os colchetes depois do identificador. Por exemplo:

int ages[];

Depois da declaração, precisamos criar o array e especificar seu tamanho. Este processo é
chamado de construção (a palavra, em orientação a objetos, para a criação de objetos). Para
se construir um objeto, precisamos utilizar um construtor. Por exemplo:

// declaração
int ages[];

// construindo
ages = new int[100];

ou, pode ser escrito como:

// declarar e construir
int ages[] = new int[100];

No exemplo, a declaração diz ao compilador


Java que o identificador ages será usado como
um nome de um array contendo inteiros, usado
para criar, ou construir, um novo array
contendo 100 elementos.

Em vez de utilizar uma nova linha de instrução


para construir um array, também é possível
automaticamente declarar, construir e adicionar
um valor uma única vez. Figura 2: Instanciando Arrays

Exemplos:

// criando um array de valores lógicos em uma variável


// results. Este array contém 4 elementos que são
// inicializados com os valores {true, false, true, false}
boolean results[] ={ true, false, true, false };

// criando um array de 4 variáveis double inicializados


// com os valores {100, 90, 80, 75};
double []grades = {100, 90, 80, 75};

// criando um array de Strings com identificador days e


// também já inicializado. Este array contém 7 elementos
String days[] = {"Mon","Tue","Wed","Thu","Fri","Sat","Sun"};

Uma vez que tenha sido inicializado, o tamanho de um array não pode ser modificado, pois é
armazenado em um bloco contínuo de memória.

Introdução à Programação I 6
JEDITM

4. Acessando um elemento do Array


Para acessar um elemento do array, ou parte de um array, utiliza-se um número inteiro
chamado de índice.

Um índice é atribuído para cada membro de um array, permitindo ao programa e ao


programador acessar os valores individualmente quando necessário. Os números dos índices
são sempre inteiros. Eles começam com zero e progridem seqüencialmente por todas as
posições até o fim do array. Lembre-se que os elementos dentro do array possuem índice de 0
a tamanhoDoArray-1.

Por exemplo, dado o array ages que declaramos anteriormente, temos:

// atribuir 10 ao primeiro elemento do array


ages[0] = 10;

// imprimir o último elemento do array


System.out.print(ages[99]);

Lembre-se que o array, uma vez declarado e construído, terá o valor de cada membro
inicializado automaticamente. Conforme a seguinte tabela:

Tipo primitivo Iniciado com


boolean false
byte, short e int 0
char '\u0000'
long 0L
float 0.0F
double 0.0
Tabela 1: Valor de inicialização automatica para os tipos primitivos

Entretanto, tipos de dados por referência, como as Strings, não serão inicializados caracteres
em branco ou com uma string vazia "", serão inicializados com o valor null. Deste modo, o
ideal é preencher os elementos do arrays de forma explícita antes de utilizá-los. A manipulação
de objetos nulos pode causar a desagradável surpresa de uma exceção do tipo
NullPointerException, por exemplo, ao tentar executar algum método da classe String,
conforme o exemplo a seguir:

public class ArraySample {


public static void main(String[] args){
String [] nulls = new String[2];
System.out.print(nulls[0]); // Linha correta, mostra null
System.out.print(nulls[1].trim()); // Causa erro
}
}

O código abaixo utiliza uma declaração for para mostrar todos os elementos de um array.

public class ArraySample {


public static void main(String[] args){
int[] ages = new int[100];
for (int i = 0; i < 100; i++) {
System.out.print(ages[i]);

Introdução à Programação I 7
JEDITM

}
}
}

Dicas de programação:

1. Normalmente, é melhor inicializar, ou instanciar, um array logo após declará-lo.


Por exemplo, a instrução:

int []arr = new int[100];

é preferível, ao invés de:

int [] arr;
arr = new int[100];

2. Os elementos de um array de n elementos tem índices de 0 a n-1. Note que não


existe o elemento arr[n]. A tentativa de acesso a este elemento causará uma
exceção do tipo ArrayIndexOutOfBoundsException, pois o índice deve ser
até n-1.
3. Não é possível modificar o tamanho de um array.

Introdução à Programação I 8
JEDITM

5. Tamanho de Array
Para se obter o número de elementos de um array, pode-se utilizar o atributo length. O
atributo length de um array retorna seu tamanho, ou seja, a quantidade de elementos. É
utilizado como no código abaixo:

nomeArray.length

Por exemplo, dado o código anterior, podemos reescrevê-lo como:

public class ArraySample {


public static void main (String[] args) {
int[] ages = new int[100];
for (int i = 0; i < ages.length; i++) {
System.out.print(ages[i]);
}
}
}

Dicas de programação:

1. Quando criar laços com for para o processamento de um array, utilize o campo
length como argumento da expressão lógica. Isto irá permitir ao laço ajustar-
se, automaticamente para tamanhos de diferentes arrays.
2. Declare o tamanho dos arrays utilizando variáveis do tipo constante para facilitar
alterações posteriores. Por exemplo:

final int ARRAY_SIZE = 1000; // declarando uma constante


...
int[] ages = new int[ARRAY_SIZE];

Introdução à Programação I 9
JEDITM

6. Arrays Multidimensionais
Arrays multidimensionais são implementados como arrays dentro de arrays. São declarados ao
atribuir um novo conjunto de colchetes depois do nome do array. Por exemplo:

// array inteiro de 512 x 128 elementos


int [][] twoD = new int[512][128];

// array de caracteres de 8 x 16 x 24
char [][][] threeD = new char[8][16][24];

// array de String de 4 linhas x 2 colunas


String [][] dogs = {{"terry", "brown"},
{"Kristin", "white"},
{"toby", "gray"},
{"fido", "black"}};

Acessar um elemento em um array multidimensional é semelhante a acessar elementos em


um array de uma dimensão. Por exemplo, para acessar o primeiro elemento da primeira linha
do array dogs, escreve-se:

System.out.print(dogs[0][0]);

Isso mostrará a String "terry" na saída padrão. Caso queira mostrar todos os elementos deste
array, escreve-se:

for (int i = 0; i < dogs.length; i++) {


for (int j = 0; j < dogs[i].length; j++) {
System.out.print(dogs[i][j] + " ");
}
}

Introdução à Programação I 10
JEDITM

7. Exercícios

7.1. Dias da semana


Criar um array de Strings inicializado com os nomes dos sete dias da semana. Por exemplo:

String days[] = {"Monday", "Tuesday", "Wednesday", "Thursday",


"Friday", "Saturday", "Sunday"};

Usando uma declaração while, imprima todo o conteúdo do array. Faça o mesmo para as
declarações do-while e for.

7.2. Maior número


Usando as classes BufferedReader, Scanner ou JOptionPane, solicite 10 números ao
usuário. Utilize um array para armazenar o valor destes números. Mostre o número de maior
valor.

7.3. Entradas de agenda telefônica


Dado o seguinte array multidimensional, que contém as entradas da agenda telefônica:

String entry = {{"Florence", "735-1234", "Manila"},


{"Joyce", "983-3333", "Quezon City"},
{"Becca", "456-3322", "Manila"}};

mostre-as conforme o formato abaixo:

Name : Florence
Tel. # : 735-1234
Address: Manila

Name : Joyce
Tel. # : 983-3333
Address: Quezon City

Name : Becca
Tel. # : 456-3322
Address: Manila

Introdução à Programação I 11
Módulo 1
Introdução à Programação I

Lição 8
Argumentos de linha de comando

Versão 1.0 - Jan/2007


JEDITM

1. Objetivos
Nesta lição, aprenderemos sobre como processar a entrada que vem da linha de comando
usando argumentos passados para um programa feito em Java.

Ao final desta lição, o estudante será capaz de:


• Utilizar o argumento de linha de comando
• Receber dados enviados pelo usuário utilizando os argumentos de linha de comando
• Aprender como passar argumentos para os programas no NetBeans

Introdução à Programação I 4
JEDITM

2. Argumentos de linha de comando


Uma aplicação em Java aceita qualquer quantidade de argumentos passados pela linha de
comando. Argumentos de linha de comando permitem ao usuário modificar a operação de uma
aplicação a partir de sua execução. O usuário insere os argumentos na linha de comando no
momento da execução da aplicação. Deve-se lembrar que os argumentos de linha de comando
são especificados depois do nome da classe a ser executada.

Por exemplo, suponha a existência de uma aplicação Java, chamada Sort, que ordena cinco
números que serão recebidos. Essa aplicação seria executada da seguinte maneira:

java Sort 5 4 3 2 1

Lembre-se que os argumentos são separados por espaços.

Em linguagem Java, quando uma aplicação é executada, o sistema repassa os argumentos da


linha de comando para a o método main da aplicação através de um array de String. Cada
elemento deste array conterá um dos argumentos de linha de comando passados. Lembre-se
da declaração do método main:

public static void main(String[] args) {


}

Os argumento que são passados para o programa são salvos em um array de String com o
identificador args. No exemplo anterior, os argumentos de linha de comando passados para a
aplicação Sort estarão em um array que conterá cinco strings: "5", "4", "3", "2" e "1". É
possível conhecer o número de argumentos passados pela linha de comando utilizando-se o
atributo length do array.

Por exemplo:

int numberOfArgs = args.length;

Se o programa precisa manipular argumento de linha de comando numérico, então, deve-se


converter o argumento do tipo String, que representa um número, assim como "34", para um
número. Aqui está a parte do código que converte um argumento de linha de comando para
inteiro:

int firstArg = 0;
if (args.length > 0) {
firstArg = Integer.parseInt(args[0]);
}

parseInt dispara uma exceção do tipo NumberFormatException se o conteúdo do elemento


arg[0] não for um número.

Dicas de programação:

1. Antes de usar os argumentos de linha de comando, observe a quantidade de


argumentos passados para a aplicação. Deste modo, nenhuma exceção será
disparada.

Introdução à Programação I 5
JEDITM

3. Argumentos de linha de comando no NetBeans


Para ilustrar a passagem de alguns argumentos para um projeto no NetBeans, vamos criar um
projeto em Java que mostrará na tela o número de argumentos e o primeiro argumento
passado.

public class CommandLineExample {


public static void main( String[] args ) {
System.out.println("Number of arguments=" +
args.length);
System.out.println("First Argument="+ args[0]);
}
}

Abra o NetBeans, crie um novo projeto e dê o nome de CommandLineExample. Copie o


código mostrado anteriormente e o compile. Em seguida, siga estas etapas para passar
argumentos para o programa, utilizando o NetBeans.

Figura 1: Abrindo o projeto

Dê um clique com o botão direito do mouse no ícone CommandLineExample, conforme


destacado na Figura 1. Um menu aparecerá, conforme a Figura 2. Selecione a opção
"Properties".

Introdução à Programação I 6
JEDITM

Figura 2: Abrindo a janela de propriedades

A janela "Project Properties" irá aparecer, conforme a Figura 3.

Figura 3: Janela de propriedades

Acesse a opção Run ⇒ Running Project.

Introdução à Programação I 7
JEDITM

Figura 4: Acessando através de Running Project

Na caixa de texto dos argumentos, digite os argumentos que se quer passar para o programa.
Neste caso, digitamos os argumentos 5 4 3 2 1. Pressione o botão OK.

Figura 5: Salvando os Argumentos de Linha de Comando

Introdução à Programação I 8
JEDITM

Execute o projeto.

Figura 6: Executando o programa com botão de atalho

Como pode-se ver, a saída do projeto é a quantidade de argumentos, que é 5, e o primeiro


argumento passado, que também é 5.

Figura 7: Saída do Programa

Introdução à Programação I 9
JEDITM

4. Exercícios
4.1. Argumentos de Exibição
Utilizando os dados passados pelo usuário através dos argumentos de linha de comando, exiba
os argumentos recebidos. Por exemplo, se o usuário digitar:

java Hello world that is all

o programa deverá mostrar na tela:

world
that
is
all

4.2. Operações aritméticas


Obtenha dois números, passados pelo usuário usando argumentos de linha de comando, e
mostre o resultado da soma, subtração, multiplicação e divisão destes números. Por exemplo,
se o usuário digitar:

java ArithmeticOperation 20 4

o programa deverá mostrar na tela:

sum = 24
subtraction = 16
multiplication = 80
division = 5

Introdução à Programação I 10
Módulo 1
Introdução à Programação I

Lição 9
Trabalhando com Bibliotecas de Classe

Versão 1.0 - Jan/2007


JEDITM

1. Objetivos
Nesta lição, abordaremos alguns conceitos básicos da Programação Orientada a Objetos ou
POO. Mais adiante, discutiremos o conceito de classes e objetos e como usar as classes e seus
membros. Comparação, conversão e casting de objetos, também serão vistos. Por enquanto, o
foco será o uso das classes já definidas nas bibliotecas Java e, posteriormente, discutiremos
como criar nossas próprias classes.

Ao final desta lição, o estudante será capaz de:

• Explicar o que é Programação Orientada a Objetos e alguns dos seus conceitos


• Diferenciar entre classes e objetos
• Diferenciar atributos e métodos de objeto de atributos e métodos de classe
• Explicar o que são métodos, como invocá-los e como enviar argumentos
• Identificar o escopo de um atributo
• Realizar conversões entre tipos de dados primitivos e entre objetos
• Comparar objetos e determinar suas classes

Introdução à Programação I 4
JEDITM

2. Introdução à Programação Orientada a Objeto


Programação Orientada a Objetos (POO) refere-se ao conceito de objetos como elemento
básico das classes. O mundo físico é constituído por objetos tais como carro, leão, pessoa,
dentre outros. Estes objetos são caracterizados pelas suas propriedades (ou atributos) e
seus comportamentos.

Por exemplo, um objeto "carro" tem as propriedades, tipo de câmbio, fabricante e cor. O seu
comportamento pode ser 'virar', 'frear' e 'acelerar'. Igualmente, podemos definir diferentes
propriedades e comportamentos para um leão. Veja exemplos na Tabela 1.

Objeto Propriedades Comportamentos


carro tipo de câmbio virar
fabricante frear
cor acelerar
leão peso rugir
cor dormir
apetite (faminto ou saciado) caçar
temperamento (dócil ou selvagem)
Tabela 1: Exemplos de objetos do mundo real

Com tais descrições, os objetos do mundo físico podem ser facilmente modelados como
objetos de software usando as propriedades como atributos e os comportamentos como
métodos. Estes atributos e métodos podem ser usados em softwares de jogos ou interativos
para simular objetos do mundo real! Por exemplo, poderia ser um objeto de 'carro' numa
competição de corrida ou um objeto de 'leão' num aplicativo educacional de zoologia para
crianças.

Introdução à Programação I 5
JEDITM

3. Classes e Objetos
3.1. Diferenças entre Classes e Objetos
No mundo do computador, um objeto é um componente de software cuja estrutura é similar a
um objeto no mundo real. Cada objeto é composto por um conjunto de atributos
(propriedades) que são as variáveis que descrevem as características essenciais do objeto e,
consiste também, num conjunto de métodos (comportamentos) que descrevem como o
objeto se comporta. Assim, um objeto é uma coleção de atributos e métodos relacionados. Os
atributos e métodos de um objeto Java são formalmente conhecidos como atributos e
métodos de objeto, para distinguir dos atributos e métodos de classes, que serão discutidos
mais adiante.

A classe é a estrutura fundamental na Programação Orientada a Objetos. Ela pode ser


pensada como um gabarito, um protótipo ou, ainda, uma planta para a construção de um
objeto. Ela consiste em dois tipos de elementos que são chamados atributos (ou
propriedades) e métodos. Atributos especificam os tipos de dados definidos pela classe,
enquanto que os métodos especificam as operações. Um objeto é uma instância de uma
classe.

Para diferenciar entre classes e objetos, vamos examinar um exemplo. O que temos aqui é
uma classe Carro que pode ser usada pra definir diversos objetos do tipo carro. Na tabela
mostrada abaixo, Carro A e Carro B são objetos da classe Carro. A classe tem os campos
número da placa, cor, fabricante e velocidade que são preenchidos com os valores
correspondentes do carro A e B. O carro também tem alguns métodos: acelerar, virar e frear.

Classe Carro Objeto Carro A Objeto Carro B


Número da placa ABC 111 XYZ 123

Atributos de Cor Azul Vermelha


Objeto Fabricante Mitsubishi Toyota
Velocidade 50 km/h 100 km/h
Método Acelerar
Métodos de
Método Girar
Objeto
Método Frear
Tabela 2: Exemplos da classe Carro e seus objetos

Quando construídos, cada objeto adquire um conjunto novo de estado. Entretanto, as


implementações dos métodos são compartilhadas entre todos os objetos da mesma classe.

As classes fornecem o benefício do Reutilização de Classes (ou seja, utilizar a mesma classe
em vários projetos). Os programadores de software podem reutilizar as classes várias vezes
para criar os objetos.

3.2. Encapsulamento
Encapsulamento é um princípio que propõe ocultar determinados elementos de uma classe das
demais classes. Ao colocar uma proteção ao redor dos atributos e criar métodos para prover o
acesso a estes, desta forma estaremos prevenindo contra os efeitos colaterais indesejados que
podem afetá-los ao ter essas propriedades modificadas de forma inesperada.

Introdução à Programação I 6
JEDITM

Podemos prevenir o acesso aos dados dos nossos objetos declarando que temos controle desse
acesso. Aprenderemos mais sobre como Java implementa o encapsulamento quando
discutirmos mais detalhadamente sobre as classes.

3.3. Atributos e Métodos de Classe


Além dos atributos de objeto, também é possível definir atributos de classe, que são
atributos que pertencem à classe como um todo. Isso significa que possuem o mesmo valor
para todos os objetos daquela classe. Também são chamados de atributos estáticos.

Para melhor descrever os atributos de classe, vamos voltar ao exemplo da classe Carro.
Suponha que a classe Carro tenha um atributo de classe chamado Contador. Ao mudarmos o
valor de Contador para 2, todos os objetos da classe Carro terão o valor 2 para seus
atributos Contador.

Classe Carro Objeto Carro A Objeto Carro B


Número da placa ABC 111 XYZ 123

Atributos de Cor Azul Vermelho


Objeto Fabricante Mitsubishi Toyota
Velocidade 50 km/h 100 km/h
Atributos de
Contador = 2
Classe
Método Acelerar
Métodos de
Método virar
Objeto
Método Frear
Tabela 3: Atributos e métodos da classe Carro

3.4. Instância de Classe


Para criar um objeto ou uma instância da classe, utilizamos o operador new. Por exemplo,
para criar uma instância da classe String, escrevemos o seguinte código:

String str2 = new String("Hello world!");

ou, o equivalente:

String str2 = "Hello world!";

Figura 1: Instanciação de uma classe

O operador new aloca a memória para o objeto e retorna uma referência para essa alocação.
Ao criar um objeto, invoca-se, na realidade, o construtor da classe. O construtor é um
método onde todas as inicializações do objeto são declaradas e possui o mesmo nome da
classe.

Introdução à Programação I 7
JEDITM

4. Métodos
4.1. O que são métodos e porque usar métodos?
Nos exemplos apresentados anteriormente, temos apenas um método, o método main(). Em
Java, nós podemos definir vários métodos e podemos chamá-los a partir de outros métodos.

Um método é um trecho de código distinto que pode ser chamado por qualquer outro método
para realizar alguma função específica.

Métodos possuem as seguintes características:

• Podem ou não retornar um valor


• Podem aceitar ou não argumentos
• Após o método encerrar sua execução, o fluxo de controle é retornado a quem o
chamou

O que é necessário para se criar métodos? Porque não colocamos todas as instruções dentro
de um grande método? O foco destas questões é chamado de decomposição. Conhecido o
problema, nós o separamos em partes menores, que torna menos crítico o trabalho de
escrever grandes classes.

4.2. Chamando Métodos de Objeto e Enviando Argumentos

Para ilustrar como chamar os métodos, utilizaremos como exemplo a classe String. Pode-se
usar a documentação da API Java para conhecer todos os atributos e métodos disponíveis na
classe String. Posteriormente, iremos criar nossos próprios métodos.

Para chamar um método a partir de um objeto, escrevemos o seguinte:

nomeDoObjeto.nomeDoMétodo([argumentos]);

Vamos pegar dois métodos encontrados na classe String como exemplo:

Declaração do método Definição


public char charAt(int index) Retorna o caractere especificado no índice.
Um índice vai de 0 até length() - 1. O primeiro
caractere da seqüência está no índice 0, o
seguinte, no índice 1, e assim sucessivamente
por todo o array.
public boolean equalsIgnoreCase Compara o conteúdo de duas Strings, ignorando
(String anotherString) maiúsculas e minúsculas. Duas strings são
consideradas iguais quando elas têm o mesmo
tamanho e os caracteres das duas strings são
iguais, sem considerar caixa alta ou baixa.
Tabela 4: Exemplos de Métodos da classe String

Usando os métodos:

String str1 = "Hello";


char x = str1.charAt(0); // retornará o caracter H
// e o armazenará no atributo x

Introdução à Programação I 8
JEDITM

String str2 = "hello";

// aqui será retornado o valor booleano true


boolean result = str1.equalsIgnoreCase(str2);

4.3. Envio de Argumentos para Métodos


Em exemplos anteriores, enviamos atributos para os métodos. Entretanto, não fizemos
nenhuma distinção entre os diferentes tipos de atributos que podem ser enviados como
argumento para os métodos. Há duas formas para se enviar argumentos para um método, o
primeiro é envio por valor e o segundo é envio por referência.

4.3.1. Envio por valor


Quando ocorre um envio por valor, a chamada do método faz uma cópia do valor do atributo
e o reenvia como argumento. O método chamado não modifica o valor original do argumento
mesmo que estes valores sejam modificados durante operações de cálculo implementadas pelo
método. Por exemplo:

public class TestPassByValue {


public static void main( String[] args ){
int i = 10;
//exibe o valor de i
System.out.println( i );

//chama o método test


//envia i para o método test
test( i );

//exibe o valor de i não modificado


System.out.println( i );
}

public static void test( int j ){


//muda o valor do argumento j
j = 33;
}
}

No exemplo dado, o método test foi chamado e o valor de i foi enviado como argumento. O
valor de i é copiado para o atributo do método j. Já que j é o atributo modificado no método
test, não afetará o valor do atributo i, o que significa uma cópia diferente do atributo.

Como padrão, todo tipo primitivo, quando enviado para um método, utiliza a forma de envio
por valor.

4.3.2. Envio por referência


Quando ocorre um envio por referência, a referência de um objeto é enviada para o método
chamado. Isto significa que o método faz uma cópia da referência do objeto enviado.
Entretanto, diferentemente do que ocorre no envio por valor, o método pode modificar o
objeto para o qual a referência está apontando. Mesmo que diferentes referências sejam
usadas nos métodos, a localização do dado para o qual ela aponta é a mesma.

Por exemplo:

Introdução à Programação I 9
JEDITM

class TestPassByReference {
public static void main(String[] args) {
// criar um array de inteiros
int []ages = {10, 11, 12};
// exibir os valores do array
for (int i=0; i < ages.length; i++) {
System.out.println( ages[i] );
}
// chamar o método test e enviar a
// referência para o array
test( ages );

// exibir os valores do array


for (int i=0; i < ages.length; i++) {
System.out.println(ages[i]);
}
}
public static void test( int[] arr ){
// mudar os valores do array
for (int i=0; i < arr.length; i++) {
arr[i] = i + 50;
}
}
}

Figura 2: Exemplo de Envio por referência

Dicas de programação:

1. Um erro comum sobre envio por referência acontece quando criamos um


método para fazer trocas (swap) usando referência. Note que Java manipula
objetos 'por referência', entretanto envia-se a referência para um método 'por
valor'. Como conseqüência, não se escreve um método padrão para fazer troca
de valores (swap) entre objetos.

Introdução à Programação I 10
JEDITM

4.4. Chamando métodos estáticos


Métodos estáticos são métodos que podem ser invocados sem que um objeto tenha sido
instanciado pela classe (sem utilizar a palavra-chave new). Métodos estáticos pertencem a
classe como um todo e não ao objeto especifico da classe. Métodos estáticos são diferenciados
dos métodos de objeto pela declaração da palavra-chave static na definição do método.

Para chamar um método estático, digite:

NomeClasse.nomeMétodoEstático(argumentos);

Alguns métodos estáticos, que já foram usados em nossos exemplos são:

// Converter a String 10 em um atributo do tipo inteiro


int i = Integer.parseInt("10");

// Retornar uma String representando um inteiro sem o sinal da


// base 16
String hexEquivalent = Integer.toHexString(10);

4.5. Escopo de um atributo


Além do atributo ter um nome e um tipo, ele também possui um escopo. O escopo determina
onde o atributo é acessível dentro da classe. O escopo também determina o tempo de vida do
atributo ou quanto tempo o atributo irá existir na memória. O escopo é determinado pelo local
onde o atributo é declarado na classe.

Para simplificar, vamos pensar no escopo como sendo algo existente entre as chaves {...}. A
chave à direita é chamada de chave de saída do bloco (outer) e a chave à esquerda é
chamada chave de entrada do bloco (inner).

Ao declarar atributos fora de um bloco, eles serão visíveis (usáveis) inclusive pelas linhas da
classe dentro do bloco. Entretanto, ao declarar os atributo dentro do bloco, não será possível
utilizá-los fora do bloco.

O escopo de um atributo é dito local quando é declarado dentro do bloco. Seu escopo inicia
com a sua declaração e vai até a chave de saída do bloco.

Por exemplo, dado o seguinte fragmento de código:

public class ScopeExample {


int i = 0;
public static void main(String[] args) {
int j = 0;
{
int k = 0;
A int m = 0;
B C
int n = 0; D
C }
}
}

O código acima representa cinco escopos indicado pelas letras. Dados os atributos i, j, k, m e
n, e os cinco escopos A, B, C, D e E, temos os seguintes escopos para cada atributo:

O escopo do atributo i é A.

Introdução à Programação I 11
JEDITM

O escopo do atributo j é B.
O escopo do atributo k é C.
O escopo do atributo m é D.
O escopo do atributo n é E.

Dado dois métodos: main e test teremos o seguinte exemplo:

class TestPassByReference {
public static void main(String[] args) {
// criar um array de inteiros
int []ages = {10, 11, 12};

//exibir os valores do array


for (int i=0; i < ages.length; i++){
System.out.println( ages[i] );
B
}

A // chamar o método test e enviar a referência para o array


test(ages);

//exibe novamente os valores do array


for (int i = 0; i < ages.length; i++) {
C System.out.println( ages[i] );
}
}
public static void test(int[] arr) {
// modificar os valores do array
for (int i = 0; i < arr.length; i++) { D
E arr[i] = i + 50;
}
}
}

Para o método main, os escopos dos atributos são:

ages[] - escopo A
i em B - escopo B
i em C – escopo C

E, no método test, os escopos dos atributos são:

arr[] - escopo D
i em E - escopo E

Quando atributos são declarados, o identificador deve ser único no escopo. Isto significa que
se você tiver a seguinte declaração:

{
int test = 10;
int test = 20;
}

o compilador irá gerar um erro pois deve-se ter um nome único para o atributos dentro do
bloco. Entretanto, é possível ter atributos definidos com o mesmo nome, se não estiverem
declarados no mesmo bloco. Por exemplo:

public class TestBlock {


int test = 10;

Introdução à Programação I 12
JEDITM

public void test() {


System.out.print(test);
int test = 20;
System.out.print(test);
}
public static void main(String[] args) {
TestBlock testBlock = new TestBlock();
testBlock.test();
}
}

Quando a primeira instrução System.out.print for invocada, exibirá o valor 10 contido na


primeira declaração do atributo test. Na segunda instrução System.out.print, o valor 20 é
exibido, pois é o valor do atributos test neste escopo.

Dicas de programação:

1. Evite ter atributos declarados com o mesmo nome dentro de um método para
não causar confusão.

Introdução à Programação I 13
JEDITM

5. Casting, Conversão e Comparação de Objetos


Nesta seção, vamos aprender como realizar um casting. Casting, ou typecasting, é o
processo de conversão de um certo tipo de dado para outro. Também aprenderemos como
converter tipos de dados primitivos para objetos e vice-versa. E, finalmente, aprenderemos
como comparar objetos.

5.1. Casting de Tipos Primitivos


Casting entre tipos primitivos permite converter o valor de um dado de um determinado tipo
para outro tipo de dado primitivo. O casting entre primitivos é comum para os tipos numéricos.

Há um tipo de dado primitivo que não aceita o casting, o tipo de dado boolean.

Como demonstração de casting de tipos, considere que seja necessário armazenar um valor do
tipo int em um atributo do tipo double. Por exemplo:

int numInt = 10;


double numDouble = numInt; // cast implícito

uma vez que o atributo de destino é double, pode-se armazenar um valor cujo tamanho seja
menor ou igual aquele que está sendo atribuído. O tipo é convertido implicitamente.

Quando convertemos um atributo cujo tipo possui um tamanho maior para um de tamanho
menor, necessariamente devemos fazer um casting explícito. Esse possui a seguinte forma:

(tipoDado)valor
onde:
tipoDado é o nome do tipo de dado para o qual se quer converter o valor
valor é um valor que se quer converter.

Por exemplo:

double valDouble = 10.12;


int valInt = (int)valDouble; //converte valDouble para o tipo int
double x = 10.2;
int y = 2;
int result = (int)(x/y); //converte o resultado da operação para int

Outro exemplo é quando desejamos fazer um casting de um valor do tipo int para char. Um
caractere pode ser usado como int porque para cada caractere existe um correspondente
numérico que representa sua posição no conjunto de caracteres. O casting (char)65 irá
produzir a saída 'A'. O código numérico associado à letra maiúscula A é 65, segundo o
conjunto de caracteres ASCII. Por exemplo:

char valChar = 'A';


System.out.print((int)valChar); //casting explícito produzirá 65

5.2. Casting de Objetos


Para objetos, a operação de casting também pode ser utilizada para fazer a conversão para
outras classes, com a seguinte restrição: a classe de origem e a classe de destino devem ser
da mesma família, relacionadas por herança; uma classe deve ser subclasse da outra.
Veremos mais em lições posteriores sobre herança.

Introdução à Programação I 14
JEDITM

Analogamente à conversão de valores primitivos para um tipo maior, alguns objetos não
necessitam ser convertidos explicitamente. Em conseqüência de uma subclasse conter todas as
informações da sua superclasse, pode-se usar um objeto da subclasse em qualquer lugar onde
a superclasse é esperada.

Por exemplo, um método que recebe dois argumentos, um deles do tipo Object e outro do
tipo Window. Pode-se enviar um objeto de qualquer classe como argumento Object porque
todas as classes Java são subclasses de Object. Para o argumento Window, é possível enviar
apenas suas subclasses, tais como Dialog, FileDialog, Frame (ou quaisquer de subclasses de
suas subclasses, indefinidamente). Isso vale para qualquer parte da classe, não apenas dentro
da chamadas do método. Para um objeto definido como uma classe Window, é possível atribuir
objetos dessa classe ou qualquer uma de suas subclasses para esse objeto sem o casting.

Figura 3: Exemplo de Hierarquia de Classes

O contrário também é verdadeiro. Uma superclasse pode usada quando uma subclasse é
esperada. Entretanto, nesse caso, o casting é necessário porque as subclasses contém mais
métodos que suas superclasses, e isso acarreta em perda de precisão. Os objetos das
superclasses podem não dispor de todo o comportamento necessário para agir como um
objeto da subclasse. Por exemplo, se uma operação faz a chamada a um método de um objeto
da classe Integer, usando um objeto da classe Number, ele não terá muitos dos métodos
que foram especificados na classe Integer. Erros ocorrerão se você tentar chamar métodos
que não existem no objeto de destino.

Para usar objetos da superclasse onde uma subclasse é esperada, é necessário fazer o
casting explícito. Nenhuma informação será perdida no casting, entretanto, ganhará todos
os atributos e métodos que a subclasse define. Para fazer o casting de um objeto para outro,
utiliza-se a mesma operação utilizada com os tipos primitivos:

Para fazer o casting:

(nomeClasse)objeto
onde:
nomeClasse é o nome da classe destino
objeto é a referência para o objeto origem que se quer converter

Uma vez que casting cria uma referência para o antigo objeto de nomeClasse; ele continua a
existir depois do casting.

Introdução à Programação I 15
JEDITM

Figura 4: Hierarquia de classes para a superclasse Employee

O exemplo a seguir realiza um casting de um objeto da classe VicePresident para um objeto


da classe Employee. VicePresident é uma subclasse de Employee com mais informações,
supondo que tenha sido definido que a classe VicePresident tem mais privilégios que um
Employee.

Employee emp = new Employee();


VicePresident veep = new VicePresident();
emp = veep; // casting não é necessário de baixo para cima
veep = (VicePresident)emp; // necessita do casting explícito

5.3. Convertendo Tipos Primitivos para Objetos e Vice-Versa


Não se pode fazer sob qualquer circunstância é um casting de um objeto para um tipo de dado
primitivo, ou vice-versa. Tipos primitivos e objetos são muito diferentes em Java e não se pode
fazer o casting automaticamente entre os dois ou intercambiar o seu uso.

Como alternativa, o pacote java.lang oferece classes que fazem a correspondência para cada
tipo primitivo: Float, Boolean, Byte, dentre outros. Muitas dessas classes têm o mesmo nome
dos tipos de dados primitivos, exceto pelo fato que o nome dessas classe começam com letra
maiúscula (Short ao invés de short, Double ao invés de double, etc). Há duas classes que
possuem nomes que diferem do correspondente tipo de dado primitivo: Character é usado
para o tipo char e Integer usado para o tipo int. Estas classes são chamadas de Wrapper
Class.

Versões anteriores a 5.0 de Java tratam os tipos de dados e suas Wrapper Class de forma
muito diferente e uma classe não será compilada com sucesso se for utilizado uma quando
deveria usar a outra. Por exemplo:

Integer ten = 10;


Integer two = 2;
System.out.println(ten + two);

Usando as classes que correspondem a cada um dos tipos primitivos, é possível criar objetos
que armazenam este mesmo valor. Por exemplo:

// A declaração seguinte cria um objeto de uma classe Integer


// com o valor do tipo int 7801 (primitivo -> objeto)
Integer dataCount = new Integer(7801);

// A declaração seguinte converte um objeto Integer para um


// tipo de dado primitivo int. O resultado é o valor 7801
int newCount = dataCount.intValue();

// Uma conversão comum de se fazer é de String para um tipo


// numérico (objeto -> primitivo)
String pennsylvania = "65000";
int penn = Integer.parseInt(pennsylvania);

Introdução à Programação I 16
JEDITM

Dicas de programação:

1. A classe Void representa vazio em Java. Deste modo, não existem motivos para
ela ser usada na conversão de valores primitivos e objetos. Ela é um tratador
para a palavra-chave void, que é utilizada na assinatura de métodos indicando
que estes não retornam valor.

5.4. Comparando Objetos


Em lições prévias, aprendemos sobre operadores para comparar valores — igualdade,
negação, menor que, etc. Muitos desses operadores trabalham apenas com dados de tipo
primitivo, não com objetos. Ao tentar utilizar outros tipos de dados, o compilador produzirá
erros.

Uma exceção para esta regra são os operadores de igualdade: == (igual) e != (diferente).
Quando aplicados a objetos, estes operadores não fazem o que se poderia supor. Ao invés de
verificar se um objeto tem o mesmo valor de outro objeto, eles determinam se os dois objetos
comparados pelo operador têm a mesma referência. Por exemplo:

String valor1 = new String;


Integer dataCount = new Integer(7801);

Para comparar objetos de uma classe e ter resultados apropriados, deve-se implementar e
chamar métodos especiais na sua classe. Um bom exemplo disso é a classe String.

É possível ter dois objetos String diferentes que contenham o mesmo valor. Caso se empregue
o operador == para comparar objetos, estes serão considerados diferentes. Mesmo que seus
conteúdos sejam iguais, eles não são o mesmo objeto.

Para ver se dois objetos String têm o mesmo conteúdo, um método chamado equals() é
utilizado. O método compara cada caractere presente no conteúdo das Strings e retorna true
se ambas strings tiverem o mesmo valor.

O código seguinte ilustra essa comparação,

class EqualsTest {
public static void main(String[] args) {
String str1, str2;
str1 = "Free the bound periodicals.";
str2 = str1;

System.out.println("String1: " + str1);


System.out.println("String2: " + str2);
System.out.println("Same object? " + (str1 == str2));

str2 = new String(str1);

System.out.println("String1: " + str1);


System.out.println("String2: " + str2);
System.out.println("Same object? " + (str1 == str2));
System.out.println("Same value? " + str1.equals(str2));
}
}

Introdução à Programação I 17
JEDITM

A saída dessa classe é a seguinte:

String1: Free the bound periodicals.


String2: Free the bound periodicals.
Same object? true
String1: Free the bound periodicals.
String2: Free the bound periodicals.
Same object? false
Same value? true

Vamos entender o processo envolvido.

String str1, str2;


str1 = "Free the bound periodicals.";
str2 = str1;

Figura 5: Duas referências apontando para o mesmo objeto

A primeira parte dessa classe declara dois atributos (str1 e str2) e atribui a literal "Free the
bound periodicals." a str1, e depois atribui esse valor a str2. Como visto anteriormente, str1 e
str2 agora apontam para o mesmo objeto, e o teste de igualdade prova isso.

Em seguida, temos a seguinte instrução:

str2 = new String(str1);

Na segunda parte da classe, cria-se um novo objeto String com o mesmo valor de str1 e faz-se
a atribuição de str2 para esse novo objeto String. Agora temos dois diferentes tipos de objetos
na str1 e str2, ambos com o mesmo conteúdo. Testando para ver se eles são o mesmo objeto
usando o operador de igualdade obtemos a resposta esperada: false — eles não são o mesmo
objeto na memória. Utilizando o método equals() recebemos a resposta esperada: true —
eles tem o mesmo conteúdo.

Figura 6: As referências apontam agora para objetos diferentes

Dicas de programação:

1. Porque não se pode ter a mesma literal quando mudamos str2, a não ser quando
utilizamos o new? Literais String são otimizadas em Java; se uma String é
criada utilizando uma literal e cria-se outra String com os mesmos caracteres,

Introdução à Programação I 18
JEDITM

Java tem inteligência suficiente para retornar apenas a posição em memória do


primeiro objeto String criado. Ou seja, ambas strings se referem ao mesmo
objeto como se fosse um apelido. Para obrigar ao Java criar um novo objeto
String, deve-se utilizar o operador new.

5.5. Determinando a Classe de um Objeto


Existem duas maneiras de se descobrir a qual classe determinado objeto pertence:

1. Para obter o nome da classe:

Utiliza-se o método getClass() que retorna a classe do objeto (onde Class é a classe em si).
Esta, por sua vez, possui o método chamado getName() que retorna o nome da classe.

Por exemplo:

String name = key.getClass().getName();

2. Para testar se um objeto qualquer foi instanciado de uma determinada classe:

Utiliza-se a palavra-chave instanceof. Esta palavra-chave possui dois operadores: a referência


para o objeto à esquerda e o nome da classe à direita. A expressão retorna um lógico
dependendo se o objeto é uma instância da classe declarada ou qualquer uma de suas
subclasses.

Por exemplo:

String ex1 = "Texas";


System.out.println(ex1 instanceof String); // retorna true
String ex2;
System.out.println(ex2 instanceof String); // retorna false

Introdução à Programação I 19
JEDITM

6. Exercícios
6.1. Definindo termos
Em suas palavras, defina os seguintes termos:

1. Classe
2. Objeto
3. Instanciação
4. Atributo de objeto
5. Método de objeto
6. Atributo de classe ou atributos estáticas
7. Construtor
8. Método de classe ou métodos estáticos

6.2. Java Scavenger Hunt


Pipoy é um novato na linguagem de programação Java. Ele apenas ouviu que existem Java
APIs (Application Programming Interface) prontas para serem usadas em suas classes e ele
está ansioso para fazer uns testes com elas. O problema é que Pipoy não tem uma cópia da
documentação Java e ele também não tem acesso à Internet, deste modo, não há como ele
ver as APIs java.

Sua tarefa é ajudar Pipoy a procurar as APIs. Você deve informar as classes às quais os
métodos pertencem e como o método deve ser declarado com um exemplo de uso deste.

Por exemplo, se Pipoy quer saber qual o método que converte uma String para int, sua
resposta deve ser:

Classe: Integer
Declaração do Método: public static int parseInt( String value )
Exemplo de Uso:
String strValue = "100";
int value = Integer.parseInt( strValue );

Tenha certeza de que o fragmento de código que você escreveu em seu exemplo de uso
compila e que produza o resultado correto. Enfim, não deixe Pipoy confuso. (Dica: Todos os
métodos estão no package java.lang). Caso haja mais de um método para atender à
tarefa, utilize apenas um.

Agora vamos iniciar a busca! Aqui estão alguns métodos que Pipoy necessita:

1. Procure pelo método que verifica se uma String termina com um determinado sufixo. Por
exemplo, se a String dada é "Hello", o método deve retornar true se o sufixo informado é
"lo", e false se o sufixo for "alp".
2. Procure pelo método que determina a representação do caractere para um dígito e base
específicos. Por exemplo, se o dígito informado é 15 e a base é 16, o método retornará o
caractere 'F', uma vez que 'F' é a representação hexadecimal para o número 15 em base
10.
3. Procure por um método que retorna a parte inteira de um valor double. Por exemplo, se a
entrada for 3.13, o método deve retornar o valor 3.
4. Procure por um método que determina se um certo caractere é um dígito. Por exemplo, se a
entrada for '3', retornará o valor true.
5. Procure por um método que interrompe a execução da Java Virtual Machine corrente.

Introdução à Programação I 20
Módulo 1
Introdução à Programação 1

Lição 10
Criando nossas classes

Versão 1.0 - Jan/2007


JEDITM

1. Objetivos

Agora que já estudamos como usar as classes existentes na biblioteca de


classes do Java, estudaremos como criar nossas próprias classes. Nesta lição,
para facilmente entender como criá-las, realizaremos um exemplo de classe no
qual adicionaremos dados e funcionalidades à medida em que avançarmos no
curso.

Criaremos uma classe com informações de um Estudante e com operações


necessárias para seu registro.

Algumas observações devem ser feitas quanto à sintaxe que será usada nesta
e nas próximas seções:

* - significa que pode haver nenhuma ou diversas


ocorrências na linha em que for aplicada
<descrição> - indica a substituição deste trecho por um certo valor,
ao invés de digitá-lo como está
[] - indica que esta parte é opcional

Ao final desta lição, o estudante será capaz de:

• Criar nossas classes


• Declarar atributos e métodos para as classes
• Usar o objeto this para acessar dados de instância
• Utilizar overloading de métodos
• Importar e criar pacotes
• Usar modificadores de acesso para controlar o acesso aos elementos de
uma classe

Introdução à Programação I 4
JEDITM

2. Definindo nossas classes

Antes de escrever sua classe, primeiro pense onde e como sua classe será
usada. Pense em um nome apropriado para a classe e liste todas as
informações ou propriedades que deseje que ela tenha. Liste também os
métodos que serão usados para a classe.

Para definir uma classe, escrevemos:

<modificador>* class <nome> {


<declaraçãoDoAtributo>*
<declaraçãoDoConstrutor>*
<declaraçãoDoMétodo>*
}
onde:

<modificador> é um modificador de acesso, que pode ser


usado em combinação com outros
<nome> nome da sua classe
<declaraçãoDoAtributo> atributos definidos para a classe
<declaraçãoDoConstrutor> método construtor
<declaraçãoDoMétodo> métodos da classe

Dicas de programação:

1. Lembre-se de que, para a declaração da classe, o único


modificador de acesso válido é o public. De uso exclusivo para a
classe que possuir o mesmo nome do arquivo externo.

Nesta lição, criaremos uma classe que conterá o registro de um estudante.


Como já identificamos o objetivo da nossa classe, agora podemos nomeá-la.
Um nome apropriado para nossa classe seria StudentRecord.

Para definir nossa classe, escrevemos:

public class StudentRecord {


// adicionaremos mais código aqui
}

onde:

public modificador de acesso e significa que


qualquer classe pode acessar esta
class palavra-chave usada para criar uma classe
StudentRecord identificador único que identifica a classe

Introdução à Programação I 5
JEDITM

Dicas de programação:

1. Pense em nomes apropriados para a sua classe. Não a chame


simplesmente de classe XYZ ou qualquer outro nome aleatório.
2. Os nomes de classes devem ser iniciadas por letra MAIÚSCULA.
3. O nome do arquivo de sua classe obrigatoriamente possui o
MESMO NOME da sua classe pública.

Introdução à Programação I 6
JEDITM

3. Declarando Atributos

Para declarar um certo atributo para a nossa classe, escrevemos:

<modificador>* <tipo> <nome> [= <valorInicial>];

onde:

modificador tipo de modificador do atributo


tipo tipo do atributo
nome pode ser qualquer identificador válido
valorInicial valor inicial para o atributo

Relacionaremos a lista de atributos que um registro de estudante pode conter.


Para cada informação, listaremos os tipos de dados apropriados que serão
utilizados. Por exemplo, não seria ideal usar um tipo int para o nome do
estudante ou String para a nota do estudante.

Abaixo, por exemplo, temos algumas informações que podemos adicionar ao


registro do estudante:

nome - String
endereço - String
idade - int
nota de matemática - double
nota de inglês - double
nota de ciências - double

Futuramente, é possível adicionar mais informações. Para este exemplo,


utilizaremos somente estas.

3.1. Atributos de Objeto

Agora que temos uma lista de todos os atributos que queremos adicionar à
nossa classe, vamos adicioná-los ao nosso código. Uma vez que queremos que
estes atributos sejam únicos para cada objeto (ou para cada estudante),
devemos declará-los como atributos de objeto.

Por exemplo:

public class StudentRecord {


private String name;
private String address;
private int age;
private double mathGrade;

Introdução à Programação I 7
JEDITM

private double englishGrade;


private double scienceGrade;
}

onde:

private significa que os atributos são acessíveis apenas de dentro


da classe. Outros objetos não podem acessar diretamente
estes atributos.

Dicas de programação:

1. Declare todas os atributos de objeto na parte superior da


declaração da classe.
2. Declare cada atributo em uma linha.
3. Atributos de objeto, assim como qualquer outro atributo devem
iniciar com letra MINÚSCULA.
4. Use o tipo de dado apropriado para cada atributo declarado.
5. Declare atributos de objetos como private de modo que somente
os métodos da classe possam acessá-los diretamente.

3.2. Atributos de Classe ou Atributos Estáticos

Além das atributos de objeto, podemos também declarar atributos de classe ou


atributos que pertençam à classe como um todo. O valor destes atributos é o
mesmo para todos os objetos da mesma classe. Suponha que queiramos saber
o número total de registros criados para a classe. Podemos declarar um
atributo estático que armazenará este valor. Vamos chamá-lo de
studentCount.

Para declarar um atributo estático:

public class StudentRecord {


// atributos de objeto declarados anteriormente

private static int studentCount;


}

usamos a palavra-chave static para indicar que é um atributo estático.

Então, nosso código completo deve estar assim:

public class StudentRecord {


private String name;
private String address;

Introdução à Programação I 8
JEDITM

private int age;


private double mathGrade;
private double englishGrade;
private double scienceGrade;

private static int studentCount;


}

Introdução à Programação I 9
JEDITM

4. Declarando Métodos

Antes de discutirmos quais métodos que a nossa classe deverá conter,


vejamos a sintaxe geral usada para a declaração de métodos.

Para declararmos métodos, escrevemos:

<modificador>* <tipoRetorno> <nome>(<argumento>*) {


<instruções>*
}

onde:

<modificador> pode ser utilizado qualquer modificador de


acesso
<tipoRetorno> pode ser qualquer tipo de dado (incluindo
void)
<nome> pode ser qualquer identificador válido
<argumento> argumentos recebidos pelo método separados
por vírgulas. São definidos por:

<tipoArgumento> <nomeArgumento>

4.1. Métodos assessores

Para que se possa implementar o princípio do encapsulamento, isto é, não


permitir que quaisquer objetos acessem os nossos dados de qualquer modo,
declaramos campos, ou atributos, da nossa classe como particulares.
Entretanto, há momentos em que queremos que outros objetos acessem estes
dados particulares. Para que possamos fazer isso, criamos métodos
assessores.

Métodos assessores são usados para ler valores de atributos de objeto ou de


classe. O método assessor recebe o nome de get<NomeDoAtributo>. Ele
retorna um valor.

Para o nosso exemplo, queremos um método que possa ler o nome, endereço,
nota de inglês, nota de matemática e nota de ciências do estudante.

Vamos dar uma olhada na implementação deste:

public class StudentRecord {


private String name;
:
:
public String getName() {

Introdução à Programação I 10
JEDITM

return name;
}
}

onde:

public significa que o método pode ser chamado por


objetos externos à classe
String é o tipo do retorno do método. Isto significa que o
método deve retornar um valor de tipo String
getName o nome do método
() significa que o nosso método não tem nenhum
argumento

A instrução:

return name;

no método, significa que retornará o conteúdo do atributo name ao método


que o chamou. Note que o tipo do retorno do método deve ser do mesmo tipo
do atributo utilizado na declaração return. O seguinte erro de compilação
ocorrerá caso o método e o atributo de retorno não tenham o mesmo tipo de
dados:

StudentRecord.java:14: incompatible types


found : int
required: java.lang.String
return name;
^
1 error

Outro exemplo de um método assessor é o método getAverage:

public class StudentRecord {


private String name;
:
:
public double getAverage(){
double result = 0;
result =
(mathGrade+englishGrade+scienceGrade)/3;
return result;
}
}

O método getAverage calcula a média das 3 notas e retorna o resultado.

Introdução à Programação I 11
JEDITM

4.2. Métodos modificadores

Para que outros objetos possam modificar os nossos dados, disponibilizamos


métodos que possam gravar ou modificar os valores dos atributos de objeto ou
de classe. Chamamos a estes métodos modificadores. Este método é escrito
como set<NomeDoAtributoDeObjeto>.

Vamos dar uma olhada na implementação de um método modificador:

public class StudentRecord {


private String name;
:
:
public void setName(String temp) {
name = temp;
}
}

onde:

public significa que o método pode ser chamado por


objetos externos à classe
void significa que o método não retorna valor
setName o nome do método
(String temp) argumento que será utilizado dentro do nosso
método

A instrução:

name = temp;

atribuir o conteúdo de temp para name e, portanto, alterar os dados dentro


do atributo de objeto name.

Métodos modificadores não retornam valores. Entretanto, eles devem receber


um argumento com o mesmo tipo do atributo no qual estão tratando.

4.3. Múltiplos comandos return

É possível ter vários comandos return para um método desde que eles não
pertençam ao mesmo bloco. É possível utilizar constantes para retornar
valores, ao invés de atributos.

Por exemplo, considere o método:

public String getNumberInWords(int num) {


String defaultNum = "zero";

Introdução à Programação I 12
JEDITM

if (num == 1) {
return "one"; // retorna uma constante
} else if( num == 2) {
return "two"; // retorna uma constante
}
// retorna um atributo
return defaultNum;
}

4.4. Métodos estáticos

Para o atributo estático studentCount, podemos criar um método estático


para obter o seu conteúdo.

public class StudentRecord {


private static int studentCount;

public static int getStudentCount(){


return studentCount;
}
}

onde:

public significa que o método pode ser chamado por


objetos externos à classe
static significa que o método é estático e deve ser
chamado digitando-se
[NomeClasse].[nomeMétodo]
int é o tipo do retorno do método. Significa que o
método deve retornar um valor de tipo int
getStudentCount nome do método
() significa que o método não tem nenhum
argumento

Por enquanto, getStudentCount retornará sempre o valor zero já que ainda


não fizemos nada na nossa classe para atribuir o seu valor. Modificaremos o
valor de studentCount mais tarde, quando discutirmos construtores.

Dicas de programação:

1. Nomes de métodos devem iniciar com letra MINÚSCULA.


2. Nomes de métodos devem conter verbos
3. Sempre faça documentação antes da declaração do método. Use o
estilo javadoc para isso.

Introdução à Programação I 13
JEDITM

4.5. Exemplo de Código Fonte para a classe StudentRecord

Aqui está o código para a nossa classe StudentRecord:

public class StudentRecord {


private String name;
private String address;
private int age;
private double mathGrade;
private double englishGrade;
private double scienceGrade;

private static int studentCount;

/**
* Retorna o nome do estudante
*/
public String getName(){
return name;
}

/**
* Muda o nome do estudante
*/
public void setName( String temp ){
name = temp;
}

// outros métodos modificadores aqui ....

/**
* Calcula a média das classes de inglês, matemática
* e ciências
*/
public double getAverage(){
double result = 0;
result =
(mathGrade+englishGrade+scienceGrade)/3;
return result;
}
/**
* Retorna o número de ocorrências em StudentRecords
*/
public static int getStudentCount(){
return studentCount;
}
}

Aqui está um exemplo do código de uma classe que utiliza a nossa classe

Introdução à Programação I 14
JEDITM

StudentRecord.

public class StudentRecordExample {


public static void main( String[] args ){
// criar três objetos para StudentRecord
StudentRecord annaRecord = new StudentRecord();
StudentRecord beahRecord = new StudentRecord();
StudentRecord crisRecord = new StudentRecord();

// enviar o nome dos estudantes


annaRecord.setName("Anna");
beahRecord.setName("Beah");
crisRecord.setName("Cris");

// mostrar o nome de anna


System.out.println(annaRecord.getName());

//mostrar o número de estudantes


System.out.println("Count=" +
StudentRecord.getStudentCount());
}
}

A saída desta classe é:

Anna
Count = 0

Introdução à Programação I 15
JEDITM

5. this

O objeto this é usado para acessar atributos de objeto ou métodos da classe.


Para entender isso melhor, tomemos o método setAge como exemplo.
Suponha que tenhamos o seguinte método para setAge:

public void setAge(int age){


age = age; // Não é uma boa prática
}

O nome do argumento nesta declaração é age, que tem o mesmo nome do


atributo de objeto age. Já que o argumento age é a declaração mais próxima
do método, o valor do argumento age será usado. Na instrução:

age = age;

estamos simplesmente associando o valor do argumento age para si mesmo!


Isto não é o que queremos que aconteça no nosso código. A fim de corrigir
esse erro, usamos o objeto this. Para utilizar o objeto this, digitamos:

this.<nomeDoAtributo>

O ideal é reescrever o nosso método do seguinte modo:

public void setAge(int age){


this.age = age;
}

Este método irá atribuir o valor do argumento age para a atributo de objeto
age do objeto StudentRecord.

Introdução à Programação I 16
JEDITM

6. Overloading de Métodos

Nas nossas classes, podemos necessitar de criar métodos que tenham os


mesmos nomes, mas que funcionem de maneira diferente dependendo dos
argumentos que informamos. Esta capacidade é chamada de overloading de
métodos.

Overloading de métodos permite que um método com o mesmo nome,


entretanto com diferentes argumentos, possa ter implementações diferentes e
retornar valores de diferentes tipos. Ao invés de inventar novos nomes todas
as vezes, o overloading de métodos pode ser utilizado quando a mesma
operação tem implementações diferentes.

Por exemplo, na nossa classe StudentRecord, queremos ter um método que


mostre as informações sobre o estudante. Entretanto, queremos que o método
print mostre dados diferentes dependendo dos argumentos que lhe
informamos. Por exemplo, quando não enviamos qualquer argumento
queremos que o método print mostre o nome, endereço e idade do estudante.
Quando passamos 3 valores double, queremos que o método mostre o nome
e as notas do estudante.

Temos os seguintes métodos dentro da nossa classe StudentRecord:

public void print(){


System.out.println("Name:" + name);
System.out.println("Address:" + address);
System.out.println("Age:" + age);
}

public void print(double eGrade, double mGrade, double


sGrade)
System.out.println("Name:" + name);
System.out.println("Math Grade:" + mGrade);
System.out.println("English Grade:" + eGrade);
System.out.println("Science Grade:" + sGrade);
}

Quando tentamos chamar estes métodos no método main, criado para a


classe StudantRecordExample:

public static void main(String[] args) {


StudentRecord annaRecord = new StudentRecord();

annaRecord.setName("Anna");
annaRecord.setAddress("Philippines");
annaRecord.setAge(15);

Introdução à Programação I 17
JEDITM

annaRecord.setMathGrade(80);
annaRecord.setEnglishGrade(95.5);
annaRecord.setScienceGrade(100);

// overloading de métodos
annaRecord.print();
annaRecord.print(
annaRecord.getEnglishGrade(),
annaRecord.getMathGrade(),
annaRecord.getScienceGrade());
}

teremos a saída para a primeira chamada ao método print:

Name:Anna
Address:Philippines
Age:15

e, em seguida, a saída para a segunda chamada ao método print:

Name:Anna
Math Grade:80.0
English Grade:95.5
Science Grade:100.0

Lembre-se sempre que métodos overload possuem as seguintes


propriedades:

1. o mesmo nome
2. argumentos diferentes
3. tipo do retorno igual ou diferente

Introdução à Programação I 18
JEDITM

7. Declarando Construtores

Discutimos anteriormente o conceito de construtores. Construtores são


importantes na criação de um objeto. É um método onde são colocadas todas
as inicializações.

A seguir, temos as propriedades de um construtor:

1. Possuem o mesmo nome da classe


2. Construtor é um método, entretanto, somente as seguintes informações
podem ser colocadas no cabeçalho do construtor:
○ Escopo ou identificador de acessibilidade (como public)
○ Nome do construtor
○ Argumentos, caso necessário
3. Não retornam valor
4. São executados automaticamente na utilização do operador new durante
a instanciação da classe

Para declarar um construtor, escrevemos:

[modificador] <nomeClasse> (<argumento>*) {


<instrução>*
}

7.1. Construtor Padrão (default)

Toda classe tem o seu construtor padrão. O construtor padrão é um


construtor público e sem argumentos. Se não for definido um construtor para a
classe, então, implicitamente, é assumido um construtor padrão.

Por exemplo, na nossa classe StudentRecord, o construtor padrão é definido


do seguinte modo:

public StudentRecord() {
}

7.2. Overloading de Construtores

Como mencionamos, construtores também podem sofrer overloading, por


exemplo, temos aqui quatro construtores:

public StudentRecord() {
// qualquer código de inicialização aqui
}
public StudentRecord(String temp){

Introdução à Programação I 19
JEDITM

this.name = temp;
}
public StudentRecord(String name, String address) {
this.name = name;
this.address = address;
}
public StudentRecord(double mGrade, double eGrade,
double sGrade) {
mathGrade = mGrade;
englishGrade = eGrade;
scienceGrade = sGrade;
}

7.3. Usando Construtores

Para utilizar estes construtores, temos as seguintes instruções:

public static void main(String[] args) {


// criar três objetos para o registro do estudante
StudentRecord annaRecord = new
StudentRecord("Anna");
StudentRecord beahRecord =
new StudentRecord("Beah", "Philippines");
StudentRecord crisRecord =
new StudentRecord(80,90,100);
// algum código aqui
}

Antes de continuarmos, vamos retornar o atributo estático studentCount que


declaramos agora a pouco. O objetivo de studentCount é contar o número de
objetos que são instanciados com a classe StudentRecord. Então, o que
desejamos é incrementar o valor de studentCount toda vez que um objeto da
classe StudentRecord é instanciado. Um bom local para modificar e
incrementar o valor de studentCount é nos construtores, pois são sempre
chamados toda vez que um objeto é instanciado. Por exemplo:

public StudentRecord() {
studentCount++; // adicionar um estudante
}
public StudentRecord(String name) {
studentCount++; // adicionar um estudante
this.name = name;
}
public StudentRecord(String name, String address) {
studentCount++; // adicionar um estudante
this.name = name;
this.address = address;

Introdução à Programação I 20
JEDITM

}
public StudentRecord(double mGrade, double eGrade,
double sGrade) {
studentCount++; // adicionar um estudante
mathGrade = mGrade;
englishGrade = eGrade;
scienceGrade = sGrade;
}

7.4. Utilizando o this()

Chamadas a construtores podem ser cruzadas, o que significa ser possível


chamar um construtor de dentro de outro construtor. Usamos a chamada
this() para isso. Por exemplo, dado o seguinte código,

public StudentRecord() {
this("some string");
}
public StudentRecord(String temp) {
this.name = temp;
}
public static void main( String[] args ) {
StudentRecord annaRecord = new StudentRecord();
}

Dado o código acima, quando se executa a instrução do método main, será


chamado o primeiro construtor. A instrução inicial deste construtor resultará
na chamada ao segundo construtor.

Há algum detalhes que devem ser lembrados na utilização da chamada ao


construtor por this():

1. A chamada ao construtor DEVE SEMPRE OCORRER NA PRIMEIRA


LINHA DE INSTRUÇÃO
2. UTILIZADO PARA A CHAMADA DE UM CONSTRUTOR. A chamada ao
this() pode ser seguida por outras instruções.

Como boa prática de programação, é ideal nunca construir métodos que


repitam as instruções. Buscamos a utilização de overloading com o objetivo
de evitarmos essa repetição. Deste modo, reescreveremos os construtores da
classe StudentRecord para:

public StudentRecord() {
studentCount++; // adicionar um estudante
}
public StudentRecord(String name) {
this();

Introdução à Programação I 21
JEDITM

this.name = name;
}
public StudentRecord(String name, String address) {
this(name);
this.address = address;
}
public StudentRecord(double mGrade, double eGrade,
double sGrade) {
this();
mathGrade = mGrade;
englishGrade = eGrade;
scienceGrade = sGrade;
}

Introdução à Programação I 22
JEDITM

8. Pacotes

São utilizados para agrupar classes e interfaces relacionadas em uma única


unidade (discutiremos interfaces mais tarde). Esta é uma característica
poderosa que oferece um mecanismo para gerenciamento de um grande grupo
de classes e interfaces e evita possíveis conflitos de nome.

8.1. Importando Pacotes

Para utilizar classes externas ao pacote da classe, é necessário importar os


pacotes dessas classes. Por padrão, todos as suas classes Java importam o
pacote java.lang. É por isso que é possível utilizar classes como String e
Integer dentro da sua classe, mesmo não tendo importado nenhum pacote
explicitamente.

A sintaxe para importar pacotes é como segue:

import <nomeDoPacote>.<nomeDaClasse>;

Por exemplo, necessitar utilizar a classe Color dentro do pacote awt, é


necessário a seguinte instrução:

import java.awt.Color;

ou:

import java.awt.*;

A primeira linha de instrução importa especificamente a classe Color enquanto


que a seguinte importa todas as classes do pacote java.awt.

Outra maneira de importar classes de outros pacotes é através da referência


explícita ao pacote. Isto é feito utilizando-se o nome completo do pacote para
declaração do objeto na classe:

java.awt.Color color;

8.2. Criando pacotes

Para criar os nossos pacotes, escrevemos:

package <nomeDoPacote>;

Suponha que desejamos criar um pacote onde colocaremos a nossa classe


StudentRecord juntamente com outras classes relacionadas. Chamaremos o

Introdução à Programação I 23
JEDITM

nosso pacote de schoolClasses.

A primeira coisa que temos que fazer é criar uma pasta chamada
schoolClasses. Em seguida, copiar para esta pasta todas as classes que
pertençam a este pacote. Adicione a seguinte instrução no arquivo da classe,
esta linha deve ser colocada antes da definição da classe. Por exemplo:

package schoolClasses;

public class StudentRecord {


// instruções da classe
}

Pacotes podem ser aninhados. Neste caso, o interpretador espera que a


estrutura de diretórios contendo as classes combinem com a hierarquia dos
pacotes.

8.3. Definindo a variável de ambiente CLASSPATH

Suponha que colocamos o pacote schoolClasses sob o diretório C:\.


Precisamos que a classpath aponte para este diretório de tal forma que
quando executemos a classe, a JVM seja capaz de enxergar onde está
armazenada.

Antes de discutirmos como ajustar a variável classpath, vamos ver um


exemplo sobre o que aconteceria se esta não fosse ajustada.

Suponha que sigamos os passos para compilar e executar a classe


StudentRecord que escrevemos:

C:\schoolClasses>javac StudentRecord.java

C:\schoolClasses>java StudentRecord
Exception in thread "main" java.lang.NoClassDefFoundError: StudentRecord
(wrong name: schoolClasses/StudentRecord)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)

Surge o erro NoClassDefFoundError, que significa que o Java desconhece


onde procurar por esta classe. A razão disso é que a sua classe

Introdução à Programação I 24
JEDITM

StudentRecord pertence a um pacote denominado schoolClasses. Se


desejamos executar esta classe, teremos que dizer ao Java o seu nome
completo schoolClasses.StudentRecord. Também teremos que dizer à JVM
onde procurar pelos nossos pacotes, que, neste caso, é no C:\. Para fazer isso,
devemos definir a variável classpath.

Para definir a variável classpath no Windows, digitamos o seguinte na linha


de comando:

C:\schoolClasses>set classpath=C:\

onde C:\ é o diretório onde colocamos os pacotes. Após definir a variável


classpath, poderemos executar a nossa classe em qualquer pasta, digitando:

C:\schoolClasses>java schoolClasses.StudentRecord

Para sistemas baseados no Unix, suponha que as nossas classes estejam no


diretório /usr/local/myClasses, escrevemos:

export classpath=/usr/local/myClasses

Observe que é possível definir a variável classpath em qualquer lugar. É


possível definir mais de um local de pesquisa; basta separá-los por ponto-e-
vírgula (no Windows) e dois-pontos (nos sistemas baseados em Unix). Por
exemplo:

set classpath=C:\myClasses;D:\;E:\MyPrograms\Java

e para sistemas baseados no Unix:

export classpath=/usr/local/java:/usr/myClasses

Introdução à Programação I 25
JEDITM

9. Modificadores de Acesso

Quando estamos criando as nossas classes e definindo as suas propriedades e


métodos, queremos implementar algum tipo de restrição para se acessar esses
dados. Por exemplo, ao necessitar que um certo atributo seja modificado
apenas pelos métodos dentro da classe, é possível esconder isso dos outros
objetos que estejam usando a sua classe. Para implementar isso, no Java,
temos os modificadores de acesso.

Existem quatro diferentes tipos de modificadores de acesso: public, private,


protected e default. Os três primeiros modificadores são escritos
explicitamente no código para indicar o acesso, para o tipo default, não se
utiliza nenhuma palavra-chave.

9.1. Acesso padrão

Especifica que os elementos da classe são acessíveis somente aos métodos


internos da classe e às suas subclasses. Não há palavra chave para o
modificador default; sendo aplicado na ausência de um modificador de
acesso. Por exemplo :

public class StudentRecord {


// acesso padrão ao atributo
int name;

// acesso padrão para o método


String getName(){
return name;
}
}

O atributo de objeto name e o método getName() podem ser acessados


somente por métodos internos à classe e por subclasses de StudentRecord.
Falaremos sobre subclasses em próximas lições.

9.2. Acesso público

Especifica que os elementos da classe são acessíveis tanto internamente


quanto externamente à classe. Qualquer objeto que interage com a classe
pode ter acesso aos elementos públicos da classe. Por exemplo:

public class StudentRecord {


// acesso público o atributo
public int name;

// acesso público para o método

Introdução à Programação I 26
JEDITM

public String getName(){


return name;
}
}

O atributo de objeto name e o método getName() podem ser acessados a


partir de outros objetos.

9.3. Acesso protegido

Especifica que somente classes no mesmo pacote podem ter acesso aos
atributos e métodos da classe. Por exemplo:

public class StudentRecord {


//acesso protegido ao atributo
protected int name;

//acesso protegido para o método


protected String getName(){
return name;
}
}

O atributo de objeto name e o método getName() podem ser acessados por


outros objetos, desde que o objetos pertençam ao mesmo pacote da classe
StudentRecord.

9.4. Acesso particular

Especifica que os elementos da classe são acessíveis somente na classe que o


definiu. Por exemplo:

public class StudentRecord {


// acesso particular ao atributo
private int name;

// acesso particular para o método


private String getName(){
return name;
}
}

O atributo de objeto name e o método getName() podem ser acessados


somente por métodos internos à classe.

Introdução à Programação I 27
JEDITM

Dicas de programação:

1. Normalmente, os atributos de objeto de uma classe devem ser


declarados particulares e a classe pode fornecer métodos
assessores e modificadores para estes.

Introdução à Programação I 28
JEDITM

10. Exercícios

10.1. Registro de Agenda

Sua tarefa é criar uma classe que contenha um Registro de Agenda. A tabela
1 descreve as informações que um Registro de Agenda deve conter:

Atributos/Propriedades Descrição
Nome Nome da pessoa
Endereço Endereço da pessoa
Número de Telefone Número de telefone da pessoa
email Endereço eletrônico da pessoa
Tabela 1: Atributos e Descrições dos Atributos

Crie os seguintes métodos:

1. Forneça todos os métodos assessores e modificadores necessários para


todos os atributos.
2. Construtores.

10.2. Agenda

Crie uma classe Agenda que possa conter entradas de objetos tipo Registro de
Agenda (utilize a classe criada no primeiro exercício). Devem ser oferecidos os
seguintes métodos para a agenda:

1. Adicionar registro
2. Excluir registro
3. Visualizar registros
4. Modificar um registro

Introdução à Programação I 29
Módulo 1
Introdução à Programação I

Lição 11
Herança, polimorfismo e interfaces

Versão 1.0 - Jan/2007


JEDITM

1. Objetivos

Nesta lição será discutido como uma classe pode herdar as propriedades de outra classe já
existente. Uma classe que faz isso é chamada de subclasse, e sua classe pai é chamada de
superclasse. Será também discutida a aplicação automática dos métodos de cada objeto,
independente da subclasse deste. Esta propriedade é conhecida como polimorfismo. E, por
último, discutiremos sobre interfaces, que ajudam a reduzir no esforço de programação.

Ao final desta lição, o estudante será capaz de:

• Definir superclasses e subclasses


• Criar override de métodos das superclasses
• Criar métodos final e classes final

Introdução à Programação I 4
JEDITM

2. Herança

Todas as classes, incluindo as que compõem a API Java, são subclasses da classe Object. Um
exemplo de hierarquia de classes é mostrado com a figura 1.

A partir de uma determinada classe, qualquer classe acima desta na hierarquia de classes é
conhecida como uma superclasse (ou classe Pai). Enquanto que qualquer classe abaixo na
hierarquia de classes é conhecia como uma subclasse (ou classe Filho).

Figura 1: Hierarquia de Classes

Herança é um dos principais princípios em orientação a objeto. Um comportamento (método) é


definido e codificado uma única vez em uma única classe e este comportamento é herdado por
todas suas subclasses. Uma subclasse precisa apenas implementar as diferenças em relação a
sua classe pai, ou seja, adaptar-se ao meio em que vive.

2.1. Definindo Superclasses e Subclasses


Para herdar uma classe usamos a palavra-chave extends. Ilustraremos criando uma classe
pai de exemplo. Suponha que tenhamos uma classe pai chamada Person.

public class Person {


protected String name;
protected String address;

/**
* Construtor Padrão
*/
public Person(){
System.out.println("Inside Person:Constructor");
name = "";
address = "";
}
/**
* Construtor com 2 parâmetros
*/
public Person( String name, String address ){
this.name = name;
this.address = address;
}
/**
* Métodos modificadores e acessores
*/
public String getName(){
return name;

Introdução à Programação I 5
JEDITM

}
public String getAddress(){
return address;
}
public void setName( String name ){
this.name = name;
}
public void setAddress( String add ){
this.address = add;
}
}

Os atributos name e address são declarados como protected. A razão de termos feito isto é
que queremos que estes atributos sejam acessíveis às subclasses dessa classe. Se a
declararmos com o modificador private, as subclasses não estarão aptas a usá-los. Todas as
propriedades de uma superclasse que são declaradas como public, protected e default
podem ser acessadas por suas subclasses.

Vamos criar outra classe chamada Student. E, como um estudante também é uma pessoa,
concluímos que iremos estender a classe Person, então, poderemos herdar todas as
propriedades existêntes na classe Person. Para isto, escrevemos:

public class Student extends Person {


public Student(){
System.out.println("Inside Student:Constructor");
//Algum código aqui
}

// Algum código aqui


}

O fluxo de controle é mostrado na figura 2.

Figura 2: Fluxo do Programa

Quando a classe Student for instanciada, o construtor padrão da superclasse Person é


invocado implicitamente para fazer as inicializações necessárias. Após isso, as instruções
dentro do construtor da subclasse são executadas. Para ilustrar, considere o seguinte código:

Introdução à Programação I 6
JEDITM

public static void main( String[] args ){


Student anna = new Student();
}

No código, criamos um objeto da classe Student. O resultado da execução deste programa é:

Inside Person:Constructor
Inside Student:Constructor

2.2. super
Uma subclasse pode, explicitamente, chamar um construtor de sua superclasse imediata. Isso
é feito utilizando uma chamada ao objeto super. Uma chamada ao super no construtor de
uma subclasse irá resultar na execução de um construtor específico da superclasse baseado
nos argumentos passados.

Por exemplo, dada a seguinte instrução para a classe Student:

public Student(){
super( "SomeName", "SomeAddress" );
System.out.println("Inside Student:Constructor");
}

Este código chama o segundo construtor de sua superclasse imediata (a classe Person) e a
executa. Outro código de exemplo é mostrado abaixo:

public Student(){
super();
System.out.println("Inside Student:Constructor");
}

Este código chama o construtor padrão de sua superclasse imediata (a classe Person) e o
executa.

Devemos relembrar, quando usamos uma chamada ao objeto super:

1. A instrução super() DEVE SER A PRIMEIRA INSTRUÇÃO EM UM CONSTRUTOR.


2. As instruções this() e super() não podem ocorrer simultaneamente no mesmo construtor.

O objeto super é uma referência aos membros da superclasse (assim como o objeto this é da
sua própria classe). Por exemplo:

public Student() {
super.name = "person name"; // Nome da classe pai
this.name = "student name"; // Nome da classe atual
}

2.3. Override de Métodos


Se, por alguma razão, uma classe derivada necessita que a implementação de algum método
seja diferente da superclasse, o polimorfismo por override pode vir a ser muito útil. Uma
subclasse pode modificar um método definido em sua superclasse fornecendo uma nova
implementação para aquele método.

Introdução à Programação I 7
JEDITM

Supondo que tenhamos a seguinte implementação para o método getName da superclasse


Person:

public class Person {


...
public String getName(){
System.out.println("Parent: getName");
return name;
}
...
}

Para realizar um polimorfismo por override no método getName da subclasse Student,


escrevemos:

public class Student extends Person {


...
public String getName(){
System.out.println("Student: getName");
return name;
}
...
}

Então, quando invocarmos o método getName de um objeto da classe Student, o método


chamado será o de Student, e a saída será:

Student: getName

É possível chamar o método getName da superclasse, basta para isso:

public class Student extends Person {


...
public String getName() {
super.getName();
System.out.println("Student: getName");
return name;
}
...
}

Inserimos uma chamada ao objeto super e a saída será:

Parent: getName
Student: getName

2.4. Métodos final e Classes final


Podemos declarar classes que não permitem a herança. Estas classes são chamadas classes
finais. Para definir que uma classe seja final, adicionamos a palavra-chave final na declaração
da classe (na posição do modificador). Por exemplo, desejamos que a classe Person não
possa ser herdada por nenhuma outra classe, escrevemos:

public final class Person {


// Código da classe aqui
}

Introdução à Programação I 8
JEDITM

Muitas classes na API Java são declaradas final para certificar que seu comportamento não
seja herdado e, possivelmente , modificado. Exemplos, são as classes Integer, Double e Math.

Também é possível criar métodos que não possam ser modificados pelos filhos, impedindo o
polimorfismo por override. Estes métodos são o que chamamos de métodos finais. Para
declarar um método final, adicionamos a palavra-chave final na declaração do método (na
posição do modificador). Por exemplo, se queremos que o método getName da classe Person
não possa ser modificado, escrevemos:

public final String getName(){


return name;
}

Caso o programador tente herdar uma classe final, ocorrerá um erro de compilação. O mesmo
acontecerá ao se tentar fazer um override de um método final.

Introdução à Programação I 9
JEDITM

3. Polimorfismo
Considerando a classe pai Person e a subclasse Student do exemplo anterior, adicionaremos
outra subclasse a Person, que se chamará Employee. Abaixo está a hierarquia de classes que
ilustra o cenário:

Figura 3: Hieraquia para a classe Person e suas subclasses.

Podemos criar uma referência do tipo da superclasse para a subclasse. Por exemplo:

public static main( String[] args ) {


Person ref;
Student studentObject = new Student();
Employee employeeObject = new Employee();
ref = studentObject; //Person ref: ponteiro para um Student

// algum código aqui


}

Supondo que tenhamos um método getName em nossa superclasse Person, iremos realizar
uma modificação deste nas subclasses Student e Employee:

public class Person {


public String getName(){
System.out.println("Person Name:" + name);
return name;
}
}
public class Student extends Person {
public String getName(){
System.out.println("Student Name:" + name);
return name;
}
}
public class Employee extends Person {
public String getName(){
System.out.println("Employee Name:" + name);
return name;
}
}

Voltando ao método main, quando tentamos chamar o método getName da referência ref do
tipo Person, o método getName do objeto Student será chamado. Agora, se atribuirmos ref
ao objeto Employee, o método getName de Employee será chamado.

public static main(String[] args) {


Person ref;
Student studentObject = new Student();
Employee employeeObject = new Employee();
ref = studentObject; //ponteiro de referência para um Student
String temp = ref.getName(); //getName de Student é chamado

Introdução à Programação I 10
JEDITM

System.out.println(temp);
ref = employeeObject; // ponteiro de referência Person para um
// objeto Employee
String temp = ref.getName(); // getName de Employee
// classe é chamada
System.out.println(temp);
}

A capacidade de uma referência mudar de comportamento de acordo com o objeto a que se


refere é chamada de polimorfismo. O polimorfismo permite que múltiplos objetos de
diferentes subclasses sejam tratados como objetos de uma única superclasse, e que
automaticamente sejam selecionados os métodos adequados a serem aplicados a um objeto
em particular, baseado na subclasse a que ele pertença.

Outro exemplo que demonstra o polimorfismo é realizado ao passar uma referência a métodos.
Supondo que exista um método estático printInformation que recebe como parâmetro um
objeto do tipo Person, pode-se passar uma referência do tipo Employee e do tipo Student,
porque são subclasses do tipo Person.

public static main(String[] args) {


Student studentObject = new Student();
Employee employeeObject = new Employee();
printInformation(studentObject);
printInformation(employeeObject);
}
public static printInformation(Person p){
...
}

Introdução à Programação I 11
JEDITM

4. Classes Abstratas
Para criar métodos em classes devemos, necessariamente, saber qual o seu comportamento.
Entretanto, em muitos casos não sabemos como estes métodos se comportarão na classe que
estamos criando, e, por mera questão de padronização, desejamos que as classes que herdem
desta classe possuam, obrigatoriamente, estes métodos.

Por exemplo, queremos criar uma superclasse chamada LivingThing. Esta classe tem certos
métodos como breath, sleep e walk. Entretanto, existem tantos métodos nesta superclasse
que não podemos generalizar este comportamento. Tome por exemplo, o método walk
(andar). Nem todos os seres vivos andam da mesma maneira. Tomando os humanos como
exemplo, os humanos andam sobre duas pernas, enquanto que outros seres vivos como os
cães andam sobre quatro. Entretanto, existem muitas características que os seres vivos têm
em comum, isto é o que nós queremos ao criar uma superclasse geral.

Figura 4: Classe Abstrata

Para realizarmos isto, teremos que criar uma superclasse que possua alguns métodos com
implementações e outros não. Este tipo de classe é chamada de classe abstrata.

Uma classe abstrata é uma classe que não pode gerar um objeto. Freqüentemente aparece
no topo de uma hierarquia de classes no modelo de programação orientada a objetos.

Os métodos nas classes abstratas que não têm implementação são chamados de métodos
abstratos. Para criar um método abstrato, apenas escreva a assinatura do método sem o
corpo e use a palavra-chave abstract. Por exemplo:

public abstract void someMethod();

Agora, vamos criar um exemplo de classe abstrata:

public abstract class LivingThing {


public void breath(){
System.out.println("Living Thing breathing...");
}
public void eat(){
System.out.println("Living Thing eating...");
}
/**
* método abstrato walk
* Queremos que este método seja criado pela
* subclasse de LivingThing
*/
public abstract void walk();
}

Quando uma classe estende a classe abstrata LivingThing, ela é obrigada a implementar o
método abstrato walk. Por exemplo:

Introdução à Programação I 12
JEDITM

public class Human extends LivingThing {


public void walk(){
System.out.println("Human walks...");
}
}

Se a classe Human não implementar o método walk, será mostrada a seguinte mensagem de
erro de compilação:

Human.java:1: Human is not abstract and does not override abstract


method walk() in LivingThing
public class Human extends LivingThing
^
1 error

Dicas de programação:

1. Use classes abstratas para definir muitos tipos de comportamentos no topo de


uma hierarquia de classes de programação orientada a objetos. Use suas
subclasses para prover detalhes de implementação da classe abstrata.

Introdução à Programação I 13
JEDITM

5. Interfaces
Uma interface é um tipo especial de classe que contém unicamente métodos abstratos ou
atributos finais. Interfaces, por natureza, são abstratas.

Interfaces definem um padrão e o caminho público para especificação do comportamento de


classes. Permitem que classes, independente de sua localização na estrutura hierárquica,
implementem comportamentos comuns.

5.1. Porque utilizar Interfaces?

Utilizamos interfaces quando queremos classes não relacionadas que implementem métodos
similares. Através de interfaces, podemos obter semelhanças entre classes não relacionadas
sem forçar um relacionamento artificial entre elas.

Tomemos como exemplo a classe Line, contém métodos que obtém o tamanho da linha e
compara o objeto Line com objetos de mesma classe. Considere também que tenhamos outra
classe, MyInteger, que contém métodos que comparam um objeto MyInteger com objetos
da mesma classe. Podemos ver que ambas classes têm os mesmos métodos similares que os
comparam com outros objetos do mesmo tipo, entretanto eles não são relacionados. Para se
ter certeza de que essas classes implementem os mesmos métodos com as mesmas
assinaturas, utilizamos as interfaces. Podemos criar uma interface Relation que terá
declarada algumas assinaturas de métodos de comparação. A interface Relation pode ser
implementada da seguinte forma:

public interface Relation {


public boolean isGreater(Object a, Object b);
public boolean isLess(Object a, Object b);
public boolean isEqual(Object a, Object b);
}

Outra razão para se utilizar interfaces na programação de objetos é revelar uma interface de
programação de objeto sem revelar essas classes. Como veremos mais adiante, podemos
utilizar uma interface como tipo de dados.

Finalmente, precisamos utilizar interfaces como mecanismo alternativo para herança múltipla,
que permite às classes em ter mais de uma superclasse. A herança múltipla não está
implementada em Java.

5.2. Interface vs. Classe Abstrata

A principal diferença entre uma interface e uma classe abstrata é que a classe abstrata
pode possuir métodos implementados (reais) ou não implementados (abstratos). Na interface,
todos os métodos são obrigatoriamente abstratos e públicos, tanto que para esta, a palavra-
chave abstract ou public é opcional.

5.3. Interface vs. Classe

Uma característica comum entre uma interface e uma classe é que ambas são tipos. Isto
significa que uma interface pode ser usada no lugar onde uma classe é esperada. Por exemplo,

Introdução à Programação I 14
JEDITM

dadas a classe Person e a interface PersonInterface, as seguintes declarações são válidas:

PersonInterface pi = new Person();


Person pc = new Person();

Entretanto, não se pode criar uma instância de uma interface sem implementá-la. Um exemplo
disso é:

PersonInterface pi = new PersonInterface(); //ERRO DE


//COMPILAÇÃO !!!

Outra característica comum é que ambas, interfaces e classes, podem definir métodos, embora
uma interface não possa tê-los implementados. Já uma classe pode.

5.4. Criando Interfaces

Para criarmos uma interface, utilizamos:

[public] [abstract] interface <NomeDaInterface> {


< [public] [final] <tipoAtributo> <atributo> = <valorInicial>; >*
< [public] [abstract] <retorno> <nomeMetodo>(<parametro>*); >*
}

Como exemplo, criaremos uma interface que define o relacionamento entre dois objetos de
acordo com a "ordem natural" dos objetos:

interface Relation {
boolean isGreater(Object a, Object b);
boolean isLess(Object a, Object b);
boolean isEqual( Object a, Object b);
}

Para implementar esta interface, usaremos a palavra chave "implements". Por exemplo:

/**
* Esta classe define um segmento de linha
*/
public class Line implements Relation {
private double x1;
private double x2;
private double y1;
private double y2;
public Line(double x1, double x2, double y1, double y2) {
this.x1 = x1;
this.x2 = x2;
this.y2 = y2;
this.y1 = y1;
}
public double getLength(){
double length = Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
return length;
}
public boolean isGreater( Object a, Object b){
double aLen = ((Line)a).getLength();
double bLen = ((Line)b).getLength();
return (aLen > bLen);

Introdução à Programação I 15
JEDITM

}
public boolean isLess( Object a, Object b){
double aLen = ((Line)a).getLength();
double bLen = ((Line)b).getLength();
return (aLen < bLen);
}
public boolean isEqual( Object a, Object b){
double aLen = ((Line)a).getLength();
double bLen = ((Line)b).getLength();
return (aLen == bLen);
}
}

Quando a classe implementa uma interface, deve-se implementar todos os métodos desta,
caso contrário será mostrado o erro:

Line.java:4: Line is not abstract and does not override abstract


method isGreater(java.lang.Object,java.lang.Object) in Relation
public class Line implements Relation
^
1 error

Dicas de programação:

1. Use interface para criar uma definição padrão de métodos em classes diferentes.
Uma vez que o conjunto de definições de métodos é criado, e pode ser escrito
um método simples para manipular todas as classes que implementam a
interface.

5.5. Relacionamento de uma Interface para uma Classe


Como vimos nas seções anteriores, a classe pode implementar uma interface e para isso
prover o código de implementação para todos os métodos definidos na interface.

Outro detalhe a se notar na relação entre uma interface e uma classe. A classe pode apenas
estender uma única superclasse, mas pode implementar diversas interfaces. Um exemplo de
uma classe que implementa diversas interfaces:

public class Person


implements PersonInterface, LivingThing, WhateverInterface {
//algumas linhas de código
}

Outro exemplo de uma classe que estende de outra superclasse e implementa interfaces:

public class ComputerScienceStudent extends Student


implements PersonInterface, LivingThing {
// algumas linhas de código
}

Uma interface não é parte de uma hierarquia de classes. Classes não relacionadas podem
implementar a mesma interface.

Introdução à Programação I 16
JEDITM

5.6. Herança entre Interfaces


Interfaces não são partes de uma hierarquia de classes. Entretanto, interfaces podem ter
relacionamentos entre si. Por exemplo, suponha que tenhamos duas interfaces,
StudentInterface e PersonInterface. Se StudentInterface estende PersonInterface,
esta herda todos os métodos declarados em PersonInteface.

public interface PersonInterface {


...
}
public interface StudentInterface extends PersonInterface {
...
}

Introdução à Programação I 17
JEDITM

6. Exercícios
6.1. Estendendo StudentRecord
Neste exercício, queremos criar um registro mais especializado de Student que contém
informações adicionais sobre um estudante de Ciência da Computação. Sua tarefa é estender a
classe StudentRecord que foi implementada nas lições anteriores e acrescentar atributos e
métodos que são necessários para um registro de um estudante de Ciência da Computação.
Utilize override para modificar alguns métodos da superclasse StudentRecord, caso seja
necessário.

6.2. A classe abstrata Shape


Crie uma classe abstrata chamada Shape com os métodos abstratos getArea() e
getName(). Escreva duas de suas subclasses Circle e Square. E acrescente métodos
adicionais a estas subclasses.

Introdução à Programação I 18
Módulo 1
Introdução à Programação I

Lição 12
Tratamento básico de exceções

Versão 1.0 - Jan/2007


JEDITM

1. Objetivos

Nesta lição, iremos aprender uma técnica utilizada em Java para tratar condições incomuns
que interrompem a operação normal da classe. Esta técnica é chamada de tratamento de
exceção.

Ao final desta lição, o estudante será capaz de:

• Definir o que são exceções


• Tratar exceções utilizando try-catch-finally

Introdução à Programação I 4
JEDITM

2. O que são Exceções (Exception)?

Uma exceção é um evento que interrompe o fluxo normal de processamento de uma classe.
Este evento é um erro de algum tipo. Isto causa o término anormal da classe.

Estes são alguns dos exemplos de exceções que podem ter ocorridos em exercícios anteriores:

● ArrayIndexOutOfBoundsException, ocorre ao acessar um elemento inexistente de


um array.

● NumberFormatException, ocorre ao enviar um parâmetro não-numérico para o


método Integer.parseInt().

Introdução à Programação I 5
JEDITM

3. Tratando Exceções

Para tratar exceções em Java utilizamos a declaração try-catch-finally. O que devemos fazer
para proteger as instruções passíveis de gerar uma exceção, é inserí-las dentro deste bloco.

A forma geral de um try-catch-finally é:

try{
// escreva as instruções passíveis de gerar uma exceção
// neste bloco
} catch (<exceptionType1> <varName1>){
// escreva a ação que o seu programa fará caso ocorra
// uma exceção de um determinado
} . . .
} catch (<exceptionTypen> <varNamen>){
// escreva a ação que o seu programa fará caso ocorra
// uma exceção de um determinado tipo
} finally {
// escreva a ação que o seu programa executará caso ocorra
// ou não um erro ou exceção
}

Exceções geradas durante a execução do bloco try podem ser detectadas e tratadas num
bloco catch. O código no bloco finally é sempre executado, ocorrendo ou não a exceção.

A seguir são mostrados os principais aspectos da sintaxe da construção de um try-catch-


finally:

• A notação de bloco é obrigatória.


• Para cada bloco try, pode haver um ou mais blocos catch, mas somente um bloco
finally.
• Um bloco try deve que ser seguido de PELO MENOS um bloco catch OU um bloco
finally, ou ambos.
• Cada bloco catch define o tratamento de uma exceção.
• O cabeçalho do bloco catch recebe somente um argumento, que é a exceção
(Exception) que este bloco pretende tratar.
• A exceção deve ser da classe Throwable ou de uma de suas subclasses.

Para um melhor entendimento, observe a figura 1 que demonstra o fluxo seguido pelo try-
catch-finally:

Introdução à Programação I 6
JEDITM

Figura 1: Fluxo em um try-catch-finally

Tomemos, por exemplo, uma classe que imprime o segundo argumento passado através da
linha de comandos. Supondo que não há verificação no código para o número de argumentos.

public class ExceptionExample {


public static void main( String[] args ) {
System.out.println(args[1]);
System.out.println("Finish");
}
}

Ao executar esta classe sem informar nenhum argumento e, ao tentar acessar diretamente,
conforme o exemplo descrito, o segundo argumento args[1], uma exceção é obtida que
interromperá a execução normal do programa, e a seguinte mensagem será mostrada:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1


at ExceptionExample.main(ExceptionExample.java:5)

Para prevenir que isto ocorra, podemos colocar o código dentro de um bloco try-catch. O
bloco finally é opcional. Neste exemplo, não utilizaremos o bloco finally.
public class ExceptionExample
{
public static void main( String[] args ){

try {
System.out.println( args[1] );
} catch (ArrayIndexOutOfBoundsException exp) {
System.out.println("Exception caught!");

Introdução à Programação I 7
JEDITM

}
System.out.println("Finish");
}
}

Assim, quando tentarmos rodar o programa novamente sem a informação dos argumentos, a
saída trataria a exceção e o fluxo do programa não seria interrompido, mostrando o resultado:

Exception caught!
Finish

Introdução à Programação I 8
JEDITM

4. Exercícios
4.1. Capturando Exceções 1
Dada a seguinte classe:

public class TestException {


public static void main(String[] args) {
for (int i=0; true; i++) {
System.out.println("args["+i+"]="+ args[i]);
}
System.out.println("Quiting...");
}
}

Compile e rode a classe TestException. E como saída será:

java TestExceptions one two three


args[0]=one
args[1]=two
args[2]=three
Exception in thread "main"
java.lang.ArrayIndexOutOfBoundsException: 3
at TestExceptions.main(1.java:4)

Modifique a classe TestException para tratar esta exceção. A saída depois do tratamento da
exceção deverá ser:

java TestExceptions one two three


args[0]=one
args[1]=two
args[2]=three
Exception caught: java.lang.ArrayIndexOutOfBoundsException: 3
Quiting...

4.2. Capturando Exceções 2


Há uma boa chance de que algumas classes escritas anteriormentes tenham disparados
exceções. Como as exceções não foram tratadas, simplesmente interromperam a execução.
Retorne a estes programas e implemente o tratamento de exceções.

Introdução à Programação I 9
Módulo 1
Introdução à Programação 1

Apêndice A
Instalação do Java e do NetBeans

Versão 1.0 - Jan/2007


JEDITM

1. Objetivos
Neste apêndice, veremos como instalar o Java, versão JDK, e o NetBeans no seu sistema
(Ubuntu Dapper/Windows). Efetue os downloads na página web da Sun Microsystems no
endereço http://java.sun.com para o JDK 5.0.x e na página web do projeto NetBeans no
endereço http://www.netbeans.org/downloads para o NetBeans 5.5. Antes de começar a
instalação, copie, primeiramente, os arquivos instaladores para seu disco rígido.

Para Ubuntu Dapper:


Copie todos os instaladores para a pasta /usr.

Para Windows:
Copie os instaladores em qualquer diretório temporário.

Introdução à Programação I 4
JEDITM

2. Instalando Java no Ubuntu Dapper

Passo 1: No diretório onde foi efetuado o download dos instaladores.

Passo 2: Antes de executar o instalador, assegure-se de que o arquivo seja um executável.


Para tanto, pressione o botão direito do mouse no ícone do instalador, e em seguida selecione
Properties. Selecione na aba Permissions, e então marque a opção Execute. Feche a
janela.

Passo 3: Duplo-clique no arquivo jdk-1_5_0_07-linux-i586.bin. A caixa de diálogo abaixo


será mostrada. Pressione o botão Run in Terminal.

Introdução à Programação I 5
JEDITM

No console será mostrado o contrato de licença do software.

Pressione ENTER até ser mostrada a pergunta: Do you agree to the above license terms?
[yes or no]. Caso concorde com os termos apresentados digite a palavra yes e pressione a
tecla ENTER. Aguarde que o instalador termine de descompactar e instale o Java.

Passo 4: Devemos um caminho de pesquisa a fim de permitir a execução de comandos java


em qualquer local. Para isto, entraremos na pasta /usr/local/bin. Digitando:

cd /usr/local/bin

Introdução à Programação I 6
JEDITM

Para criar os links simbólicos para os comandos, tecle:

sudo ln -s /usr/java/jdk1.5.0_07/bin/* .

Introdução à Programação I 7
JEDITM

3. Instalando Java no Windows


Passo 1: Utilizando o Windows Explorer, vá até a pasta onde estiver o instalador Java.

Figura 1: Pasta contendo os instaladores

Passo 2: Para executar o instalador, duplo-clique no ícone. A caixa de diálogo do instalador


J2SE será mostrada com o contrato. Selecione a opção I accept the terms in the license
agreement caso concorde com os termos apresentados e pressione o botão Next >.

Figura 2: Contrato de Licença

Esta próxima janela define o que será instalado. Pressione o botão Next > para continuar a
instalação.

Introdução à Programação I 8
JEDITM

Figura 3: Instalação Customizada

O processo de instalação poderá demorar um pouco, ao término a seguinte janela será


mostrada, pressione o botão Finish para completar a instalação.

Figura 4: Fim da instalação

Introdução à Programação I 9
JEDITM

4. Instalando NetBeans no Ubuntu Dapper


Passo 1: Vá para a pasta onde estiver o instalador do NetBeans.

Passo 2: Antes de executar o instalador, assegure-se de que o arquivo seja executável. Para
tanto, utilize o botão direito do mouse no ícone do instalador e, em seguida selecione
Properties. Selecione a aba Permissions, e marque a opção Execute. Encerre a janela.

Introdução à Programação I 10
JEDITM

Passo 3: Duplo-clique no arquivo de instalação do NetBeans. Pressione o botão Run in


Terminal.

Será mostrada uma caixa de diálogo do NetBeans 5.5. Pressione o botão Next >.

Na próxima janela o termos da licença serão mostrados, caso concorde selecione a opção I
accept the terms in the license agreement, e então pressione o botão Next >.

Introdução à Programação I 11
JEDITM

Modifique o nome do diretório para: /usr/java/netbeans-5.5, então pressione o botão Next >.

Na pasta do JDK, selecione /usr/java/jdk1.5.0_07, e então pressione o botão Next >.

Introdução à Programação I 12
JEDITM

A próxima caixa de diálogo mostra apenas informações sobre o NetBeans que você está
instalando. Pressione o botão Next >. Aguarde o NetBeans terminar o processo de instalação.

Pressione o botão Finish para completar a instalação.

Introdução à Programação I 13
JEDITM

Passo 4: A fim de possibilitar a execução do NetBeans a partir de qualquer pasta no


computador, precisamos criar um caminho de pesquisa. Para isso, entramos na pasta
:/usr/local/bin. com o comando:

cd /usr/local/bin

Crie um caminho de pesquisa para o NetBeans, digitando:

sudo ln -s /usr/java/netbeans-5.5 .

É possível executar o NetBeans a partir de qualquer pasta, digitando:

netbeans &

Introdução à Programação I 14
JEDITM

5. Instalando NetBeans no Windows


Passo 1: Através do Windows Explorer, localize a pasta do instalador do NetBeans.

Figura 5: Arquivo instalador do NetBeans

Passo 2: Para executar o instalador, dê um duplo-clique no ícone do instalador. O assistente


de instalação do NetBeans será mostrado. Pressione o botão Next > para iniciar o processo de
instalação.

Figura 6: Instalação do NetBeans

Introdução à Programação I 15
JEDITM

A página do contrato será mostrada. Caso concorde com os termos selecione a opção I accept
the terms in the license agreement e pressione o botão Next > para continuar.

Figura 7: Contrato de Licença

O instalador solicitará a pasta que deve ser instado o NetBeans. Se desejar modifique a pasta
sugerida pressionando o botão Browse, e ao término pressione o botão Next >.

Figura 8: Selecione o diretório onde o NetBeans será instalado

O próximo passo é selecionar uma JDK existente em seu computador. Pressione o botão Next
> para continuar.

Introdução à Programação I 16
JEDITM

Figura 9: Selecione a JDK a ser utilizada

Em seguida, o instalador informará a localização e o espaço em disco que o NetBeans irá


ocupar depois de instalado no seu computador. Pressione o botão Next > e aguarde o término
da instalação.

Figura 10: Sumário da Instalação

No momento que o NetBeans terminar de ser instalado em seu computador. Pressione o botão
Finish para encerrar o processo.

Introdução à Programação I 17
JEDITM

Figura 11: Instalação efetuada com sucesso

Introdução à Programação I 18
Módulo 1
Introdução à Programação 1

Apêndice B
Conhecendo seu ambiente de
programação (versão Windows XP)

Versão 1.0 - Jan/2007


JEDITM

1. Objetivos
Neste apêndice, discutiremos como escrever, compilar e executar programas em Java. Existem
duas maneiras para se fazer isto: a primeira é utilizando uma console e um editor de texto; e
a segunda é utilizando o NetBeans, que é um Integrated Development Environment
(Ambiente Integrado de Desenvolvimento) ou IDE.

Um IDE é um progama que contempla um construtor de interface gráfica (GUI builder), um


editor de código ou texto, um compilador e um depurador de erros.

Introdução à Programação I 4
JEDITM

2. Primeiro Programa em Java


Antes de entrarmos em detalhes, vejamos o programa em Java que escreveremos:

public class Hello {


/**
* Meu primeiro programa em Java
*/
public static void main(String[] args) {
//imprime o texto "Hello world" na tela
System.out.println("Hello world!");
}
}

Introdução à Programação I 5
JEDITM

3. Utilizando um Editor de Texto e uma Console


Para este exemplo, utilizaremos o editor de texto "Notepad" (Bloco de notas do Windows) para
editar o código-fonte em Java. Podem ser utilizados quaisquer outros editores de texto.
Também será necessário abrir uma janela de console para compilar e executar o programa.

Passo 1: Para iniciar o Notepad, clique em Iniciar  Todos os Programas  Accessórios 


Notepad.

Figura 2: Programa Notepad

Figura 1: Clique em Start  All Programs  Accessories 


Notepad

Passo 2: Para abrir uma janela de console, clique em Start  Programs  Accessories 
Comand Prompt.

Figura 3: Janela de Console do Windows

Passo 3: Escreva o código-fonte, descrito na seção 2, no editor:

Introdução à Programação I 6
JEDITM

Passo 4: Salve o programa em um arquivo chamado "Hello.java" dentro de uma pasta


chamada MYJAVAPROGRAMS. Selecione no menu a opção File na barra de menus e então
selecione a opção Save.

Depois de executar o procedimento acima descrito, uma caixa de diálogo será mostrada,
conforme a Figura 4.

Figura 4: Esta caixa de diálogo aparece depois de clicar em File  Save

Pressione o botão MY DOCUMENTS para abrir a pasta My Documents onde salvaremos nossos
programas em Java.

Introdução à Programação I 7
JEDITM

Figura 5: Selecione no botão circulado.

Criaremos uma nova pasta, dentro da pasta My Documents, onde salvaremos nossos
programas. Iremos nomeá-la como MYJAVAPROGRAMS. Pressione o botão circulado conforme
mostrado na Figura 6 para criar a pasta.

Figura 6: Clicar no botão circulado criará uma nova pasta.

Após criar a pasta, digite o nome MYJAVAPROGRAMS, e então pressione a tecla ENTER.

Introdução à Programação I 8
JEDITM

Criamos a pasta aonde salvaremos os arquivos, dê um duplo-clique nesta para abrí-la. Será
mostrada uma janela como a figura seguinte. A pasta deverá estar vazia por ora, pois foi
recém-criada e ainda não foi salvo nenhum arquivo.

Selecione a caixa de seleção Save as type, a fim de que possamos escolher o tipo de arquivo
que queremos salvar. Marque a opção All Files.

Introdução à Programação I 9
JEDITM

Digite "Hello.java" como nome do seu programa na caixa de texto Filename, e então
pressione o botão Save.

Observe que o título da janela mudou de Untitled - Notepad para Hello.java - Notepad.
Para efetuar alterações no arquivo, edite-o, e então salve-o novamente através das opções File
 Save.

Introdução à Programação I 10
JEDITM

Passo 5: Para compilar o programa, utilizaremos a janela de console aberta no passo 2.


Normalmente, esta janela é iniciada no que chamamos de home folder (pasta do usuário).
Para ver uma lista do conteúdo desta pasta, digite DIR e pressione Enter. Será mostrada uma
lista de arquivos e pastas que estão dentro desta.

Figura 7: Lista de arquivos e pastas mostrados depois de executar o comando DIR.

Existe uma pasta chamada "My Documents" onde criamos a pasta MYJAVAPROGRAMS. Iremos
para este diretório. Para entrar em um diretório, digite o comando: cd [nome do diretório].
O comando "cd" significa "Change Directory". Neste caso, já que o nome de nosso diretório é
My Documents, digite: cd My Documents e pressione Enter.

Introdução à Programação I 11
JEDITM

Figura 8: Dentro da pasta My Documents

Estamos dentro da pasta "My Documents", digite o comando "dir" novamente.

Figura 9: O contéudo de My Documents

Execute os mesmos passos descritos para entrar na pasta MYJAVAPROGRAMS.

Figura 10: Dentro da pasta MYJAVAPROGRAMS

Um vez nesta pasta onde seus programas estão localizados, iremos compilar o programa.
Certifique-se de assegurar de que o arquivo está localizado nessa pasta. Para isso, execute o
comando dir e verifique que realmente o arquivo se encontra nesta pasta. Para compilar um
programa em Java, digitamos o comando: javac [nomedoarquivo]. Deste modo, digitamos:
javac Hello.java.

Introdução à Programação I 12
JEDITM

Figura 11: Compilar um programa utilizando comando javac

Durante o processo de compilação, o compilador javac cria um arquivo chamado


[nomedoarquivo].class, neste caso, Hello.class, sendo o arquivo em linguagem de
bytecode.

Passo 6: Para executar o programa, considerando que não existam erros durante a
compilação, digite o comando: java [nomedoarquivo], para nosso exemplo, digite: java
Hello

Veja que na tela que executamos o programa em Java é mostrada a mensagem, "Hello
world!".

Figura 12: Saída do programa

Introdução à Programação I 13
JEDITM

4. Configurando o caminho (Path)


Ao tentar executar o comando javac ou java, é mostrada a mensagem: 'javac' is not
recognized as an internal or external command, operable program or batch file. Isto
significa que ou ainda não foi instalado o Java em seu sistema, ou é necessário configurar o
caminho de pesquisa (path) onde os aplicativos de Java estão instalados. Dessa forma, seu
sistema saberá aonde procurá-los.

Figura 13: Sistema não reconhece o comando javac

Se o Java foi instalado corretamente em seu sistema, configure a variável PATH para apontar
para a localização dos comandos Java. Para fazer isto, digite: set PATH=C:\Program
Files\Java\jdk1.5.0_01\bin. Isto fará com que seu sistema procure pelos comandos na
pasta C:\Program Files\Java\jdk1.5.0_01\bin, que é o padrão de localização dos arquivos
Java quando de sua instalação. Depois de fazer isto, agora é possível utilizar os comandos
Java.

Figura 14: Configurando o caminho(path) e executando java

Introdução à Programação I 14
JEDITM

5. Utilizando NetBeans
Como já aprendemos a construção de programas de uma forma mais complicada, veremos
como realizar todos estes processos descritos utilizando uma única aplicação. O NetBeans, é
um Ambiente Integrado de Desenvolvimento (Integrated Development Environment ou
IDE). Um IDE é um ambiente de programação, que possui um construtor de interface gráfica
(GUI builder), um editor de código-fonte ou texto, um compilador e um depurador de erros.

Passo 1: Para executar NetBeans, selecione Start  All Programs  NetBeans 5.5  NetBeans
IDE

Depois de aberto o NetBeans, será mostrada uma janela similar a mostrada na Figura 15.

Figura 15: IDE NetBeans

Passo 2: Vamos criar um projeto para o NetBeans. Selecione File  New Project.

Introdução à Programação I 15
JEDITM

Depois disto, uma caixa de diálogo New Project será mostrada.

Na opção Categories selecione General e em Projects selecione Java Application pressione


o botão NEXT.

Introdução à Programação I 16
JEDITM

Uma caixa de diálogo de nova aplicação Java (New Java Application) será mostrada. Na caixa
de texto do nome do projeto (Project Name), digite "HelloApplication".

Figura 16: Altere Project Name

Altere a localização da aplicação (Application Location), pressionando no botão Browse... Siga


os passos descritos na seção anterior para ir para a pasta MYJAVAPROGRAMS.

Por fim, na caixa de texto Create Main Class, digite Hello como a classe principal, e então
clique no botão FINISH.

Introdução à Programação I 17
JEDITM

Passo 3: Antes de escrever o programa, vamos primeiro descrever a janela principal depois
de criado o projeto. Como mostrado abaixo, NetBeans cria automaticamente o código básico
para seu programa Java. Você pode então adicionar suas próprias declarações para o código
gerado. No lado esquerdo da janela, temos uma lista de pastas e arquivos que o NetBeans
gerou depois de criar o projeto. Isto é tudo que será encontrado na pasta MYJAVAPROGRAMS,
que é onde está configurada a localização do projeto.

Modifique o código gerado pelo NetBeans ignorando as outras partes do programa. Insira a
seguinte instrução: System.out.println("Hello world!");

Passo 4: Para compilar o programa, clique em Build  Build Main Project. Ou, utilize o botão
de atalho para compilar a classe, conforme mostrado na Figura 17.

Figura 17: Botão de atalho para


compilação do código

Se não houver nenhum erro em seu programa, você verá uma mensagem de “build successful”

Introdução à Programação I 18
JEDITM

na janela de saída.

Figura 18: Janela de saída que está localizada abaixo da janela


onde você escreve o código-fonte

Passo 5: Para executar o programa, clique em Run  Run Main Project. Ou utilize o botão de
atalho.

Figura 19: Botão de atalho para execução do programa

A saída do seu programa é mostrada na janela de saída(output window).

Figura 20: Saída de Hello.java

Introdução à Programação I 19
Módulo 1
Introdução à Programação 1

Apêndice C
Respostas dos exercícios

Versão 1.0 - Jan/2007


JEDITM

Autor Necessidades para os Exercícios


Florence Tiu Balagtas Sistemas Operacionais Suportados
NetBeans IDE 5.5 para os seguintes sistemas operacionais:
3. Microsoft Windows XP Profissional SP2 ou superior
4. Mac OS X 10.4.5 ou superior
Equipe 5. Red Hat Fedora Core 3
Joyce Avestro 6. Solaris™ 10 Operating System (SPARC® e x86/x64 Platform Edition)
NetBeans Enterprise Pack, poderá ser executado nas seguintes plataformas:
Florence Balagtas
1. Microsoft Windows 2000 Profissional SP4
Rommel Feria 2. Solaris™ 8 OS (SPARC e x86/x64 Platform Edition) e Solaris 9 OS (SPARC e
Reginald Hutcherson x86/x64 Platform Edition)
Rebecca Ong 3. Várias outras distribuições Linux
John Paul Petines
Configuração Mínima de Hardware
Sang Shin Nota: IDE NetBeans com resolução de tela em 1024x768 pixel
Raghavan Srinivas Sistema Operacional Processador Memória HD Livre
Matthew Thompson
Microsoft Windows 500 MHz Intel Pentium III 512 MB 850 MB
workstation ou equivalente
Linux 500 MHz Intel Pentium III 512 MB 450 MB
workstation ou equivalente
Solaris OS (SPARC) UltraSPARC II 450 MHz 512 MB 450 MB
Solaris OS (x86/x64 AMD Opteron 100 Série 1.8 GHz 512 MB 450 MB
Platform Edition)
Mac OS X PowerPC G4 512 MB 450 MB

Configuração Recomendada de Hardware

Sistema Operacional Processador Memória HD Livre


Microsoft Windows 1.4 GHz Intel Pentium III 1 GB 1 GB
workstation ou equivalente
Linux 1.4 GHz Intel Pentium III 1 GB 850 MB
workstation ou equivalente
Solaris OS (SPARC) UltraSPARC IIIi 1 GHz 1 GB 850 MB
Solaris OS (x86/x64 AMD Opteron 100 Series 1.8 GHz 1 GB 850 MB
Platform Edition)
Mac OS X PowerPC G5 1 GB 850 MB

Requerimentos de Software
NetBeans Enterprise Pack 5.5 executando sobre Java 2 Platform Standard Edition
Development Kit 5.0 ou superior (JDK 5.0, versão 1.5.0_01 ou superior),
contemplando a Java Runtime Environment, ferramentas de desenvolvimento para
compilar, depurar, e executar aplicações escritas em linguagem Java. Sun Java
System Application Server Platform Edition 9.
1. Para Solaris, Windows, e Linux, os arquivos da JDK podem ser obtidos para
sua plataforma em http://java.sun.com/j2se/1.5.0/download.html
2. Para Mac OS X, Java 2 Plataform Standard Edition (J2SE) 5.0 Release 4, pode ser
obtida diretamente da Apple's Developer Connection, no endereço:
http://developer.apple.com/java (é necessário registrar o download da JDK).

Para mais informações:


http://www.netbeans.org/community/releases/55/relnotes.html

Introdução à Programação I 2
JEDITM

Colaboradores que auxiliaram no processo de tradução e revisão


Alexandre Mori Hugo Leonardo Malheiros Ferreira Mauro Regis de Sousa Lima
Alexis da Rocha Silva Ivan Nascimento Fonseca Namor de Sá e Silva
Aline Sabbatini da Silva Alves Jacqueline Susann Barbosa Néres Chaves Rebouças
Allan Wojcik da Silva Jader de Carvalho Belarmino Nolyanne Peixoto Brasil Vieira
André Luiz Moreira João Aurélio Telles da Rocha Paulo Afonso Corrêa
Andro Márcio Correa Louredo João Paulo Cirino Silva de Novais Paulo José Lemos Costa
Antoniele de Assis Lima João Vianney Barrozo Costa Paulo Oliveira Sampaio Reis
Antonio Jose R. Alves Ramos José Augusto Martins Nieviadonski Pedro Antonio Pereira Miranda
Aurélio Soares Neto José Leonardo Borges de Melo Pedro Henrique Pereira de Andrade
Bruno da Silva Bonfim José Ricardo Carneiro Renato Alves Félix
Bruno dos Santos Miranda Kleberth Bezerra G. dos Santos Renato Barbosa da Silva
Bruno Ferreira Rodrigues Lafaiete de Sá Guimarães Reyderson Magela dos Reis
Carlos Alberto Vitorino de Almeida Leandro Silva de Morais Ricardo Ferreira Rodrigues
Carlos Alexandre de Sene Leonardo Leopoldo do Nascimento Ricardo Ulrich Bomfim
Carlos André Noronha de Sousa Leonardo Pereira dos Santos Robson de Oliveira Cunha
Carlos Eduardo Veras Neves Leonardo Rangel de Melo Filardi Rodrigo Pereira Machado
Cleber Ferreira de Sousa Lucas Mauricio Castro e Martins Rodrigo Rosa Miranda Corrêa
Cleyton Artur Soares Urani Luciana Rocha de Oliveira Rodrigo Vaez
Cristiano Borges Ferreira Luís Carlos André Ronie Dotzlaw
Cristiano de Siqueira Pires Luís Octávio Jorge V. Lima Rosely Moreira de Jesus
Derlon Vandri Aliendres Luiz Fernandes de Oliveira Junior Seire Pareja
Fabiano Eduardo de Oliveira Luiz Victor de Andrade Lima Sergio Pomerancblum
Fábio Bombonato Manoel Cotts de Queiroz Silvio Sznifer
Fernando Antonio Mota Trinta Marcello Sandi Pinheiro Suzana da Costa Oliveira
Flávio Alves Gomes Marcelo Ortolan Pazzetto Tásio Vasconcelos da Silveira
Francisco das Chagas Marco Aurélio Martins Bessa Thiago Magela Rodrigues Dias
Francisco Marcio da Silva Marcos Vinicius de Toledo Tiago Gimenez Ribeiro
Gilson Moreno Costa Maria Carolina Ferreira da Silva Vanderlei Carvalho Rodrigues Pinto
Givailson de Souza Neves Massimiliano Giroldi Vanessa dos Santos Almeida
Gustavo Henrique Castellano Mauricio Azevedo Gamarra Vastí Mendes da Silva Rocha
Hebert Julio Gonçalves de Paula Mauricio da Silva Marinho Wagner Eliezer Roncoletta
Heraldo Conceição Domingues Mauro Cardoso Mortoni

Auxiliadores especiais
Revisão Geral do texto para os seguintes Países:
• Brasil – Tiago Flach
• Guiné Bissau – Alfredo Cá, Bunene Sisse e Buon Olossato Quebi – ONG Asas de Socorro

Coordenação do DFJUG
• Daniel deOliveira – JUGLeader responsável pelos acordos de parcerias
• Luci Campos - Idealizadora do DFJUG responsável pelo apoio social
• Fernando Anselmo - Coordenador responsável pelo processo de tradução e revisão,
disponibilização dos materiais e inserção de novos módulos
• Regina Mariani - Coordenadora responsável pela parte jurídica
• Rodrigo Nunes - Coordenador responsável pela parte multimídia
• Sérgio Gomes Veloso - Coordenador responsável pelo ambiente JEDITM (Moodle)

Agradecimento Especial
John Paul Petines – Criador da Iniciativa JEDITM
Rommel Feria – Criador da Iniciativa JEDITM

Introdução à Programação I 3
JEDITM

Lição 1 – Introdução à programação de


computadores
Exercício 1. Escrevendo Algoritmos
1. Assar Pão
Pseudo código:
Preparar todos os ingredientes
Colocar os ingredientes na batedeira
Enquanto a mistura não estiver homogênea
Bater ingredientes
Colocar a mistura em uma forma de pão
Inserir a forma no forno
Enquanto pão não estiver pronto
Esperar
Retirar a forma do forno

Fluxograma:

Introdução à Programação I 4
JEDITM

2. Acessar o computador

Pseudo código:
Fazer power = botão ligar do computador
Fazer in = status do usuário (inicialmente falso)
Se power == off
Pressione o botão ligar
Aguardar o procedimento inicial
Enquanto in == falso
Entrar com o nome do usuário
Entrar com a senha
Se senha e nome do usuário são corretos
in = verdadeiro

Fluxograma:

Introdução à Programação I 5
JEDITM

3. Obter a média de três números


Pseudo código:
Fazer count = 0
Fazer sum = 0
Fazer average = 0
Enquanto count < 3
Obter number
Fazer sum = sum + number
Fazer count = count + 1
Fazer average = sum / 3
Mostrar average

Fluxograma:

Exercício 2. Conversões Numéricas

1. 198010 para binário, hexadecimal e octal


Para Binário:
1980/2 = 990 0
990/2 = 495 0
495/2 = 247 1

Introdução à Programação I 6
JEDITM

1980/2 = 990 0
247/2 = 123 1
123/2 = 61 1
61/2 = 30 1
30/2 = 15 0
15/2 = 7 1
7/2 = 3 1
3/2 = 1 1
1/2 = 0 1

Binário = 11110111100

Para Hexadecimal:
0111, 1011, 1100,
7 B C
Hexadecimal = 7BC

Para Octal:
011, 110, 111, 100
3 6 7 4
Octal = 3674

2. 10010011012 para decimal, hexadecimal e octal


Para Decimal:
1 * 1 = 1
0 * 2 = 0
1 * 4 = 4
1 * 8 = 8
0 * 16 = 0
0 * 32 = 0
1 * 64 = 64
0 * 128 = 0
0 * 256 = 0
1 * 512 = 512
TOTAL = 589
Decimal = 589

Para Hexadecimal:
0010, 0100, 1101
2 4 D
Hexadecimal = 24D

Para Octal:
001, 001, 001, 101
1 1 1 5
Octal = 1115

3. 768 para binário, hexadecimal e decimal


Para Binário:
111, 110,
7 6

Introdução à Programação I 7
JEDITM

Binário = 111110

Para Hexadecimal:
0011, 1110,
3 E
Hexadecimal = 3E

Para Decimal:
6 * 1 = 6
7 * 8 = 56
TOTAL = 62
Decimal = 62

4. 43F16 para binário, decimal e octal


Para Binário:
4 3 F
0100, 0011, 1111
Binário = 010000111111

Para Decimal:
F * 1 = 15
3 * 16 = 48
4 * 256 = 1024
TOTAL = 1087
Decimal = 1087

Para Octal:
010, 000 , 111 , 111
2 0 7 7
Octal = 2077

Introdução à Programação I 8
JEDITM

Lição 2 – Histórico de Java

Não houve exercícios nesta lição

Introdução à Programação I 9
JEDITM

Lição 3 – Primeiros passos no ambiente de


programação
Exercício 1. Melhorando o Hello World

/**
* Esta classe mostra "Welcome to Java Programming [SeuNome]!!!"
*/
public class HelloWorld {
public static void main(String[] args){
System.out.println("Welcome to Java Programming [YourName]!!!");
}
}

Exercício 2. A árvore

/**
* O programa mostra o poema "The Tree"
*/
public class TheTree {
public static void main(String[] args){
System.out.println("I think I shall never see,");
System.out.println("[Eu acho que nunca verei,]");
System.out.println("a poem as lovely as a tree.");
System.out.println("[um poema tão adorável quanto uma árvore.]");
System.out.println("A tree whose hungry mouth is pressed");
System.out.println("[Uma árvore cuja boca faminta é pressionada]");
System.out.println("Against the Earth's flowing breast.");
System.out.println("[Contra a Terra fluindo em seu seio docemente.]");
}
}

Introdução à Programação I 10
JEDITM

Lição 4 – Fundamentos da programação


Exercício 1. Declarar e mostrar variáveis
/**
* Um programa que declara diferentes variáveis
* e mostra os valores dessas variáveis
*/
public class VariableSample {
public static void main(String[] args){
// Declarar variável number do tipo integer
// com valor inicial igual a 10
int number = 10;

// Declarar variável letter do tipo character


// com valor inicial igual a 'a'
char letter = 'a';

// Declara variável result do tipo boolean


// com valor inicial igual a true
boolean result = true;

// Declarar variável str do tipo String


// com valor inicial igual a "hello"
String str = "hello";

// Mostrar os valores das variáveis


System.out.println("Number = " + number);
System.out.println("letter = " + letter);
System.out.println("result = " + result);
System.out.println("str = " + str);
}
}

Exercício 2. Obter a média de três números


/**
* Um programa que calcula a média de três
* números: 10,20, e 45
* e imprime o resultado na tela
*/
public class AverageNumber {
public static void main(String[] args){
// Declarar três números
int num1 = 10;
int num2 = 20;
int num3 = 45;
// Obter a média dos números e guardar na variável ave
int ave = (num1+num2+num3)/3;
// Mostrar
System.out.println("number 1 = " + num1);
System.out.println("number 2 = " + num2);
System.out.println("number 3 = " + num3);
System.out.println("Average is = " + ave);
}
}

Exercício 3. Exibir o maior valor


/**
* Um programa que imprime o número com
* maior valor dados três números
*/
public class GreatestValue {
public static void main(String[] args){

Introdução à Programação I 11
JEDITM

// Declarar os números
int num1 = 10;
int num2 = 23;
int num3 = 5;
int max = 0;
// Determinar qual é o maior
max = (num1>num2)?num1:num2;
max = (max>num3)?max:num3;
// Mostrar
System.out.println("número 1 = " + num1);
System.out.println("número 2 = " + num2);
System.out.println("número 3 = " + num3);
System.out.println("O maior número é = " + max);
}
}

Exercício 4. Precedência de Operadores


1. (((a/b)^c)^((d-e+f-(g*h))+i))
2. ((((((3*10)*2)/15)-2+4)^2)^2)
3. ((r^((((s*t)/u)-v)+w))^(x-(y++)))

Introdução à Programação I 12
JEDITM

Lição 5 – Capturando entrada de dados através do


teclado
Exercício 1. As 3 palavras (versão Console - BufferedReader)
import java.io.*;
/**
* Um programa que solicita três palavras ao usuário
* e então as imprime na tela como uma frase
*/
public class LastThreeWords {
public static void main(String[] args){
// Declarar a variável reader como
BufferedReader reader = new BufferedReader(
new InputStreamReader(System.in));
// Declarar variáveis String para as 3 palavras
String firstWord = "";
String secondWord = "";
String thirdWord = "";
try{
System.out.print("Palavra 1: ");
// Obter a primeira palavra
firstWord = reader.readLine();
// Obter a segunda palavra
System.out.print("Palavra 2: ");
secondWord = reader.readLine();
// Obter a terceira palavra
System.out.print("Palavra 3: ");
thirdWord = reader.readLine();
} catch(IOException e) {
System.out.println("Erro na obtenção dos dados");
}
// Mostrar a frase
System.out.println(firstWord + " " + secondWord + " " + thirdWord);
}
}

Exercício 1. As 3 palavras (versão Console - Scanner)

import java.util.Scanner;
/**
* Um programa que solicita três palavras ao usuário
* e então as imprime na tela como uma frase
*/
public class LastThreeWords {
public static void main(String[] args){
// Declarar a variável Scanner
Scanner sc = new Scanner(System.in));
// Declarar variáveis String para as 3 palavras
String firstWord = "";
String secondWord = "";
String thirdWord = "";
System.out.print("Palavra 1: ");
// Obter a primeira palavra
firstWord = sc.nextLine();
// Obter a segunda palavra
System.out.print("Palavra 2: ");
secondWord = sc.nextLine();
// Obter a terceira palavra
System.out.print("Palavra 3: ");
thirdWord = sc.nextLine();
// Mostrar a frase
System.out.println(

Introdução à Programação I 13
JEDITM

firstWord + " " + secondWord + " " + thirdWord);


}
}

Exercício 2. Últimas 3 palavras (versão Gráfica)


import javax.swing.JOptionPane;
/**
* Um programa que solicita do usuário três palavras usando
* o JOptionPane e mostra na tela essas três palavras como
* uma frase
*/
public class LastThreeWords {
public static void main(String[] args){
// Obter a primeira palavra do usuário
String firstWord = JOptionPane.showInputDialog("Palavra 1");
// Obter a segunda palavra do usuário
String secondWord = JOptionPane.showInputDialog("Palavra 2");
// Obter a terceira palavra do usuário
String thirdWord = JOptionPane.showInputDialog("Palavra 3");
// mostra a mensagem
JOptionPane.showMessageDialog(null,
firstWord + " " + secondWord + " " + thirdWord);
}
}

Introdução à Programação I 14
JEDITM

Lição 6 – Estruturas de controle


Exercício 1. Notas
1. Utilizando BufferedReader:
import java.io.*;
/**
* Obtém três entradas numéricas do usuário
* e mostra a média na tela
*/
public class Grades {
public static void main(String[] args) {
// Declarar a variável reader como entrada
BufferedReader reader = new BufferedReader
(new InputStreamReader(System.in));
int firstGrade = 0;
int secondGrade = 0;
int thirdGrade = 0;
double average = 0;
try {
System.out.print("Primeira nota: ");
firstGrade = Integer.parseInt(reader.readLine());
System.out.print("Segunda nota: ");
secondGrade = Integer.parseInt(reader.readLine());
System.out.print("Terceira nota: ");
thirdGrade = Integer.parseInt(reader.readLine());
} catch(Exception e) {
System.out.println("Entrada inválida");
System.exit(0);
}
// Calcular a média
average = (firstGrade+secondGrade+thirdGrade)/3;
// Mostrar a média dos três exames
System.out.print("Média: "+average);
if (average >= 60)
System.out.print(" :-)");
else
System.out.print(" :-(");
}
}

2. Utilizando JOptionPane:
import javax.swing.JOptionPane;
/**
* Obtém três entradas numéricas do usuário
* e mostra a média na tela
*/
public class Grades {
public static void main(String[] args) {
double firstGrade = 0;
double secondGrade = 0;
double thirdGrade = 0;
double average = 0;
try {
firstGrade = Double.parseDouble(JOptionPane.showInputDialog
("Primeira nota"));
secondGrade = Double.parseDouble(JOptionPane.showInputDialog
("Segunda nota"));
thirdGrade = Double.parseDouble(JOptionPane.showInputDialog
("Terceira nota"));
} catch( Exception e) {
JOptionPane.showMessageDialog(null, "Entrada inválida");
System.exit(0);

Introdução à Programação I 15
JEDITM

}
// Calcular a média
average = (firstGrade+secondGrade+thirdGrade)/3;
if (average>=60)
JOptionPane.showMessageDialog(null,"Média :"+average+" :-)");
else
JOptionPane.showMessageDialog(null,"Média :"+average+" :-(");
}
}

Exercício 2. Números por Extenso

Classe Básica
import javax.swing.JOptionPane;
/**
* Transforma uma entrada numérica entre 1-10 para palavras
* utilizando if-else
*/
public class NumWords {
public static void main(String[] args) {
String msg = "";
int input = 0;
// Obter a entrada
input = Integer.parseInt(JOptionPane.showInputDialog("Digite número"));
// ------------------------------------
// Substitua aqui as declarações
// ------------------------------------
// Mostrar o número em palavras se dentro da faixa
JOptionPane.showMessageDialog(null,msg);
}
}

1. Declaração if-else:
// Declaração if para atribuir em msg o extenso do número digitado
if (input == 1) msg = "um";
else if(input == 2) msg = "dois";
else if(input == 3) msg = "três";
else if(input == 4) msg = "quatro";
else if(input == 5) msg = "cinco";
else if(input == 6) msg = "seis";
else if(input == 7) msg = "sete";
else if(input == 8) msg = "oito";
else if(input == 9) msg = "nove";
else if(input == 10) msg = "dez";
else msg = "número inválido";

2. Declaração switch:
// Declaração switch para atribuir em msg o extenso do número digitado
switch (input) {
case 1: msg = "um"; break;
case 2: msg = "dois"; break;
case 3: msg = "três"; break;
case 4: msg = "quatro"; break;
case 5: msg = "cinco"; break;
case 6: msg = "seis"; break;
case 7: msg = "sete"; break;
case 8: msg = "oito"; break;
case 9: msg = "nove"; break;
case 10: msg = "dez"; break;
default: msg = "número inválido";
}

Introdução à Programação I 16
JEDITM

Exercício 3. Cem Vezes

Classe Básica
import java.io.*;
/**
* Um programa que imprime 100 vezes um número digitado
*/
public class HundredNames{
public static void main(String[] args){
BufferedReader reader = new BufferedReader(
new InputStreamReader(System.in));
String name = "";
// Obter o nome do usuário
try {
System.out.print("Digite o nome: ");
name = reader.readLine();
} catch(Exception e) {
System.out.println("entrada inválida");
System.exit(0);
}
// ------------------------------------
// Substitua aqui as declarações
// ------------------------------------
}
}

1. Declaração while:
// Declaração while para exibir 100 vezes o nome digitado
int counter = 0;
while (counter < 100) {
System.out.println(name);
counter++;
}

2. Declaração do-while:
// Declaração do-while para exibir 100 vezes o nome digitado
int counter = 0;
do {
System.out.println(name);
counter++;
} while(counter < 100);

3. Declaração for:
// Declaração for para exibir 100 vezes o nome digitado
for (int counter = 0; counter < 100; counter++) {
System.out.println(name);
}

Exercício 4. Potências

Classe Básica
import javax.swing.JOptionPane;
/**
* Calcula a potência de um número dados a base e expoente.
* O expoente está limitado a números positivos.
*/
public class Powers {
public static void main(String[] args){
int base = 0;
int exp = 0;
int power = 1;

Introdução à Programação I 17
JEDITM

// Obter entrada do usuário para base e expoente


base = Integer.parseInt(JOptionPane.showInputDialog("Base"));
exp = Integer.parseInt(JOptionPane.showInputDialog("Expoente"));
// Limitar variável exp a somente número positivos e maiores que 0
if (exp <= 0) {
JOptionPane.showMessageDialog(null,
"Somente números positivos e maiores que 0, por favor");
System.exit(0);
}
// ------------------------------------
// Substitua aqui as declarações
// ------------------------------------
// Mostrar o resultado
JOptionPane.showMessageDialog(null,
base + " elevado a " + exp + " é igual a " + power);
}
}

1. Declaração while:
// Declaração while para calcular a potência
int counter = 0;
while (counter++ < exp)
power = power*base;

2. Declaração do-while:
// Declaração do-while para calcular a potência
int counter = 0;
do
power = power*base;
while(++counter < exp);

3. Declaração for:
// Declaração for para calcular a potência
for (int counter = 0; counter < exp; counter++)
power = power*base;

Introdução à Programação I 18
JEDITM

Lição 7 – Array em Java


Exercício 1. Dias da Semana
/**
* Utilizar um array de string para salvar os dias da semana
* e imprime na tela.
*/
public class DaysOfTheWeek {
public static void main(String[] args){
// Declarar o array de String dos dias da semana
String[] days = {"Sunday", "Monday", "Tuesday",
"Wednesday", "Thursday", "Friday", "Saturday"};
// ------------------------------------
// Substitua aqui as declarações
// ------------------------------------
}
}

1. Declaração while:
// Declaração while para mostrar os dias da semana
int counter = 0;
while (counter++ < days.length)
System.out.println(days[counter]);

2. Declaração do-while:
// Declaração do-while para mostrar os dias da semana
int counter = 0;
do
System.out.println(days[counter++]);
while(counter < days.length);

3. Declaração for:
// Declaração for para mostrar os dias da semana
for (int counter = 0; counter < days.length; counter++)
System.out.println(days[counter]);

Exercício 2. Maior número


import javax.swing.JOptionPane;
/**
* Um programa que utiliza JOptionPane para obter dez números do usuário
* e exibir o maior número.
*/
public class GreatestNumber {
public static void main(String[] args){
int[] num = new int[10];
int counter;
int max = 0;
// Declaração for para obter 10 números do usuário
for (counter = 0; counter < 10; counter++) {
num[counter] = Integer.parseInt(
JOptionPane.showInputDialog("Digite o número "+(counter+1)));
// Obter o número máximo
if ((counter == 0)||(num[counter] > max))
max = num[counter];
}
// Mostrar o maior número
JOptionPane.showMessageDialog(null, "O número com o maior valor é " + max);
}
}

Introdução à Programação I 19
JEDITM

Exercício 3. Entradas de Agenda Telefônica


import javax.swing.JOptionPane;
/**
* Um programa que mostra os dados de um array multidimensional.
*/
public class GreatestNumber {
public static void main(String[] args){
String entry [][] = {
{"Florence", "735-1234", "Manila"},
{"Joyce", "983-3333", "Quezon City"},
{"Becca", "456-3322", "Manila"}};
// Declaração for para percorrer nas linhas
for (int line = 0; line < entry.length; line++) {
System.out.println("Name : " + entry[line][0]);
System.out.println("Tel. # : " + entry[line][1]);
System.out.println("Address: " + entry[line][2]);
System.out.println();
}
}
}

Introdução à Programação I 20
JEDITM

Lição 8 – Argumentos de linha de comando


Exercício 1. Argumentos de Exibição
/**
* Um programa que imprime a string da linha de comando, se
* houver.
*/
public class CommandLineSample {
public static void main(String[] args){
// Declaração for para exibir os argumentos da linha de comando
for (int counter=0; counter < args.length; counter++)
System.out.println(args[counter]);
}
}

Exercício 2. Operações Aritméticas


/**
*
*/
public class ArithmeticOperation {
public static void main(String[] args){
// Obter os argumentos em int
int num1 = Integer.parseInt(args[0]);
int num2 = Integer.parseInt(args[1]);
// Mostrando valores
System.out.println("sum = " + (num1 + num2));
System.out.println("subtraction = " + (num1 - num2));
System.out.println("multiplication = " + (num1 * num2));
System.out.println("division = " + (num1 / num2));
}
}

Introdução à Programação I 21
JEDITM

Lição 9 – Trabalhando com bibliotecas de classes


Exercício 1. Argumentos de Exibição
Não existe uma única resposta.

Exercício 2. Java Scavenger Hunt


Nota: Esses são apenas alguns exemplos de métodos na API Java que é possível utilizar.
Verifique a API Java para mais respostas.

public class Homework1 {


public static void main(String []args) {
// 1. endsWith
String str = "Hello";
System.out.println( str.endsWith( "slo" ) );

//2. forDigit
System.out.println( Character.forDigit(13, 16) );

//3. floor
System.out.println( Math.floor(3.14));

//4. isDigit
System.out.println( "0=" + Character.isDigit('0'));
System.out.println( "A=" +Character.isDigit('A'));

//5. exit
System.exit(1);
System.out.println("if this is executed, exit was not called");
}
}

Declaração de Classe e Método:

1. Classe: String
Método: public boolean endsWith(String suffix)

2. Classe: Character
Método: public static char forDigit(int digit, int radix)

3. Classe: Math
Método: public static double floor(double a)

4. Classe: Math
Método: public static boolean isDigit(char ch)

5. Classe: System
Método: public static void exit(int status)

Introdução à Programação I 22
JEDITM

Lição 10 – Criando nossas classes


Exercício 1. Registro de agenda
/**
* Uma classe de registro de agenda que armazena o nome da
* pessoa, endereço, número de telefone e endereço de email
*/
public class AddressBookEntry {
private String name;
private String address;
private String tel;
private String email;

/**
* construtor padrão
*/
public AddressBookEntry(){
this.setName("");
this.setAddress("");
this.setTel("");
this.setEmail("");
}
/**
* Cria um objeto AddressBookEntry com o nome, endereço,
* número de telefone e endereço de email fornecidos.
*/
public AddressBookEntry(String name, String address, String tel, String email) {
this.setName(name);
this.setAddress(address);
this.setTel(tel);
this.setEmail(email);
}
/**
* retorna a variável name
*/
public String getName(){
return name;
}
/**
* altera a variável name
*/
public void setName(String name){
this.name = name;
}
/**
* retorna a variável address
*/
public String getAddress(){
return address;
}
/**
* altera a variável address
*/
public void setAddress(String address){
this.address = address;
}
/**
* retorna a variável tel
*/
public String getTel(){
return tel;
}
/**
* altera a variável tel

Introdução à Programação I 23
JEDITM

*/
public void setTel(String tel){
this.tel = tel;
}
/**
* retorna a variável email
*/
public String getEmail(){
return email;
}
/**
* altera a variável email
*/
public void setEmail(String email){
this.email = email;
}
}

Exercício 2. Agenda
import java.io.*;
/**
* Cria uma agenda com 100 registros AddressBookEntries
*/
public class AddressBook {
// Índice do último registro
private int top = 0;
// Número constante que indica o número máximo de registros da agenda
private static final int MAXENTRIES = 100;
// Array de registros da agenda
private AddressBookEntry[] list;

/**
* Método principal
*/
public static void main(String[] args) {
BufferedReader keyIn = new BufferedReader
(new InputStreamReader(System.in));
AddressBook addBook = new AddressBook();
String act = "";
while(true) {
// Mostrar as opções
System.out.println("\n[A] Adicionar registro");
System.out.println("[E] Excluir registro");
System.out.println("[V] Visualizar registros");
System.out.println("[U] atUalizar registro");
System.out.println("[S] Sair do projeto");
System.out.print("Digite a ação desejada: ");
try {
// Obter a escolha
act = keyIn.readLine();
} catch(Exception e) {
System.out.println("Erro");
}
// Verificar a ação apropiada para a escolha do usuário
switch (act.charAt(0)) {
case 'A': case 'a': addBook.addEntry(); break;
case 'E': case 'e': addBook.delEntry(); break;
case 'V': case 'v': addBook.viewEntries(); break;
case 'U': case 'u': addBook.updateEntry(); break;
case 'S': case 's': System.exit(0);
default: System.out.println("Comando Desconhecido");
}
}
}
/**

Introdução à Programação I 24
JEDITM

* cria a agenda
*/
public AddressBook(){
list = new AddressBookEntry[MAXENTRIES];
}
/**
* método para adicionar um registro AdressBookEntry
* na agenda
*/
public void addEntry(){
BufferedReader keyIn = new BufferedReader(new InputStreamReader(System.in));
String name = "";
String add = "";
String tel = "";
String email = "";
if (top == MAXENTRIES) {
System.out.println("Agenda está cheia");
return;
}
//Pede ao usuário a digitação dos dados
try {
System.out.print("Nome: ");
name = keyIn.readLine();
System.out.print("Endereço: ");
add = keyIn.readLine();
System.out.print("Telefone: ");
tel = keyIn.readLine();
System.out.print("Email: ");
email = keyIn.readLine();
} catch(Exception e) {
System.out.println(e);
System.exit(0);
}
AddressBookEntry entry = new AddressBookEntry(name, add, tel, email);
list[top] = entry;
top++;
}
/**
* método que deleta um registro AddressBookEntry
* da agenda com o índice
*/
public void delEntry(){
BufferedReader keyIn = new BufferedReader(new InputStreamReader(System.in));
int index = 0;
// Verificar se a agenda está vazia
if (top == 0) {
System.out.println("Agenda está vazia");
return;
}
// Solicitar o registro a ser deletado
try {
// Exibir os registros existentes na agenda
viewEntries();
System.out.print("\nDigite número do registro: ");
index = Integer.parseInt(keyIn.readLine())-1;
}catch(Exception e){
}
//verifica se o índice está dentro do limites
if (index < 0 || index >= top) {
System.out.println("Índice fora dos limites");
return;
} else {
for (int i=index; i<top; i++)
list[i] = list[i+1];
list[top] = null;
top--;

Introdução à Programação I 25
JEDITM

}
}
/**
* método que imprime todos os registros da agenda
*/
public void viewEntries(){
for (int index = 0; index < top; index++) {
System.out.println((index+1)+" Nome:"+list[index].getName());
System.out.println("Endereço:"+list[index].getAddress());
System.out.println("Telefone:"+list[index].getTel());
System.out.println("Email:"+list[index].getEmail());
}
}
/**
* método que atualiza um registro
*/
public void updateEntry(){
BufferedReader keyIn = new BufferedReader(new InputStreamReader(System.in));
int index = 0;
String name = "";
String add = "";
String tel = "";
String email = "";
// Solicitar a digitação dos dados
try {
System.out.print("Número do registro: ");
index =Integer.parseInt(keyIn.readLine())-1;
System.out.print("Nome: ");
name = keyIn.readLine();
System.out.print("Endereço: ");
add = keyIn.readLine();
System.out.print("Telefone: ");
tel = keyIn.readLine();
System.out.print("Email: ");
email = keyIn.readLine();
} catch(Exception e) {
System.out.println(e);
System.exit(0);
}
// Atualizar o registro
AddressBookEntry entry = new AddressBookEntry(name, add, tel, email);
list[index] = entry;
}
}

Introdução à Programação I 26
JEDITM

Lição 11 – Herança, polimorfismo e interfaces


Exercício 1. Estendendo StudentRecord

/**
* Um objeto que armazena os dados de um estudante
*/
public class StudentRecord {
private String name;
private String address;
private int age;
private double mathGrade;
private double englishGrade;
private double scienceGrade;

protected static int studentCount;

/**
* Retorna o nome do estudante
*/
public String getName() {
return name;
}
/**
* Altera o nome do estudante
*/
public void setName(String temp) {
name = temp;
}
/**
* Retorna o endereço do estudante
*/
public String getAddress() {
return address;
}
/**
* Altera o endereço do estudante
*/
public void setAddress(String temp) {
address = temp;
}
/**
* Retorna a idade do estudante
*/
public int getAge() {
return age;
}
/**
* Altera a idade do estudante
*/
public void setAge(int temp) {
age = temp;
}
/**
* Retorna a nota de inglês do estudante
*/
public double getEnglishGrade() {
return englishGrade;
}
/**
* Altera a nota de inglês do estudante
*/
public void setEnglishGrade(double temp) {
englishGrade = temp;

Introdução à Programação I 27
JEDITM

}
/**
* Retorna a nota de matemática do estudante
*/
public double getMathGrade() {
return mathGrade;
}
/**
* Altera a nota de matemática do estudante
*/
public void setMathGrade(double temp) {
mathGrade = temp;
}
/**
* Retorna a nota de ciências do estudante
*/
public double getScienceGrade() {
return scienceGrade;
}
/**
* Altera a nota de ciências do estudante
*/
public void setScienceGrade(double temp) {
scienceGrade = temp;
}
/**
* Calcula a média das notas de inglês, matemática e
* ciências do estudante
*/
public double getAverage() {
return (mathGrade+englishGrade+scienceGrade)/3;
}
/**
* Retorna o número de instâncias de StudentRecords
*/
public static int getStudentCount() {
return studentCount;
}
}

/**
* Um registro de estudante de um estudante de Ciência de
* Computação
*/
public class ComputerScienceStudentRecord extends StudentRecord {
private String studentNumber;
private double comSciGrade;

/**
* Retorna a matrícula do estudante
*/
public String getStudentNumber() {
return studentNumber;
}
/**
* Altera a matrícula do estudante
*/
public void setStudentNumber(String temp) {
studentNumber = temp;
}
/**
* Retorna a nota de ciência de computação do estudante
*/
public double getComSciGrade() {
return comSciGrade;
}

Introdução à Programação I 28
JEDITM

/**
* Altera a nota de ciência de computação do estudante
*/
public void setComSciGrade(double temp) {
comSciGrade = temp;
}
}

Exercício 2. Classes Abstratas


/**
* Definição da classe abstrata forma
*/
public abstract class Shape {
/**
* retorna a área de determinada forma
*/
public abstract double getArea();

/**
* retorna o nome da forma
*/
public abstract String getName();
}

/**
* Definição de Classe para objeto círculo
*/
public class Circle extends Shape {
private static final double pi = 3.1416;
private double radius = 0;
/**
* Construtor
*/
public Circle(double r) {
setRadius(r);
}
/**
* retorna area
*/
public double getArea() {
return pi*radius*radius;
}
/**
* retorna o nome da forma
*/
public String getName() {
return "circle";
}
/**
* Atribui raio
*/
public void setRadius(double r) {
radius = r;
}
/**
* retorna raio
*/
public double getRadius() {
return radius;
}
}
/**
* Definição de Classe para objeto quadrado
*/
public class Square extends Shape {

Introdução à Programação I 29
JEDITM

private double side = 0;

/**
* Construtor
*/
public Square(double s) {
setSide( s );
}
/**
* retorna area
*/
public double getArea() {
return side*side;
}
/**
* retorna o nome da forma
*/
public String getName() {
return "square";
}
/**
* atribui tamanho do lado
*/
public void setSide(double s) {
side = s;
}
/**
* retorna o tamanho de um lado
*/
public double getSide(){
return side;
}
}

Introdução à Programação I 30
JEDITM

Lição 12 – Tratamento básico de exceções


Exercício 1. Capturando exceções 1
public class TestExceptions {
public static void main(String[] args) {
try {
for (int i=0; true; i++)
System.out.println("args["+i+"]="+args[i]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Exception caught: " + e);
}
System.out.println("Quiting...");
}
}

Exercício 2. Capturando exceções 2


Não existe uma única resposta.

Introdução à Programação I 31
Módulo 1
Introdução à Programação 1

Apêndice D
Testes de programação

Versão 1.0 - Jan/2007


JEDITM

1. Objetivos
Neste apêndice, veremos apenas idéias de projetos para que o estudante possa se aprofundar
cada vez mais com Java. Não existem soluções únicas para cada projeto e cabe ao estudante
implementá-lo da maneira como melhor lhe agradar.

Nota:

VOCÊ tem alguma idéia interessante para um projeto? Envie-a para o email do Fernando
Anselmo (fernando.anselmo@dfjug.org) e ajude a iniciativa JEDI a crescer. No assunto do
email escreva: "Projeto para JEDI" e no corpo do email:

Título do Projeto:
Descrição do Projeto:
Nome completo do autor:

Estes projetos devem ser idéias originais e inéditas. Colabore.

Introdução à Programação I 4
JEDITM

2. Agenda Telefônica
Escrever um programa que cria uma agenda telefônica na qual seja possível acrescentar,
excluir, visualizar e pesquisar os registros. O usuário deve ter a possibilidade de visualizar
todos registros por ordem alfabética ou por ordem crescente de números de telefone. Na
pesquisa por registros, o usuário deve ter a opção de pesquisar por nome ou por número de
telefone. Na pesquisa pelo nome, o usuário deve ter uma opção em que possa selecionar se a
pesquisa será efetuada com base no primeiro ou último nome.

MENUPRINCIPAL
1– Adicionar registro na agenda telefônica
2– Excluir registro da agenda telefônica
3– Visualizar todos os registros
a – ordem alfabética
b – ordem numérica crescente de número de telefone
4 – Pesquisa de registros
a – por nome
1 – pelo primeiro nome
2 – pelo último nome
b – por número de telefone
5 – Sair

Esse é um exemplo da aplicação rodando:

Adicionar registro na agenda telefônica


Digite o Nome:
Digite o número do Telefone:
(* Se o registro já existir, avise o operador da existência do registro)

Visualizar todos os registros


Mostra todos os registros em ordem alfabética
Mostra todos os registros em ordem crescente de número de telefone

Pesquisa registros
Pesquisa agenda telefônica por nome
Pesquisa agenda telefônica pelo primeiro nome
Pesquisa agenda telefônica pelo último nome
Pesquisa agenda telefônica por número do telefone

Sair
Fechar agenda telefônica

Introdução à Programação I 5
JEDITM

3. Caça-Minas
Este jogo é uma versão simplificada do popular jogo de computador Caça-minas
(minesweeper). Inicialmente, é questionado se o usuário quer jogar numa grade de 5x5 ou
numa grade de 10x10. Você tem 2 arrays bidimensionais que contém informações sobre a
grade selecionada. Um registro desse array pode conter 0 ou 1. O valor 1 significa que existe
uma bomba nessa localização e o valor 0 se não existir.

Por exemplo, dado o seguinte array:

int bombList5by5[][]={{0, 0, 1, 0, 0},


{0, 0, 0, 0, 0},
{0, 1, 0, 0, 0},
{0, 0, 0, 1, 1},
{0, 1, 1, 0, 0}};

Dada a lista de bombas, temos 6 bombas nessa lista. As bombas estão localizadas nas células
(linha,coluna), (0,2), (2,1), (3,3), (3,4), (4,1) e (4,2).

Se o usuário escolhe uma célula que contenha uma bomba, o jogo acaba e todas as bombas
são mostradas. Se o usuário escolhe uma célula que não contenha uma bomba, um número é
mostrado naquela posição indicando a quantidade de células vizinhas que contém bombas. O
jogo deverá terminar quando todas as células que não contenham bombas tiverem sido
marcadas (jogador vence) ou quando o usuário seleciona uma bomba (jogador perde).

Segue um exemplo de tela do jogo quando selecionada uma grade 5x5 que tenha o mesmo
conteúdo do array bombList5by5 acima.

Benvindo ao Caça-Minas!
Escolha o tamanho da grade(Digite 1 para 5x5, Digite 2 para 10x10): 1
[ ] [ ] [ ] [ ] [ ]
[ ] [ ] [ ] [ ] [ ]
[ ] [ ] [ ] [ ] [ ]
[ ] [ ] [ ] [ ] [ ]
[ ] [ ] [ ] [ ] [ ]
Digite linha e coluna da célula que você quer abrir[linha coluna]: 1 1
[ ] [ ] [ ] [ ] [ ]
[ ] [2] [ ] [ ] [ ]
[ ] [ ] [ ] [ ] [ ]
[ ] [ ] [ ] [ ] [ ]
[ ] [ ] [ ] [ ] [ ]
Digite linha e coluna da célula que você quer abrir[linha coluna]: 3 2
[ ] [ ] [ ] [ ] [ ]
[ ] [2] [ ] [ ] [ ]
[ ] [ ] [ ] [ ] [ ]
[ ] [ ] [4] [ ] [ ]
[ ] [ ] [ ] [ ] [ ]
Digite linha e coluna da célula que você quer abrir[linha coluna]: 0 2
[ ] [ ] [X] [ ] [ ]
[ ] [2] [ ] [ ] [ ]
[ ] [ ] [ ] [ ] [ ]
[ ] [ ] [4] [ ] [ ]
[ ] [ ] [ ] [ ] [ ]
Ooppps! Você pisou numa bomba. Sinto muito, o jogo acabou e você perdeu!

Introdução à Programação I 6
JEDITM

4. Conversão Numérica
Criar uma calculadora científica que converta os números digitados para as quatro
representações numéricas: decimal, binário, octal e hexadecimal. O projeto deve gerar o
seguinte menu na tela.

MENU PRINCIPAL:
Por favor, selecione o tipo de conversão:
1 – Binário para Decimal
2 – Decimal para Octal
3 – Octal para Hexadecimal
4 – Hexadecimal para Binário
5 – Sair

A seguinte tela deve ser mostrada quando uma das opções do menu for escolhida.

Seleção 1:
Digite um número binário: 11000
11000 base 2 = 24 base 10
(volta para o menu principal)

Seleção 2:
Digite um número Decimal: 24
24 base 10 = 30 base 8
(volta para o menu principal)

Seleção 3:
Digite um número Octal: 30
30 base 8 = 18 base 16
(volta para o menu principal)

Seleção 4:
Digite um número Hexadecimal: 18
18 base 16 = 11000 base 2

Seleção 1:
Digite um número Binário: 110A
Número binário inválido!
Digite um número binário: 1
1 base 2 = 1 base 10
(volta para o menu principal)

Usuário selecionou 5
Tchau!

É possível ser mais criativo com a interface do usuário, contanto que o programa gere
devidamente as conversões numéricas.

Introdução à Programação I 7
Módulo 2
Introdução à Programação II

Lição 1
Revisão dos Conceitos Básicos em Java

Versão 1.01 - Jan/2008


JEDITM

Autor Necessidades para os Exercícios


Rebecca Ong Sistemas Operacionais Suportados
NetBeans IDE 5.5 para os seguintes sistemas operacionais:
• Microsoft Windows XP Profissional SP2 ou superior
• Mac OS X 10.4.5 ou superior
Equipe • Red Hat Fedora Core 3
Joyce Avestro • Solaris™ 10 Operating System (SPARC® e x86/x64 Platform Edition)
Florence Balagtas NetBeans Enterprise Pack, poderá ser executado nas seguintes plataformas:
• Microsoft Windows 2000 Profissional SP4
Rommel Feria • Solaris™ 8 OS (SPARC e x86/x64 Platform Edition) e Solaris 9 OS (SPARC e
Rebecca Ong x86/x64 Platform Edition)
John Paul Petines • Várias outras distribuições Linux
Sun Microsystems
Configuração Mínima de Hardware
Sun Philippines
Nota: IDE NetBeans com resolução de tela em 1024x768 pixel
Sistema Operacional Processador Memória HD Livre
Microsoft Windows 500 MHz Intel Pentium III 512 MB 850 MB
workstation ou equivalente
Linux 500 MHz Intel Pentium III 512 MB 450 MB
workstation ou equivalente
Solaris OS (SPARC) UltraSPARC II 450 MHz 512 MB 450 MB
Solaris OS (x86/x64 AMD Opteron 100 Série 1.8 GHz 512 MB 450 MB
Platform Edition)
Mac OS X PowerPC G4 512 MB 450 MB

Configuração Recomendada de Hardware

Sistema Operacional Processador Memória HD Livre


Microsoft Windows 1.4 GHz Intel Pentium III 1 GB 1 GB
workstation ou equivalente
Linux 1.4 GHz Intel Pentium III 1 GB 850 MB
workstation ou equivalente
Solaris OS (SPARC) UltraSPARC IIIi 1 GHz 1 GB 850 MB
Solaris OS (x86/x64 AMD Opteron 100 Series 1.8 GHz 1 GB 850 MB
Platform Edition)
Mac OS X PowerPC G5 1 GB 850 MB

Requerimentos de Software
NetBeans Enterprise Pack 5.5 executando sobre Java 2 Platform Standard Edition
Development Kit 5.0 ou superior (JDK 5.0, versão 1.5.0_01 ou superior), contemplando
a Java Runtime Environment, ferramentas de desenvolvimento para compilar, depurar,
e executar aplicações escritas em linguagem Java. Sun Java System Application Server
Platform Edition 9.
• Para Solaris, Windows, e Linux, os arquivos da JDK podem ser obtidos para
sua plataforma em http://java.sun.com/j2se/1.5.0/download.html
• Para Mac OS X, Java 2 Plataform Standard Edition (J2SE) 5.0 Release 4, pode
ser obtida diretamente da Apple's Developer Connection, no endereço:
http://developer.apple.com/java (é necessário registrar o download da JDK).

Para mais informações: http://www.netbeans.org/community/releases/55/relnotes.html

Introdução à Programação II 2
JEDITM

Colaboradores que auxiliaram no processo de tradução e revisão


Alexandre Mori Hugo Leonardo Malheiros Ferreira Mauro Regis de Sousa Lima
Alexis da Rocha Silva Ivan Nascimento Fonseca Namor de Sá e Silva
Aline Sabbatini da Silva Alves Jacqueline Susann Barbosa Néres Chaves Rebouças
Allan Wojcik da Silva Jader de Carvalho Belarmino Nolyanne Peixoto Brasil Vieira
André Luiz Moreira João Aurélio Telles da Rocha Paulo Afonso Corrêa
Andro Márcio Correa Louredo João Paulo Cirino Silva de Novais Paulo José Lemos Costa
Antoniele de Assis Lima João Vianney Barrozo Costa Paulo Oliveira Sampaio Reis
Antonio Jose R. Alves Ramos José Augusto Martins Nieviadonski Pedro Antonio Pereira Miranda
Aurélio Soares Neto José Leonardo Borges de Melo Pedro Henrique Pereira de Andrade
Bruno da Silva Bonfim José Ricardo Carneiro Renato Alves Félix
Bruno dos Santos Miranda Kleberth Bezerra G. dos Santos Renato Barbosa da Silva
Bruno Ferreira Rodrigues Lafaiete de Sá Guimarães Reyderson Magela dos Reis
Carlos Alberto Vitorino de Almeida Leandro Silva de Morais Ricardo Ferreira Rodrigues
Carlos Alexandre de Sene Leonardo Leopoldo do Nascimento Ricardo Ulrich Bomfim
Carlos André Noronha de Sousa Leonardo Pereira dos Santos Robson de Oliveira Cunha
Carlos Eduardo Veras Neves Leonardo Rangel de Melo Filardi Rodrigo Pereira Machado
Cleber Ferreira de Sousa Lucas Mauricio Castro e Martins Rodrigo Rosa Miranda Corrêa
Cleyton Artur Soares Urani Luciana Rocha de Oliveira Rodrigo Vaez
Cristiano Borges Ferreira Luís Carlos André Ronie Dotzlaw
Cristiano de Siqueira Pires Luís Octávio Jorge V. Lima Rosely Moreira de Jesus
Derlon Vandri Aliendres Luiz Fernandes de Oliveira Junior Seire Pareja
Fabiano Eduardo de Oliveira Luiz Victor de Andrade Lima Sergio Pomerancblum
Fábio Bombonato Manoel Cotts de Queiroz Silvio Sznifer
Fernando Antonio Mota Trinta Marcello Sandi Pinheiro Suzana da Costa Oliveira
Flávio Alves Gomes Marcelo Ortolan Pazzetto Tásio Vasconcelos da Silveira
Francisco das Chagas Marco Aurélio Martins Bessa Thiago Magela Rodrigues Dias
Francisco Marcio da Silva Marcos Vinicius de Toledo Tiago Gimenez Ribeiro
Gilson Moreno Costa Maria Carolina Ferreira da Silva Vanderlei Carvalho Rodrigues Pinto
Givailson de Souza Neves Massimiliano Giroldi Vanessa dos Santos Almeida
Gustavo Henrique Castellano Mauricio Azevedo Gamarra Vastí Mendes da Silva Rocha
Hebert Julio Gonçalves de Paula Mauricio da Silva Marinho Wagner Eliezer Roncoletta
Heraldo Conceição Domingues Mauro Cardoso Mortoni

Auxiliadores especiais
Revisão Geral do texto para os seguintes Países:
• Brasil – Tiago Flach
• Guiné Bissau – Alfredo Cá, Bunene Sisse e Buon Olossato Quebi – ONG Asas de Socorro

Coordenação do DFJUG
• Daniel deOliveira – JUGLeader responsável pelos acordos de parcerias
• Luci Campos - Idealizadora do DFJUG responsável pelo apoio social
• Fernando Anselmo - Coordenador responsável pelo processo de tradução e revisão,
disponibilização dos materiais e inserção de novos módulos
• Regina Mariani - Coordenadora responsável pela parte jurídica
• Rodrigo Nunes - Coordenador responsável pela parte multimídia
• Sérgio Gomes Veloso - Coordenador responsável pelo ambiente JEDITM (Moodle)

Agradecimento Especial
John Paul Petines – Criador da Iniciativa JEDITM
Rommel Feria – Criador da Iniciativa JEDITM

Introdução à Programação II 3
JEDITM

1. Objetivos

Antes de entrar em outras características do Java, inicialmente iremos revisar alguns assuntos
que vimos no primeiro módulo do curso. Esta lição fornece uma discussão breve sobre os
diferentes conceitos de Orientação a Objetos em Java.

Ao final desta lição, o estudante será capaz de:

• Explicar e usar os conceitos básicos de orientação a objetos em seus códigos


• classes, objetos, atributos, métodos e construtores
• Descrever conceitos avançados de orientação a objetos e aplicá-los na codificação
• pacote, encapsulamento, abstração, herança, polimorfismo e interface
• Descrever e utilizar as palavras-chaves: this, super, final e static
• Diferenciar entre polimorfismo por overloading e override

Introdução à Programação II 4
JEDITM

2. Conceitos de orientação a objetos


2.1. Modelagem Orientada a Objetos
Modelagem Orientada a Objetos é uma técnica que possui foco na modelagem de objetos e
classes baseados no cenário do mundo real. Ela dá enfase ao estado, comportamento e interação
dos objetos. Possibilita o benefício do desenvolvimento rápido, aumenta a qualidade, fácil
manutenção, a facilidade de alterações e a reutilização de software.

2.2. Classe
Permite definir novos tipos de dados. Serve como um referencial, a qual é um modelo para os
objetos que é possível criar utilizando este novo tipo de dado.
O modelo de um estudante seria um exemplo de uma classe. Podemos definir que cada aluno
terá uma série de qualidades tais como nome, número do estudante e nível escolar.

2.3. Objeto
É uma entidade que possui um estado, um comportamento e uma identidade com um papel bem
definido no escopo do problema. É uma instância real de uma classe. Sendo assim, é chamado de
instância da classe. Criado toda vez que for utilizado a palavra-chave new. Em um projeto de
registro de estudantes, um exemplo de objeto pode ser uma entidade estudante, como Ana. Ana
é um objeto da classe Estudante. Desta forma, as qualidades e habilidades definidas no modelo
da classe Estudante são todos aplicáveis a Ana, já que Ana é uma instância de Estudante.
Para simplificar, pensamos em uma classe como um termo mais geral se comparado a um objeto.

2.4. Atributo
Refere-se ao elemento dos dados de um objeto. Ele armazena informações sobre o objeto. É
também conhecido como dado do objeto, atributo do objeto, propriedade ou campo. No projeto
de registro do aluno, alguns atributos da entidade aluno incluem o nome, número do estudante e
nível de escolaridade.

2.5. Método
Descreve o comportamento de um objeto. Em linguagens relacionais seria comparado a uma
função ou procedimento. Métodos disponíveis para a entidade estudante são genéricos e atendem
a escola.

2.6. Construtor
É um tipo especial de método que é utilizado para a construção ou criação de um novo objeto.
Lembre-se que construtores não são elementos (atributos, métodos e classes internas de um
objeto).

2.7. Pacote
Refere ao agrupamento de classes e sub-classes. Sua estrutura é análoga a de um diretório.

2.8. Encapsulamento
Princípio de ocultar a modelagem ou as informações de implementação que não são referentes ao
objeto atual.

2.9. Abstração
Princípio de ignorar os aspectos subjetivos que não são relevantes para o real propósito em prol
de se concentrar mais diretamente naqueles que são.

Introdução à Programação II 5
JEDITM

2.10. Herança
Princípio que surge com a relação entre classes. Uma classe é a superclasse ou a classe pai de
outra. É relativo às propriedades e aos comportamentos recebidos pelo antecessor. É também
conhecida como uma relação "é-um" (is-a). Considere a seguinte hierarquia:

SuperHero

FlyingSuperHero UnderwaterSuperHero
Figura 1: Exemplo de herança

SuperHero é a superclasse das classes FlyingSuperHero e UnderwaterSuperHero. Note que


FlyingSuperHero "é-um" SuperHero e UnderwaterSuperHero "é-um" SuperHero.

2.11. Polimorfismo
Habilidade de um método poder assumir diferentes formas. Literalmente, "poli" significa muitas
enquanto "morph" significa forma. Referenciando o exemplo anterior para herança, supomos um
método displayPower na classe SuperHero que retorna o poder que o super-herói possui, na
classe FlyingSuperHero este mesmo método poderia retornar "voar" enquanto que na classe
UnderwaterSuperHero este mesmo método retornaria "respirar embaixo d'água".

2.12. Interface
É um contrato na forma de uma coleção de declarações de métodos e constantes. Quando uma
classe implementa uma interface, ela se compromete a implementar todos os métodos
declarados nesta.

Introdução à Programação II 6
JEDITM

3. Estrutura de codificação Java


Esta seção resume a sintaxe básica usada para a criação de aplicações em Java.

3.1. Declarando classes em Java

<declaraçãoClasse> ::= <modificador> class <nomeClasse> {


<declaraçãoAtributo>*
<declaraçãoConstrutor>*
<declaraçãoMétodo>*
}

onde:
<modificador> é um modificador de acesso, o qual deve ser combinado com outros tipos de
modificadores.

Guia de código:

* Poderá existir nenhuma ou diversas ocorrências da linha onde este símbolo foi
aplicado.
<descrição> Indica a descrição de um valor para esta parte.

Lembre-se que para uma classe de alto nível, os únicos modificadores de acesso são public e
default (neste caso, nenhum modificador de acesso precede a palavra-chave class).
O seguinte exemplo declara a classe SuperHero:
class SuperHero {
String superPowers[];
void setSuperPowers(String superPowers[]) {
this.superPowers = superPowers;
}
void printSuperPowers() {
for (int i = 0; i < superPowers.length; i++) {
System.out.println(superPowers[i]);
}
}
}

3.2. Declarando Atributos


<declaraçãoAtributo> ::=
<modificador> <tipo> <nome> [= <valorPadrão>];
<tipo> ::=
byte | short | int | long | char | float | double | boolean
| <classeQualquer>

Guia de código:

[] Indica que esta parte é opcional.

Aqui está um exemplo.

public class AttributeDemo {


private String studNum;
public boolean graduating = false;
protected float unitsTaken = 0.0f;
String college;

Introdução à Programação II 7
JEDITM

3.3. Declarando métodos


<declaraçãoMétodo> ::=
<modificador> <tipoRetorno> <nome>(<argumento>*) {
<instrução>*
}
<argumento> ::=
<tipoArgumento> <nomeArgumento>[,]

Por exemplo:
class MethodDemo {
int data;
int getData() {
return data;
}
void setData(int data) {
this.data = data;
}
void setMaxData(int data1, int data2) {
data = (data1>data2)? data1 : data2;
}
}

3.4. Declarando um construtor


<declaraçãoConstrutor> ::=
<modificador> <nome da classe> (<argumento>*) {
<instrução;>*
}

Se um construtor não é explicitamente fornecido, um construtor padrão é automaticamente


criado. O construtor padrão não possui argumentos e o seu corpo não possui instruções.

Dicas de programação:

1. O nome do construtor deve ser o mesmo nome da classe.


2. O único <modificador> válido para construtores são public, protected, e
private.
3. Construtores não possuem valor de retorno.

Considere a seguinte classe:


class ConstructorDemo {
private int data;
public ConstructorDemo() {
data = 100;
}
ConstructorDemo(int data) {
this.data = data;
}
}

3.5. Construir um objeto


Para construir um objeto a partir de uma classe, utilizamos a palavra-chave new seguida por uma
chamada ao construtor.
class ConstructObj {
int data;

Introdução à Programação II 8
JEDITM

ConstructObj() {
/* Inicialização dos dados */
}
public static void main(String args[]) {
ConstructObj obj = new ConstructObj();
}
}

3.6. Acessando elementos dos objetos


Para acessar os elementos de um objeto, utilizamos a notação do "ponto". É usada da seguinte
forma:
<objeto>.<elemento>

O exemplo seguinte, feito com base no anterior com instruções adicionais para acessar os
elementos.
class ConstructObj {
int data;
ConstructObj() {
/* Dados de inicialização */
}
void setData(int data) {
this.data = data;
}
public static void main(String args[]) {
ConstructObj obj = new ConstructObj(); //instanciamento
obj.setData(10); //acesso a setData()
System.out.println(obj.data); //acesso a data
}
}

A execução desta classe mostrará o seguinte resultado:

10

3.7. Pacotes
Para indicar que uma determinada classe pertence a um pacote em particular, utilizamos a
seguinte sintaxe:

<declaraçãoPacote> ::=
package <nomePacote>;

Para importar outros pacotes, use a seguinte sintaxe:


<declaraçãoImportação> ::=
import <nomePacote.elementoAcessado>;

Com isso, seu código fonte deve ter o seguinte formato:


[<declaraçãoPacote>]
<declaraçãoImportação>*
<declaraçãoClasse>+

Guia de código:

+ que pode ter 1 ou mais ocorrências da linha onde isso foi aplicado.

Vejamos o seguinte exemplo:


// Classe pertence ao pacote registration.reports

Introdução à Programação II 9
JEDITM

package registration.reports;

// Importa todas as classes do pacote registration.processing


import registration.processing.*;
// Importa a classe List do pacote java.util
import java.util.List;

// Cria a classe myClass


class MyClass {
/* detalhes da classe MyClass */
}

3.8. Os modificadores de acesso


A tabela seguinte resume os modificadores de acesso em Java.

private default protected public


Mesma classe sim sim sim sim
Mesmo pacote não sim sim sim
Pacotes diferentes (sendo subclasse) não não sim sim
Pacotes diferentes (não sendo subclasse) não não não sim
Tabela 1: Modificadores de acesso

3.9. Encapsulamento
Protege os elementos da implementação de uma classe por ser realizado utilizando o modificador
de acesso particular na declaração dos atributos.
O exemplo seguinte protege o atributo secret. Note que este atributo é indiretamente acessado
por outras classes utilizando os métodos get e set.
class Encapsulation {
private int secret; //Campo oculto
public boolean setSecret(int secret) {
if (secret < 1 || secret > 100) {
return false;
}
this.secret = secret;
return true;
}
public int getSecret() {
return secret;
}
}

Caso não se deseje que outras classes modifiquem o atributo secret, é possível configurar o
modificador de acesso do método setSecret() como particular (private).

3.10. Herança
Para se criar uma classe filha ou uma subclasse com base em uma classe existente, utilizamos a
palavra-chave extends na declaração da classe. Uma classe pode estender qualquer classe desde
que ela não possua o modificador final.

Por exemplo. A classe Point é a super-classe da classe ColoredPoint:

import java.awt.*;
class Point {
int x;

Introdução à Programação II 10
JEDITM

int y;
}

class ColoredPoint extends Point {


Color color;
}

3.11. Realizando override em métodos


Um método de uma subclasse pode modificar um método de uma super-classe quando a
subclasse define um método cuja assinatura é idêntica ao método da super-classe. A assinatura
de um método e a informação encontrada no cabeçalho de definição deste. A assinatura inclui o
tipo de retorno, o nome e a lista de argumentos do método. Os modificadores de acesso e outras
palavras-chaves, tais como final e static, não estão incluídos.

class Superclass {
void display(int n) {
System.out.println("super: " + n);
}
}
class Subclass extends Superclass {
void display(int k) { // método overriding
System.out.println("sub: " + k);
}
}
class OverrideDemo {
public static void main(String args[]) {
Subclass SubObj = new Subclass();
Superclass SuperObj = SubObj;
SubObj.display(3);
((Superclass)SubObj).display(4);
}
}

A execução desta classe mostrará o seguinte resultado:

sub: 3
sub: 4

O método chamado é determinado pelo tipo de dado do objeto que invoca o método.
Os modificadores de acesso dos métodos não precisam ser os mesmos. Contudo, os métodos
polimórficos devem ter modificadores de acesso igual ou menos restritivos que os métodos
originais.
Considere o seguinte exemplo. Vejamos qual dos seguintes métodos com polimorfismo por
override pode causar um erro no momento de compilação.
class Superclass {
void overriddenMethod() {
}
}

class Subclass1 extends Superclass {


public void overriddenMethod() {
}
}

class Subclass2 extends Superclass {


void overriddenMethod() {
}
}

Introdução à Programação II 11
JEDITM

class Subclass3 extends Superclass {


protected void overriddenMethod() {
}
}

class Subclass4 extends Superclass {


private void overriddenMethod() {
}
}

O método overriddenMethod() da Superclass possui o modificador de acesso default. O único


modificador mais restrito que esse é o private. Sendo assim, Subclass4 provoca um erro de
compilação porque ele tenta modificar o método overriddenMethod() na Superclass com um
modificar private que é mais restritivo.

3.12. Classes e métodos abstratos


A forma genérica para um método abstrato é a seguinte:

abstract <modificador> <tipoRetorno> <nome>(<argumento>*);

Uma classe contendo um método abstrato deve ser declarada como uma classe abstrata.

abstract class <Nome> {


/* construtores, campos e métodos */
}

A palavra-chave abstract não pode ser aplicada para construtores ou métodos estáticos. É
importante lembrar também que classes abstratas não podem servir para a construção de objetos
(desde que seus métodos sejam implementados).
Classes que estendem uma classe abstrata são obrigadas a implementar todos os métodos
abstratos. Caso contrário a subclasse deverá ser declarada também como abstract.
Dicas de programação:

1. Note que declarar um método abstract é muito similar à declaração de uma


classe normal exceto que um método abstrato não possui corpo. Sua assinatura
é imediatamente finalizada por um ponto e vírgula (;). Por exemplo:

abstract class SuperHero {


abstract void displayPower();
}
class Superman extends SuperHero {
void displayPower() {
System.out.println("Fly...");
}
}

class SpiderMan extends SuperHero {


void displayPower() {
System.out.println("Fast...");
}
}

3.13. Interface
Declarar uma interface é basicamente como declarar uma classe, entretanto, ao invés de utilizar
a palavra-chave class, utilizamos a palavra-chave interface. Eis a sintaxe:

Introdução à Programação II 12
JEDITM

<declaraçãoInterface> ::=
<modificador> interface <Nome> {
<declaraçãoAtributo>*
[<modificador> <tipoRetorno> <nome>(<argumento>*);]*
}

Os métodos e atributos são obrigatoriamente public.

Dicas de programação:

1. Atributos são implicitamente static e final e são obrigados a serem inicializados


com um valor constante.
2. Como na declaração de uma classe de alto nível, o único modificador de acesso
válido são public e package (caso nenhum modificador de acesso preceder a
palavra-chave class).

Uma classe pode implementar uma interface existente utilizando a palavra-chave implements.
Esta classe é obrigada a implementar todos os métodos da interface. Uma classe pode
implementar mais de uma interface.
O exemplo a seguir demonstra com declarar e utilizar uma interface:
interface MyInterface {
void iMethod();
}
class MyClass1 implements MyInterface {
public void iMethod() {
System.out.println("Interface method.");
}

void myMethod() {
System.out.println("Another method.");
}
}

class MyClass2 implements MyInterface {


public void iMethod() {
System.out.println("Another implementation.");
}
}

class InterfaceDemo {
public static void main(String args[]) {
MyClass1 mc1 = new MyClass1();
MyClass2 mc2 = new MyClass2();

mc1.iMethod();
mc1.myMethod();
mc2.iMethod();
}
}

A execução desta classe mostrará o seguinte resultado:


Interface method.
Another method.
Another implementation.

Introdução à Programação II 13
JEDITM

3.14. A palavra-chave this


A palavra-chave this pode ser utilizada pela seguintes razões:
1. Diferenciar atributos locais dos atributos de classe.
2. Referenciar objetos que invocam métodos não estáticos.
3. Referenciar outros construtores.
Como exemplo, considere a seguinte classe onde data funciona como um atributo e um
argumento ao mesmo tempo:
class ThisDemo1 {
int data;
void method(int data) {
this.data = data;
/* this.data refere-se ao atributo
enquanto data refere-se ao argumento */
}
}

O exemplo seguinte demonstra como este objeto é implicitamente referenciado quando os seus
elementos não estáticos são invocados.
class ThisDemo2 {
int data;
void method() {
System.out.println(data); //this.data
}
void method2() {
method(); //this.method();
}
}

Vamos rever o significado de polimorfismo por overloading. Um construtor, assim como um


método, pode ser modificado. Métodos diferentes numa mesma classe podem compartilhar o
mesmo nome desde que a lista de seus argumentos sejam diferentes. Métodos overloading
precisam diferir no número ou no tipo de seus argumentos. Este próximo exemplo possui dois
construtores e a referência this é utilizada para se referenciar a outras versões do construtor.
class ThisDemo3 {
int data;
ThisDemo3() {
this(100);
}
ThisDemo3(int data) {
this.data = data;
}
}

Dicas de programação:

1. A chamada para this() deve ser a primeira instrução no construtor.

3.15. A palavra-chave super


O uso da palavra-chave super está relacionado com herança. É utilizada para chamar
construtores da super-classe. Também pode ser utilizada como a palavra-chave this para
referenciar elementos da super-classe.

Introdução à Programação II 14
JEDITM

A classe a seguir demonstra como a referência super é utilizada para chamar o construtor da
super-classe.

class Person {
String firstName;
String lastName;
Person(String fname, String lname) {
firstName = fname;
lastName = lname;
}
}

class Student extends Person {


String studNum;
Student(String fname, String lname, String sNum) {
super(fname, lname);
studNum = sNum;
}
}

Dicas de programação:

1. super() refere-se a super-classe imediata. Ela deve ser a primeira instrução do


contrutor da subclasse.

Está palavra-chave também pode ser utilizada para referenciar os elementos da super-classe
como mostrado no exemplo seguinte.

class Superclass{
int a;
void display_a(){
System.out.println("a = " + a);
}
}

class Subclass extends Superclass {


int a;
void display_a(){
System.out.println("a = " + a);
}
void set_super_a(int n){
super.a = n;
}
void display_super_a(){
super.display_a();
}
}

class SuperDemo {
public static void main(String args[]){
Superclass SuperObj = new Superclass();
Subclass SubObj = new Subclass();
SuperObj.a = 1;
SubObj.a = 2;
SubObj.set_super_a(3);
SuperObj.display_a();
SubObj.display_a();
SubObj.display_super_a();
System.out.println(SubObj.a);
}

Introdução à Programação II 15
JEDITM

A execução desta classe mostrará o seguinte resultado:

a = 1
a = 2
a = 3
2

3.16. A palavra-chave static


A palavra-chave static pode ser aplicada a elementos de uma classe. Permite que atributos ou
métodos das classes sejam acessados antes que qualquer instância da classe seja criada.
Um atributo de classe possui o acesso global para a classe. Isto significa que o atributo pode ser
acessado por todas as instâncias da classe.
Métodos estáticos podem ser invocados sem necessitar criar uma instância da classe. Todavia,
eles só acessam os elementos estáticos da classe. Além disso, eles não podem fazer referencia
aos objetos this ou super.
A palavra-chave static pode também ser aplicada aos free-blocks. Estes são chamados de blocos
estáticos. Estes blocos são executados somente uma vez quando a classe é carregada. Eles são
usualmente utilizados para inicializar atributos estáticos da classe.
class Demo {
static int a = 0;
static void staticMethod(int i) {
System.out.println(i);
}
static { //static block
System.out.println("This is a static block.");
a += 1;
}
}

class StaticDemo {
public static void main(String args[]) {
System.out.println(Demo.a);
Demo.staticMethod(5);
Demo d = new Demo();
System.out.println(d.a);
d.staticMethod(0);
Demo e = new Demo();
System.out.println(e.a);
d.a += 3;
System.out.println(Demo.a+", " +d.a +", " +e.a);
}
}

A execução desta classe mostrará o seguinte resultado:


This is a static block.
1
5
1
0
1
4, 4, 4

3.17. A palavra-chave final


A palavra-chave final pode ser utilizada para atributos, métodos e classes. Para lembrar da

Introdução à Programação II 16
JEDITM

função da palavra-chave final, simplesmente lembre-se que ela restringe a modificação de


atributos, métodos e classes.
O valor de um atributo final não pode ser modificado uma vez que esse valor foi determinado. Por
exemplo:
final int data = 10;

A instrução seguinte irá causar um erro de compilação:


data++;

Um método final não pode ser modificado na classe filha:


final void myMethod() { //em uma classe pai
}

myMethod não poderá mais ser realizado o polimorfismo por override na classe filha.
Uma classe final não poderá mais ser herdada ao contrário das classes comuns.
final public class MyClass {
}

Dicas de programação:

1. A ordem de digitação das palavras-chaves final e public podem ser trocadas.


2. Essa instrução irá provocar um erro de compilação, pois MyClass não pode ser
extendida.

public WrongClass extends MyClass {


}

3.18. Classes internas


Uma classe interna é uma classe declarada dentro de outra classe.

class OuterClass {
int data = 5;
class InnerClass {
int data2 = 10;
void method() {
System.out.println(data);
System.out.println(data2);
}
}
public static void main(String args[]) {
OuterClass oc = new OuterClass();
InnerClass ic = oc.new InnerClass();
System.out.println(oc.data);
System.out.println(ic.data2);
ic.method();
}
}

A execução desta classe mostrará o seguinte resultado:


5
10

Introdução à Programação II 17
JEDITM

Para acessarmos os elementos da classe interna, precisamos de uma instância da classe interna.
Métodos de uma classe interna podem acessar diretamente os elementos da classe externa.

Introdução à Programação II 18
Módulo 2
Introdução à Programação II

Lição 2
Exceções e Assertivas

Versão 1.0 - Mar/2007


JEDITM

1. Objetivos
O conceito básico sobre tratamento de exceções foi mostrado no Módulo 1 – Introdução a
Programação I. Esta lição fornecerá um entendimento aprofundado sobre exceções e também
sobre assertivas.

Ao final desta lição, o estudante será capaz de:

• Tratar exceções pelo uso de try, catch e finally


• Diferenciar entre o uso de throw e throws
• Utilizar as classes de exceções existentes
• Diferenciar entre exceções verificadas e não verificadas
• Definir suas próprias classes de exceção
• Explicar os benefícios do uso de assertivas
• Utilizar declarações assertivas

Introdução à Programação II 4
JEDITM

2. O que são exceções?


2.1. Introdução
Bugs ou erros ocorrem freqüentemente na execução dos projetos, mesmo quando estes são
escritos por programadores hábeis e experientes. Para evitar perder mais tempo na verificação do
erro do que na resolução do problema em si, Java nos fornece um mecanismo para o tratamento
de exceções.

As exceções são, resumidamente, eventos excepcionais. São erros que ocorrem durante a
execução de um determinado trecho de instrução, alterando o seu fluxo normal. Os erros podem
ocorrer por diferentes motivos, por exemplo: erros de divisão por zero, acessar elementos em um
array além de seu próprio tamanho, entrada inválida, erro de acesso ao disco rígido, abertura de
arquivo inexistente e estouro de memória.

2.2. As classes Error e Exception


Todas as exceções são sub-classes, direta ou indiretamente, da classe Throwable. Imediatamente
abaixo desta classe encontram-se as duas categorias gerais de exceções: as classes Error e
Exception.

A classe Exception lida com as condições que os usuários podem tratar. Em geral, estas condições
são o resultado de algumas falhas no código. Exemplo de exceções são: erro de divisão por zero
e erro de índice em um array.

Por outro lado, a classe Error é utilizada pela JVM para manipular os erros ocorridos no ambiente
de execução. Geralmente, estes erros estão além do controle do programador, desde que sejam
causados dentro do ambiente de execução. Por exemplo: erro de falta de memória e erro de
acesso ao disco rígido.

2.3. Exemplo de Exceção


Considere a seguinte classe:

class DivByZero {
public static void main(String args[]) {
System.out.println(3/0);
System.out.println(“Pls. print me.”);
}
}

Executando o código, a seguinte mensagem de erro será apresentada:

Exception in thread "main" java.lang.ArithmeticException: / by zero at


DivByZero.main(DivByZero.java:3)

A mensagem fornece a informação do tipo de exceção que ocorreu e a linha do código que a
originou. Esta é a forma como o manipulador padrão trata as exceções não capturadas. Quando
não há código do usuário tratando as exceções, o manipulador padrão de exceções entra em
ação. Primeiramente, a descrição da exceção que ocorreu é apresentada. Além disso, também é
apresentado o caminho que indica a hierarquia dos métodos até onde a exceção aconteceu. Por
fim, o manipulador padrão de exceções faz com que o código termine sua execução.

Ao necessitar tratar as exceções de uma maneira diferente? Felizmente, a linguagem Java possui
três importantes palavras-chaves para o tratamento de exceções try, catch e finally.

Introdução à Programação II 5
JEDITM

3. Capturando Exceções
3.1. As instruções try-catch
Como mencionado na seção anterior, as palavras-chaves try, catch e finally são usadas para
tratar diferentes tipos de exceções. Estas três palavras-chaves são usadas juntas mas o bloco
finally é opcional. Primeiramente, focaremos no bloco try-catch e mais tarde voltaremos ao bloco
finally.

Encontra-se abaixo a sintaxe geral de uma instrução try-catch.

try {
<código a ser monitorado para exceções>
} catch (<ClasseExceção1> <nomeObj>) {
<tratar se ClasseExceção1 ocorrer>
}
...
} catch (<ClasseExceçãoN> <NomeObj>) {
<tratar se ClasseExceçãoN ocorrer>
}

Dicas de programação:

1. O bloco catch começa depois do fechamento do bloco precedente, seja


este try ou catch.
2. Instruções dentro do bloco devem ser recuadas de modo a conseguir uma
melhor visualização.

Aplicando isto a classe DivByZero teremos:

class DivByZero {
public static void main(String args[]) {
try {
System.out.println(3/0);
System.out.println(“Please print me.”);
} catch (ArithmeticException exc) {
//reação ao evento
System.out.println(exc);
}
System.out.println(“After exception.”);
}
}

O erro de divisão por zero é um exemplo de um tipo de exceção encontrado na classe


ArithmeticException. O código trata o erro simplesmente apresentando uma descrição do
problema.

Como saída para esta classe, teremos:

java.lang.ArithmeticException: / by zero
After exception.

Um código específico monitorado no bloco try pode causar a ocorrência de mais de um tipo de
exceção. Neste caso, os diferentes tipos de erro podem ser tratados pelo uso de diversos blocos
catch. Observe que o código no bloco try pode acionar apenas uma exceção por vez, mas pode
provocar a ocorrência de diferentes tipos de exceção em momentos diferentes.

Aqui temos um exemplo de uma classe que trata mais de um tipo de exceção:

Introdução à Programação II 6
JEDITM

class MultipleCatch {
public static void main(String args[]) {
try {
int den = Integer.parseInt(args[0]); //linha 4
System.out.println(3/den); //linha 5
} catch (ArithmeticException exc) {
System.out.println(“Divisor was 0.”);
} catch (ArrayIndexOutOfBoundsException exc2) {
System.out.println(“Missing argument.”);
}
System.out.println(“After exception.”);
}
}

Neste exemplo, a linha 4 pode retornar uma ArrayIndexOutOfBoundsException quando o usuário


se esquecer de entrar com um argumento enquanto a linha 5 retorna uma ArithmeticException
se o usuário entrar 0 como argumento.

Veja o que acontece ao executar a classe quando os seguintes argumentos abaixo são informados
pelo usuário:

1. Se nenhum argumento for passado, a seguinte saída será apresentada:

Missing argument.
After exception.

2. Passando o valor 1 como argumento, a seguinte saída será apresentada:

3
After exception.

3. Passando o valor 0, a seguinte saída será apresentada:

Divisor was 0.
After exception.

Também é possível aninhar blocos try em Java.

class NestedTryDemo {
public static void main(String args[]){
try {
int a = Integer.parseInt(args[0]);
try {
int b = Integer.parseInt(args[1]);
System.out.println(a/b);
} catch (ArithmeticException e) {
System.out.println(“Divide by zero error!");
}
} catch (ArrayIndexOutOfBoundsException exc) {
System.out.println(“2 parameters are required!");
}
}
}

Vejamos o que acontece a classe quando os seguintes argumentos são informado:

a) Nenhum argumento

2 parameters are required!

Introdução à Programação II 7
JEDITM

b) Valor 15

2 parameters are required!

c) Valor 15 3

d) Valor 15 0

Divide by zero error!

O código abaixo possui um try aninhado mascarado com o uso de métodos:

class NestedTryDemo2 {
static void nestedTry(String args[]) {
try {
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
System.out.println(a/b);
} catch (ArithmeticException e) {
System.out.println("Divide by zero error!");
}
}
public static void main(String args[]){
try {
nestedTry(args);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("2 parameters are required!");
}
}
}

Qual é a saída dessa classe quando testado com os seguintes argumentos?

a) Nenhum argumento
b) 15
c) 15 3
d) 15 0

A saída esperada para a classe NestedTryDemo2 é similar a classe NestedTryDemo.

3.2. A palavra-chave finally


Iremos agora incorporar a palavra-chave finally à instrução try-catch. Observe como as palavras
reservadas são organizadas no bloco:

try {
<código a ser monitorado para exceções>
} catch (<ClasseExceção1> <nomeObj>) {
<tratar se ClasseExceção1 ocorrer>
} ...
} finally {
<código a ser executado antes do bloco try ser finalizado>
}

Introdução à Programação II 8
JEDITM

Dicas de programação:

1. A mesma convenção de codificação se aplica ao bloco finally como no


bloco catch. O bloco finally começa depois do fechamento do bloco catch
precedente.
2. Instruções dentro desse bloco devem ser também adiantadas de forma a
conseguir melhor clareza no código.

O bloco finally contém o código para a finalização após um try ou catch. Este bloco de código é
sempre executado independentemente de uma exceção acontecer ou não no bloco try. Isto
permanece verdadeiro mesmo que instruções return, continue ou break sejam executadas.

Vejamos um exemplo completo com o bloco try-catch-finally:

class FinallyDemo {
public static void main(String args[]) {
for (int i = 1; i > -1; i--) {
try {
System.out.println(2/i);
} catch (ArithmeticException e) {
System.out.println("Divide by zero error!");
} finally {
System.out.println("Finally forever!");
}
}
}
}

A saída esperada para esta classe, será:

2
Finally forever!
Divide by zero error!
Finally forever!

Introdução à Programação II 9
JEDITM

4. Lançamento de Exceções
4.1. A palavra-chave throw
Além de capturar exceções, Java também permite que os métodos lancem exceções (por
exemplo, faz com que um evento excepcional ocorra). A sintaxe para o lançamento de exceções
é:

throw <objetoExceção>;

Considere este exemplo:

class ThrowDemo {
public static void main(String args[]){
try {
throw new RuntimeException("throw demo");
} catch (RuntimeException e) {
System.out.println("Exception caught here.");
System.out.println(e);
}
}
}

Esta classe mostrará a seguinte saída:

Exception caught here.


java.lang.RuntimeException: throw demo

4.2. A palavra-chave throws


No caso de um método causar uma exceção mas não capturá-la, deve-se utilizar a palavra-chave
throws para repassar esta para quem o chamou. Esta regra se aplica apenas para exceções
verificadas. Veremos mais sobre exceções verificadas e não-verificadas mais a frente.

Esta é a sintaxe para o uso da palavra-chave throws:

<tipo>* <nomeMetodo> (<argumento>*) throws <listaExcecao> {


<instrução>*
}

É necessário um método para cada catch ou lista de exceções que podem ser lançadas, contudo
podem ser omitidas aquelas do tipo Error ou RuntimeException, bem como suas sub-classes.

Este exemplo indica que myMethod não trata ClassNotFoundException.

class ThrowingDemo {
public static void myMethod() throws ClassNotFoundException {
throw new ClassNotFoundException("just a demo");
}
public static void main(String args[]) {
try {
myMethod();
} catch (ClassNotFoundException e) {
System.out.println(e);
}
}
}

A classe apresentará a seguinte saída:

Introdução à Programação II 10
JEDITM

java.lang.ClassNotFoundException: just a demo

Existem quatro cenários diferentes num bloco try-catch-finally:

1. Uma saída forçada ocorre quando o fluxo de controle é forçado a sair do bloco try por uma
instrução return, continue ou break.
2. As instruções dentro do bloco try-catch-finally executam normalmente sem que erro
algum ocorra.
3. O código pode ter um bloco catch específico para tratar a exceção que foi lançada.
4. Temos o oposto do terceiro cenário, onde a exceção não é tratada. Nesse caso, a exceção
lançada não foi tratada por nenhum bloco catch.

Estes cenários são vistos na classe a seguir:

class FourDemo {
static void myMethod(int n) throws Exception{
try {
switch(n) {
case 1: System.out.println("first case"); return;
case 3: System.out.println("third case");
throw new RuntimeException("third case demo");
case 4: System.out.println("fourth case");
throw new Exception("fourth case demo");
case 2: System.out.println("second case");
}
} catch (RuntimeException e) {
System.out.print("RuntimeException caught: " + e.getMessage());
} finally {
System.out.println("try-block is entered.");
}
}
public static void main(String args[]){
for (int i=1; i<=4; i++) {
try {
FourDemo.myMethod(i);
} catch (Exception e){
System.out.print("Exception caught: ");
System.out.println(e.getMessage());
}
System.out.println();
}
}
}

As seguintes linhas são esperadas como saída dessa classe:

first case
try-block is entered.

second case
try-block is entered.

third case
RuntimeException caught: third case demo
try-block is entered.

fourth case
try-block is entered.
Exception caught: fourth case demo

Introdução à Programação II 11
JEDITM

5. Categorias de Exceções
5.1. Hierarquia das Classes de Exceções
Conforme mencionado anteriormente, a classe de origem de todas as classes de exceção é
Throwable. Abaixo encontra-se a hierarquia das classes de exceções. Todas essas exceções estão
definidas no pacote java.lang.

Hierarquia das Classes de Exceções


Throwable Error LinkageError, ...
VirtualMachineError, ...
Exception ClassNotFoundException,
CloneNotSupportedException,
IllegalAccessException,
InstantiationException,
InterruptedException,
IOException, EOFException,
FileNotFoundException,
...
RuntimeException, ArithmeticException,
ArrayStoreException,
ClassCastException,
IllegalArgumentException,
(IllegalThreadStateException e
NumberFormatException como sub-classes)
IllegalMonitorStateException,
IndexOutOfBoundsException,
NegativeArraySizeException,
NullPointerException,
SecurityException
...
Tabela 1: Hierarquia das Classes de Excessões

Agora que estamos familiarizados com diversas classes de exceção, devemos conhecer a seguinte
regra: Múltiplos blocos catch devem ser ordenados da sub-classe para a super-classe.

class MultipleCatchError {
public static void main(String args[]){
try {
int a = Integer.parseInt(args [0]);
int b = Integer.parseInt(args [1]);
System.out.println(a/b);
} catch (Exception e) {
System.out.println(e);
} catch (ArrayIndexOutOfBoundsException e2) {
System.out.println(e2);
}
System.out.println("After try-catch-catch.");
}
}

A compilação desse código produzirá a mensagem de erro abaixo, já que a classe Exception é
super-classe da classe ArrayIndexOutOfBoundsException.

MultipleCatchError.java:9: exception
java.lang.ArrayIndexOutOfBoundsException has already been caught
} catch (ArrayIndexOutOfBoundsException e2) {

Introdução à Programação II 12
JEDITM

5.2. Exceções Verificadas e Não-verificadas


Uma exceção pode ser verificada ou não-verificada.

Uma exceção verificada é aquela que é verificada pelo compilador Java. O compilador se certifica
que cada catch ou lista de exceções encontram-se dentro da cláusula throws. Se a exceção
verificada não for capturada nem listada, ocorre um erro de compilação.

Ao contrário das exceções verificadas, as exceções não-verificadas não são condicionadas à


verificação para o tratamento de exceções no momento da compilação. As classes de exceção
não-verificadas são: Error, RuntimeException, e suas sub-classes. Desse modo, estes tipos de
exceção não são verificadas porque o tratamento de todas as exceções pode complicar o código o
que causaria um enorme transtorno.

5.3. Exceções Definidas pelo Usuário

Apesar de muitas classes de exceção já existirem no pacote java.lang, as classes de exceção


embutidas não são suficientes para cobrir todas possibilidades de exceções que podem ocorrer.
Por essa razão, é provável criar nossas próprias exceções.

Para criar nossa própria exceção, teremos que criar uma classe que estenda a classe
RuntimeException ou Exception. Deste modo, devemos customizar a classe de acordo com o
problema a ser resolvido. Atributos de objeto e construtores podem ser adicionados na sua classe
de exceção.

Segue um exemplo:

class ExplodeException extends RuntimeException{


public ExplodeException(String msg) {
super(msg);
}
}
class ExplodeDemo {
public static void main(String args[]) {
try {
throw new ExplodeException("Explode Message");
} catch (ExplodeException e) {
System.out.println("Message: " + e.getMessage());
}
}
}

Aqui está a saída esperada para a classe:

Message: Explode Message

Introdução à Programação II 13
JEDITM

6. Assertivas
6.1. O que são Assertivas?
Assertivas permitem ao programador descobrir se uma suposição foi encontrada. Por exemplo,
uma data onde o mês não está no intervalo entre 1 e 12 deveria ser considerada inválida. O
programador pode afirmar que o mês deve se encontrar neste intervalo. Contudo, é possível
utilizar outros construtores para simular a funcionalidade das assertivas, mas seria difícil fazer
isto de alguma maneira com o recurso da assertiva desabilitado. A boa notícia sobre assertivas é
que o usuário tem a opção de habilitá-la ou não na execução.

Assertivas podem ser consideradas como uma extensão de comentários em que a assertiva
informa à pessoa que lê o código que uma condição específica deve ser sempre satisfeita. Com
assertivas não há necessidade de ler cada comentário para descobrir suposições feitas no código.
Em vez disso, ao executar a classe, a mesma informará se as assertivas feitas são verdadeiras ou
não. No caso de uma assertiva ser falsa, um AssertionError será lançado.

6.2. Habilitando e Desabilitando Assertivas


Para utilizar as declarações assertivas não se faz necessário a importação do pacote
java.util.assert. Declarações assertivas são utilizadas para verificar os argumentos de métodos
não-públicos, pois métodos públicos podem ser acessados diretamente por quaisquer outras
classes. É possível que os autores dessas outras classes não estejam atentos que eles terão
assertivas habilitadas. Nesse caso, a classe poderá agir incorretamente. Já os métodos não
públicos, geralmente, são chamados por meio de códigos escritos por pessoas que tem acesso
aos métodos. Desse modo, eles devem estar cientes que ao executar seu código, as assertivas
devem estar habilitadas.

Para compilar arquivos que usam assertivas, um parâmetro extra na linha de comando é
necessário como mostrado abaixo:

javac –source 1.4 MyProgram.java

Para executar a classe sem o recurso da assertiva, basta executá-la normalmente:

java MyProgram

Todavia, para habilitar o recurso das assertivas, é necessário utilizar os argumentos –ea ou
-enableassertions:

java –enableassertions MyProgram

Para habilitar a verificação de assertivas em tempo de execução no NetBeans IDE, siga os


seguintes passos:

1. Procure o nome do projeto no painel Projects à esquerda. Pressione com o botão direito no
nome do projeto
2. Selecione Properties
3. À esquerda, no painel Categories, selecione run
4. No campo VM Options insira -ea
5. Clique no botão OK
6. Compile e execute o projeto normalmente.

As telas abaixo irão ajudá-lo a entender cada passo:

Introdução à Programação II 14
JEDITM

Figura 1: Habilitando assertivas no NetBeans – Passos 1 e 2

Figura 2: Habilitando assertivas no NetBeans – Passo 3

Introdução à Programação II 15
JEDITM

Figura 3: Habilitando assertivas no NetBeans – Passo 4

6.3. Sintaxe das Assertivas


A sintaxe das assertivas pode ser feita de duas formas.

A forma mais simples tem a seguinte sintaxe:

assert <expressãoLógica>;

onde <expression1> é a condição que é afirmada para ser verdadeira.

A outra forma utiliza duas expressões como demostra a sintaxe abaixo:

assert <expressãoLógica> : <mensagem>;

onde <expression1> é a condição que é afirmada para ser verdadeira e <expression2> é alguma
informação útil para diagnosticar o motivo da instrução ter falhado.

Aqui temos um exemplo da forma mais simples de utilizar assertivas:

class AssertDemo {
public static void main(String args[]) {
assert(args == null);
int age = Integer.parseInt(args[0]);
if (age >= 18) {
System.out.println("Congrats! You're an adult! =)");
}
}
}

A execução desta classe lança um AssertionError quando não existe argumento passado para a
classe. Nesse caso, a seguinte mensagem de erro é apresentada na execução.

Introdução à Programação II 16
JEDITM

Exception in thread "main" java.lang.AssertionError


at AssertDemo.main(AssertDemo.java:4)
Java Result: 1

Passando como argumento um valor maior que 0 e menor que 18, a classe não apresentará
nenhuma saída.

Para um argumento com valor maior ou igual a 18, será mostrada a seguinte saída:

Congrats! You're an adult! =)

As instruções seguinte é similar ao exemplo anterior exceto por apresentar uma informação
adicional sobre a exceção ocorrida. Dessa forma utiliza-se a segunda sintaxe das assertivas.

class AssertDemo {
public static void main(String args[]) {
int age = Integer.parseInt(args[0]);
assert(age>0) : "age should at least be 1";
/* se a idade é válida (ex. age>0) */
if (age >= 18) {
System.out.println("Congrats! You're an adult! =)");
}
}
}

Quando o usuário entra com um argumento menor do que 1, ocorre um AssertionError e são
apresentadas informações adicionais da exceção. Nesse cenário, a seguinte saída é apresentada.

Exception in thread "main" java.lang.AssertionError: age should at


least be 1
at AssertDemo.main(AssertDemo.java:4)
Java Result: 1

Para os outros casos, esta classe nos apresenta uma saída similar ao exemplo anterior.

Introdução à Programação II 17
Módulo 2
Introdução à Programação II

Lição 3
Técnicas Avançadas de Programação

Versão 1.0 - Mar/2007


JEDITM

1. Objetivos
Esta lição introduz algumas técnicas avançadas de programação. Veremos detalhes sobre
recursão e tipos de dados abstratos.

Ao final desta lição, o estudante será capaz de:

• Definir e aplicar recursão na programação


• Diferenciar entre pilhas e filas
• Implementar pilhas e filas seqüenciais
• Implementar pilhas e filas encadeadas
• Usar as classes Collection existentes

Introdução à Programação II 4
JEDITM

2. Recursão
2.1. O que é recursão?
Recursão é uma técnica poderosa para resolução de problemas que pode ser aplicada quando a
natureza do problema exigir repetição. Ainda que estes tipos de problemas sejam solucionáveis
utilizando a iteração (ex. uso de instruções de repetição como for, while e do-while). De fato, a
iteração é uma ferramenta mais eficiente se comparada à recursão, mas a recursão provê uma
solução mais elegante para o problema. Na recursão, é permitido aos métodos chamarem a si
mesmos. O dado passado no método como argumento é armazenado temporariamente em uma
pilha antes que a chamada do método seja completada.

2.2. Recursão versus Iteração


Para uma boa compreensão da recursão, observe como a técnica de repetição pode variar.

Determinados problemas de natureza repetitiva requerem uso explícito de estruturas de controle


de repetição. Por outro lado, para a recursão, a tarefa é repetida chamando um mesmo método
sucessivas vezes. A idéia aqui é definir o problema em pedaços de instâncias menores de si
mesmo. Considere o cálculo do fatorial de um determinado inteiro. Esta recursão pode ser
descrita da seguinte maneira: fatorial(n) = fatorial(n-1) * n; fatorial(1) = 1. Por exemplo, o
fatorial de 2 é igual ao fatorial(1)*2, o qual é igual a 2. O fatorial de 3 é 6, o qual é igual ao
fatorial(2)*3.

Figura 1: Exemplo de fatorial

Com a iteração, o processo termina quando a condição do laço falha. No caso de se utilizar
recursão, o processo é finalizado uma vez que for encontrada uma condição particular em que
este seja satisfeito. Por exemplo, como observado na definição recursiva do fatorial, o caso mais
simples é quando a entrada é o 1. O 1 para esse problema é o caso básico.

O uso da iteração e da recursão pode em ambos os casos levar a laços infinitos se eles não forem
usados corretamente.

A vantagem da iteração sobre a recursão é o desempenho. A iteração é mais rápida se


comparada à recursão. Na recursão ocorre a passagem de parâmetros para o método, e isto pode
consumir algum tempo de CPU. Entretanto, a recursão encoraja as boas práticas da engenharia
de software pois, usualmente, resulta em um código mais fácil de compreender e promove a
reutilização de uma solução previamente implementada.

Escolher entre iteração e recursão é a melhor maneira de balancear um bom desempenho e uma
boa engenharia de software.

Introdução à Programação II 5
JEDITM

2.3. Fatorial: Um exemplo

O código a seguir mostra como calcular fatorial utilizando a técnica da iteração.

class FatorialDemo {
public int factorial(int n) {
int result = 1;
for (int i = n; i > 1; i--) {
result *= i;
}
return result;
}
public static void main(String args[]) {
FatorialDemo fatorialDemo = new FatorialDemo();
System.out.println(fatorialDemo.factorial(5));
}
}

Aqui é a mesma classe entretanto o método utiliza a recursão:

class FatorialDemo {
public int factorial(int n) {
if (n == 1) { /* saída do método */
return 1;
}
/* Definição recursiva; Invoca a si mesmo */
return factorial(n-1)*n;
}
public static void main(String args[]) {
FatorialDemo fatorialDemo = new FatorialDemo();
System.out.println(fatorialDemo.factorial(5));
}
}

Considere a saída esperada de um determinado código de inteiros. Observe o que acontece no


código para uma determinada entrada. Aqui estão umas amostras de inteiros com suas saídas
correspondentes.

a) Entrada: 1
1
b) Entrada: 3
6
c) Entrada: 5
120

2.4. Imprimindo n em alguma base: Outro exemplo


Agora considere o problema de imprimir um número decimal em uma base específica definida
pelo usuário. Observe que a solução para isto é usar a divisão repetitiva e escrever o resto no
inverso. O processo termina quando a divisão é menor que a base. Assuma que a entrada do
número decimal é 10 e converteremos para a base 8. Aqui está a solução usando caneta e papel.

Introdução à Programação II 6
JEDITM

Na solução, 10 é equivalente a 12 base 8. Aqui está outro exemplo. A entrada decimal é 165 para
ser convertida em base 16.

165 é equivalente ao valor A5 na base 16. Note: A=10.

Essa é a solução iterativa para esse problema.

class DecToOthers {
public static void main(String args[]) {
int num = Integer.parseInt(args[0]);
int base = Integer.parseInt(args[1]);
printBase(num, base);
}
static void printBase(int num, int base) {
int rem = 1;
String digits = "0123456789abcdef";
String result = "";
/* o passo iterativo */
while (num!=0) {
rem = num%base;
num = num/base;
result = result.concat(digits.charAt(rem)+"");
}
/* Imprimindo o inverso do resultado */
for(int i = result.length()-1; i >= 0; i--) {
System.out.print(result.charAt(i));
}
}
}

Agora, essa é a recursão equivalente da solução acima.


class DecToOthersRecur {
static void printBase(int num, int base) {
String digits = "0123456789abcdef";
/* Passo recursivo*/
if (num >= base) {
printBase(num/base, base);
}
/* Caso básico: num < base */
System.out.print(digits.charAt(num%base));
}
public static void main(String args[]) {
int num = Integer.parseInt(args[0]);
int base = Integer.parseInt(args[1]);
printBase(num, base);
}
}

Para atingir uma melhor compreensão do código, observe o conjunto de entrada. Aqui estão
alguns exemplos de entrada.

Introdução à Programação II 7
JEDITM

a) Num: 10, base: 2


1010
b) Num: 100, base: 8
144
c) Num: 200, base: 9
242

Introdução à Programação II 8
JEDITM

3. Tipos de Dados Abstratos

3.1. O que é um Tipo de Dado Abstrato?

Um tipo de dado abstrato (TDA) é uma coleção de elementos de dados providos com um conjunto
de operações que são definidas nos elementos de dados. Pilhas, filas e árvores binárias são
alguns exemplos de TDA. Nessa lição, aprenderemos sobre pilhas (stacks) e filas (queues).

3.2. Pilhas

Uma pilha é um conjunto de elementos de dados onde à manipulação desse elemento é permitida
somente no topo (top) da pilha. A pilha é uma coleção de dados ordenado o qual a disciplina
“último a entrar é o primeiro a sair” (do inglês: “last in, first out” - LIFO) é imposta. Pilhas são
usadas para uma variedade de aplicações como o reconhecimento de padrões e a conversão
entre as notações infixa, pós-fixa e pré-fixa.

As duas operações associadas às pilhas são a de adicionar (push) e a de remover (pop). Push
simplesmente insere o elemento no topo da pilha e, por outro lado, pop remove o elemento do
topo da pilha. Para compreender como as pilhas trabalham, imagine adicionar ou remover um
prato de uma pilha de pratos sua natureza, instintivamente, sugere que seja removido somente o
que está no topo da pilha porque do contrário, existe um perigo de que todos os pratos caiam.

Aqui está um exemplo ilustrando como uma pilha funciona.

n-1
...
6
5 Jayz Top
4 KC
3 Jojo
2 Toto
1 Kyla
0 DMX bottom
Tabela 1: Ilustração da pilha

A pilha está cheia se o topo alcança a célula n-1. Se o topo é igual a n-1, é o indício de que a
pilha está cheia.

3.3. Filas

A fila é outro exemplo de TDA. Fila é uma coleção ordenada de elementos o qual prima pela
disciplina “primeiro a entrar é o primeiro a sair” (do inglês: “first-in, first-out” - FIFO). As
aplicações da fila incluem escalonamento de serviços do sistema operacional, sorteamento
topológico e o grafo transversal.

Enfileirar (enqueue) e Desenfileirar (dequeue) são operações associadas com as filas. Enqueue se
refere ao modo de inserir no final da fila e, por outro lado, dequeue, o de remover o elemento do
início da fila. Para recordar como uma fila trabalha, pense no significado literal de uma fila – uma
linha. Suponha uma fila de um banco e estamos esperando para ser atendido. Se uma pessoa
chegar ela deverá ficar no final da fila. Caso contrário haveria, provavelmente, algum
desentendimento. Essa é a maneira que funciona a inserção (enqueue). Dessa forma, é

Introdução à Programação II 9
JEDITM

necessário que a primeira pessoa seja atendida para somente depois ser a vez da segunda
pessoa da fila, e assim sucessivamente. Essa é a maneira que trabalha a remoção (dequeue).

Aqui está um exemplo de como a fila funciona.

0 1 2 3 4 5 6 7 8 9 ... n-1
Eve Jayz KC Jojo Toto Kyla DMX
front end ← Insere
→ Deleta
Tabela 2: Ilustração da fila

A fila está vazia se o final é menor do que o início. Por outro lado, a fila está cheia quando o final
é igual a n-1.

3.4. Representação seqüencial e encadeada

TDA podem ser representados usando uma representação seqüencial ou encadeada. É fácil criar
uma representação seqüencial com o uso de arrays. Entretanto, o problema com o uso de arrays
está no seu limite de tamanho, o qual é fixo. O espaço de memória ou é desperdiçado ou não é o
bastante com uso dos arrays. Considere o seguinte cenário. Deve ser criado um array com uma
capacidade de armazenar um máximo de 50 elementos. Se o usuário inserir somente 5
elementos, 45 espaços estariam desperdiçados. Por outro lado, se o usuário desejar inserir 51
elementos, o espaço provido pelo array não suportaria.

Comparativamente à representação seqüencial, uma representação encadeada poderia ser


ligeiramente mais difícil de se implementar, mas seria muito mais flexível. O encadeamento se
adapta à necessidade de memória requerida pelo usuário. Uma explanação mais detalhada da
representação encadeada será discutida na sessão a seguir.

Representação seqüencial de uma pilha de inteiros:

public class StackDemo {


int top = -1; /* inicialmente, a pilha está vazia */
int memSpace[]; /* armazenamento para inteiros */
int limit; /* tamanho do espaço de memória */

/* Recebe o tamanho inicial da pilha */


public StackDemo(int size) {
memSpace = new int[size];
limit = size;
}
/* Adiciona um elemento */
public boolean push(int value) {
top++;
if (top < limit) {
memSpace[top] = value;
} else {
top--;
return false;
}
return true;
}
/* Remove um elemento retornando a quantidade de elementos
restantes *
public int pop() {
int temp = -1;
if (top >= 0) {

Introdução à Programação II 10
JEDITM

temp = memSpace[top];
top--;
} else {
return -1;
}
return temp;
}
public static void main(String args[]) {
StackDemo stackDemo = new StackDemo(3);
stackDemo.push(1);
stackDemo.push(2);
stackDemo.push(3);
stackDemo.push(4);
System.out.println(stackDemo.pop());
System.out.println(stackDemo.pop());
System.out.println(stackDemo.pop());
System.out.println(stackDemo.pop());
}
}

A figura a seguir mostra um trecho do método principal de uma pilha seqüencial.

Figura 2: Trecho de uma pilha seqüencial

Introdução à Programação II 11
JEDITM

3.5. Lista encadeada

Antes de implementar a representação encadeada de uma pilha, vamos, primeiramente, estudar


como criar uma representação encadeada. Em particular, nós devemos olhar para as listas
encadeadas.

A lista encadeada é uma estrutura dinâmica, em oposição ao array, que é uma estrutura estática.
A grande vantagem da lista encadeada é que a lista pode crescer ou diminuir de tamanho
dependendo da necessidade do usuário. Uma lista encadeada é definida como uma coleção de
nós, cada qual consiste de um elemento e um encadeamento ou ponteiro para o próximo nó na
lista. A figura a seguir mostra como um nó aponta para outro.

Figura 3: Um nó

Aqui está um exemplo de uma lista encadeada não vazia com três nós.

Figura 4: Uma lista encadeada não vazia com três nós

Esta é uma classe que demonstra como implementar um nó. Pode ser usada para criar uma lista
encadeada:

class Node {
int data; /* dados inteiro contidos em um nó */
Node nextNode; /* o próximo nó da lista */
}
class NodeDemo {
public static void main(String args[]) {
Node emptyList = null; /* cria uma lista vazia */
/* Nó cabeça para o primeiro nó da lista */
Node head = new Node();
/* inicializa o primeiro nó da lista */
head.data = 5;
head.nextNode = new Node();
head.nextNode.data = 10;
/* marca nulo para o final de fila */
head.nextNode.nextNode = null;
/* imprime elementos da lista */
Node currNode = head;
while (currNode != null) {
System.out.println(currNode.data);
currNode = currNode.nextNode;
}
}
}

Trecho da execução do método TestNode.

Introdução à Programação II 12
JEDITM

Figura5: Percurso do nó de teste

Introdução à Programação II 13
JEDITM

3.6. Representação encadeada de uma pilha de inteiros

Agora que aprendemos sobre lista encadeada, estamos prontos para implementar uma
representação encadeada de uma pilha.

public class DynamicIntStackDemo {


private IntStackNode top; /* cabeça ou topo da pilha */
class IntStackNode { /* nó classe */
int data;
IntStackNode next;
IntStackNode(int n) {
data = n;
next = null;
}
}
public void push(int n) {
/* não há necessidade de verificar se está cheio */
IntStackNode node = new IntStackNode(n);
node.next = top;
top = node;
}
public int pop() {
/* dispara uma exceção se a lista estiver vazia */
if (isEmpty())
return -1;
int n = top.data;
top = top.next;
return n;
}
public boolean isEmpty() {
return top == null;
}
public static void main(String args[]) {
DynamicIntStackDemo myStack = new DynamicIntStackDemo();
myStack.push(5);
myStack.push(10);
/* Imprime os elementos da pilha */
IntStackNode currNode = myStack.top;
while (currNode!=null) {
System.out.println(currNode.data);
currNode = currNode.next;
}
System.out.println(myStack.pop());
System.out.println(myStack.pop());
}
}

Aqui está a saída esperada do código acima:

Figura 5: Saída esperada da pilha dinâmica

Introdução à Programação II 14
JEDITM

Figura 6: Trecho da pilha dinâmica

3.7. Java Collections

Introdução à Programação II 15
JEDITM

Os fundamentos dos tipos de dados abstratos mostrados como o básico das listas encadeadas,
pilhas e filas. Esses tipos de dados abstratos já estão implementados e incluídos no Java. As
classes pilha e lista encadeada estão disponíveis para uso sem exigir um completo entendimento
desses conceitos. Entretanto, como cientista da computação, é importante que compreendamos
os tipos de dados abstratos. Na verdade, uma explanação detalhada foi dada na sessão anterior.
Com a liberação da versão do J2SE 5.0, a interface de Filas (Queue) foi disponibilizada. Para mais
detalhes dessas classes e interfaces, por favor, veja a documentação da Java API.

Java provê outras coleções de classes e interfaces, as quais estão disponíveis no pacote java.util.
Exemplos de classes Collections incluem LinkedList, ArrayList, HashSet e TreeSet. Essas classes
são implementações de diferentes coleções e interfaces. A hierarquia das coleções de interface
inicia-se com a interface Collection. Uma Collection é apenas um grupo de objetos que são
conhecidos e seus elementos. Coleções podem permitir duplicidades e não exigir uma ordem
específica.

O SDK não provê nenhuma implementação dessas interfaces, mas sub-interfaces diretas, a
interface Set e a interface List estão disponíveis. Agora, qual é a diferença entre essas duas
interfaces? Um Set é uma coleção não ordenada que não contém duplicidade. Por outro lado, um
List é uma coleção ordenada de elementos onde duplicidades são permitidas. HashSet,
LinkedHashSet e TreeSet são algumas implementações de classes conhecidas da interface Set.
ArrayList, LinkedList e Vector são algumas implementações de classes conhecidas da interface
List.

<Interface Raiz>
Collection
<interface> <interface>
Set List
<Implementada pelas classes> <Implementada pelas classes>
HashSet LinkedHashSet TreeSet ArrayList LinkedList Vector
Tabela 3: Java collections

A seguir está uma lista dos métodos de uma coleção providas na API Collections do Java 2
Platform SE v1.4.1. Em Java 2 Platform SE v1.5.0, esses métodos foram modificados para
acomodar tipos genéricos. Tipos genéricos não serão discutidos ainda. É aconselhável considerar
esses métodos primeiramente. Recomendo que os novos métodos da coleção sejam consultados
uma vez que compreenda os tipos genéricos, os quais são discutidos no próximo capítulo.

Métodos da Collection
public boolean add(Object o)
Insere o objeto enviado como argumento na coleção. Retorna verdadeiro se o objeto foi
adicionado com sucesso.
public void clear()
Remove todos os elementos da coleção.
public boolean remove(Object o)
Remove o objeto enviado como argumento na coleção. Retorna verdadeiro se o objeto
se o objeto foi encontrado e removido com sucesso.
public boolean contains(Object o)
Retorna verdadeiro se a coleção contém o objeto enviado no argumento.
public boolean isEmpty()
Retorna verdadeiro se a coleção estiver vazia.
public int size()

Introdução à Programação II 16
JEDITM

Retorna o número de elementos na coleção.


public Iterator iterator()
Retorna um objeto do tipo Iterator que permite percorrer os elementos da coleção.
Tabela 4: Métodos da classe Collection

Por favor, consulte a documentação da API para uma lista mais completa dos métodos
encontrados nas interfaces Collection, List e Set.

Java SDK apresenta diversas formas de implementação de uma lista encadeada. A classe
LinkedList contém métodos que permitem que listas encadeadas sejam usadas como pilhas, filas
ou algum outro TDA. O código a seguir mostra como usar a classe LinkedList.

import java.util.*;

class LinkedListDemo {
public static void main(String args[]) {
LinkedList list = new LinkedList();
list.add(new Integer(1));
list.add(new Integer(2));
list.add(new Integer(3));
list.add(new Integer(1));
System.out.println(list + ", size = " + list.size());
list.addFirst(new Integer(0));
list.addLast(new Integer(4));
System.out.println(list);
System.out.println(list.getFirst() + ", " + list.getLast());
System.out.println(list.get(2) + ", " + list.get(3));
list.removeFirst();
list.removeLast();
System.out.println(list);
list.remove(new Integer(1));
System.out.println(list);
list.remove(2);
System.out.println(list);
}
}

O ArrayList é uma versão redimensionável de um array. Ela implementa a interface List. Analise o
código a seguir.

import java.util.*;

class ArrayListDemo {
public static void main(String args[]) {
ArrayList al = new ArrayList(2);
System.out.println(al + ", size = " + al.size());
al.add("R");
al.add("U");
al.add("O");
System.out.println(al + ", size = " + al.size());
al.remove("U");
System.out.println(al + ", size = " + al.size());
ListIterator li = al.listIterator();
while (li.hasNext())
System.out.println(li.next());
Object a[] = al.toArray();
for (int i=0; i<a.length; i++)
System.out.println(a[i]);
}

Introdução à Programação II 17
JEDITM

O HashSet é um tipo de implementação da interface Set que usa uma tabela hash. O uso de uma
tabela hash permite buscar os elementos de forma fácil e rápida. A tabela usa uma fórmula que
determina onde um objeto está armazenado. HashSet foi utilizado na seguinte classe:

import java.util.*;

class HashSetDemo {
public static void main(String args[]) {
HashSet hs = new HashSet(5);
System.out.println(hs.add("one"));
System.out.println(hs.add("two"));
System.out.println(hs.add("one"));
System.out.println(hs.add("three"));
System.out.println(hs.add("four"));
System.out.println(hs.add("five"));
System.out.println(hs);
}
}

O TreeSet é uma implementação da interface Set que usa uma árvore. Esta classe assegura que
o conjunto será organizado em uma ordem ascendente. Observe como a classe TreeSet foi usada
no seguinte código fonte.

import java.util.*;

class TreeSetDemo {
public static void main(String args[]) {
TreeSet ts = new TreeSet();
ts.add("one");
ts.add("two");
ts.add("three");
ts.add("four");
System.out.println(ts);
}
}

Figura 7: Exemplo de um TreeSet

Introdução à Programação II 18
Módulo 2
Introdução à Programação II

Lição 4
Passeio pelo pacote java.lang

Versão 1.0 - Mar/2007


JEDITM

1. Objetivos
Java possui muitas classes úteis para serem utilizadas. Nesta lição iremos explorá-las.

Ao final desta lição, o estudante será capaz de:

• Entender e utilizar as seguintes classes disponíveis:


• Classe Math
• Classe String
• Classe StringBuffer
• Classes Wrapper
• Classe Process
• Classe System

Introdução à Programação II 4
JEDITM

2. Classe Math
Java possui constantes pré-definidas e métodos para executar diferentes operações matemáticas,
como, por exemplo, funções trigonométricas e logarítmicas. Como estes métodos são todos
static, podemos utilizá-los sem a necessidade de construir um objeto da classe Math. Pode-se
obter uma lista completa destas constantes e métodos na documentação da API Java. Aqui estão
descritos alguns dos métodos mais utilizados:

Métodos da classe Math


public static double abs(double a)
Retorna o valor positivo do argumento a passado para o método. É um método
overloaded. Pode receber como argumento um float, um integer ou um long integer, e
nestes casos, o tipo de retorno será float, integer ou long integer, respectivamente.
public static double random()
Retorna um valor positivo randômico maior ou igual a 0.0 mas menor que 1.0.
public static double max(double a, double b)
Retorna o maior valor entre dois valores, a e b, do tipo double. É um método
overloaded. Pode receber como argumento um float, integer ou long integer, e nestes
casos, o tipo de retorno será float, integer ou um long integer, respectivamente.
public static double min(double a, double b)
Retorna o menor entre dois valores a e b, do tipo double. É um método overloaded.
Pode receber também valores dos tipos float, integer ou long integer como
argumentos, e nestes casos, o tipo de retorno será serão float, integer ou long
integer, respectivamente.
public static double ceil(double a)
Retorna o menor inteiro maior ou igual ao argumento a passado para o método.
public static double floor(double a)
Retorna o maior inteiro menor ou igual ao argumento a passado para o método.
public static double exp(double a)
Retorna o número de Euler "e" elevado à potência informada no argumento a passado
para o método.
public static double log(double a)
Retorna o logarítmico natural (base e) de a, o argumento do tipo double informado.
public static double pow(double a, double b)
Retorna o valor do tipo double de a elevado à potência b, do tipo double. a(base) e
b(potência) são os argumentos para este método.
public static long round(double a)
Retorna o valor do tipo long mais próximo do argumento a, do tipo double, informado.
É um método overloaded. Também pode receber um argumento do tipo float e neste
caso, retorna o valor do tipo int mais próximo.
public static double sqrt(double a)
Retorna a raiz quadrada do argumento a informado.
public static double sin(double a)
Retorna o seno trigonométrico de um dado ângulo a, argumento deste método.
public static double toDegrees(double angrad)
Retorna o valor aproximado em graus, equivalente ao valor em radianos passado no
argumento.
public static double toRadians(double angdeg)
Retorna o valor aproximado em radianos, equivalente ao valor em graus passado no
argumento.
Tabela 1: Alguns métodos da classe Math

A seguinte classe demonstra como estes métodos são usados:

class MathDemo {
public static void main(String args[]) {
System.out.println("absolute value of -5: " +
Math.abs(-5));
System.out.println("absolute value of 5: " +

Introdução à Programação II 5
JEDITM

Math.abs(-5));
System.out.println("random number(max value is 10): " +
Math.random()*10);
System.out.println("max of 3.5 and 1.2: " +
Math.max(3.5, 1.2));
System.out.println("min of 3.5 and 1.2: " +
Math.min(3.5, 1.2));
System.out.println("ceiling of 3.5: " + Math.ceil(3.5));
System.out.println("floor of 3.5: " + Math.floor(3.5));
System.out.println("e raised to 1: " + Math.exp(1));
System.out.println("log 10: " + Math.log(10));
System.out.println("10 raised to 3: " + Math.pow(10,3));
System.out.println("rounded off value of pi: " +
Math.round(Math.PI));
System.out.println("square root of 5 = " + Math.sqrt(5));
System.out.println("10 radian = " + Math.toDegrees(10) +
" degrees");
System.out.println("sin(90): " +
Math.sin(Math.toRadians(90)));
}
}

Esta é a saída desta classe. Sinta-se livre para experimentar com novos argumentos.

absolute value of -5: 5


absolute value of 5: 5
random number(max value is 10): 4.0855332335477605
max of 3.5 and 1.2: 3.5
min of 3.5 and 1.2: 1.2
ceiling of 3.5: 4.0
floor of 3.5: 3.0
e raised to 1: 2.7182818284590455
log 10: 2.302585092994046
10 raised to 3: 1000.0
rounded off value of pi: 3
square root of 5 = 2.23606797749979
10 radian = 572.9577951308232 degrees
sin(90): 1.0

Introdução à Programação II 6
JEDITM

3. Classes String e StringBuffer


3.1. Classe String

A Classe String que encontramos no Java SDK representa combinações de caracteres literais.
Diferente de outras linguagens de programação como C ou C++, strings podem ser
representadas utilizando-se um array de caracteres ou simplesmente a Classe String. Tenha em
mente que um objeto String é diferente de um array de caracteres.

3.2. Construtores de String

A Classe String possui 12 construtores com as seguintes assinaturas:

public String(byte [] bytes)


public String(byte [] ascii, int hibyte)
public String(byte [] bytes, int offset, int length)
public String(byte [] ascii, int hibyte, int offset, int length)
public String(byte [] byteslength, String charsetName)
public String(byte [] bytes, String charsetName)
public String(char [] value)
public String(char [] value, int offset, int count)
public String(int [] codePoints, int offset, int count)
public String(String original)
public String(StringBuffer buffer)
public String(StringBuilder builder)

Para conhecermos alguns destes construtores, considere a classe abaixo:

class StringConstructorsDemo {
public static void main(String args[]) {
String s1 = new String(); // cria uma String vazia
char chars[] = { 'h', 'e', 'l', 'l', 'o'};
String s2 = new String(chars); // s2 = "hello";
byte bytes[] = { 'w', 'o', 'r', 'l', 'd' };
String s3 = new String(bytes); // s3 = "world"
String s4 = new String(chars, 1, 3);
String s5 = new String(s2);
String s6 = s2;
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(s4);
System.out.println(s5);
System.out.println(s6);
}
}

A execução desta classe mostrará o seguinte resultado:

hello
world
ell
hello
hello

Introdução à Programação II 7
JEDITM

3.3. Métodos da Classe String


A seguir, uma lista de alguns métodos de String.

Métodos da classe String


public char charAt(int index)
Retorna o caracter localizado na posição especificada pelo argumento index, que indica
a posição do caracter no array de caracteres representado.
public int compareTo(String anotherString)
Compara uma string com outra string especificada no argumento. Retorna um valor
negativo se a string possuir um valor léxico menor que a string passada como
argumento, 0 se ambas as strings tiverem o mesmo valor léxico e um valor positivo se
a string tiver um valor léxico superior ao da string passada como argumento do
método.
public int compareToIgnoreCase(String str)
Funciona como o método compareTo ignorando o padrão case sensitive de Java, isto é,
maiúsculas e minúsculas são indiferentes, apresentando o mesmo valor léxico.
public boolean equals(Object anObject)
Retorna verdadeiro se a string possuir a mesma seqüência de caracteres do argumento
Object passado para este método, argumento este que deve ser um objeto do tipo
String. De outra maneira, se for passado um argumento que não seja do tipo String ou
se não tiver a mesma sequência de símbolos da string, o método irá retornar false.
public boolean equalsIgnoreCase(String anotherString)
Funciona como o método equals ignorando o padrão case sensitive de Java, isto é,
maiúsculas e minúsculas são indiferentes, apresentando o mesmo valor léxico.
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
Obtém os caracteres do array de caracteres da string compreendidos no intervalo
definido pelos argumentos srcBegin (na posição do primeiro caracter no array) e srcEnd
(na posição do último caracter no array) copiando estes caracteres para o array dst
iniciando na posição dstBegin.
public int length()
Retorna o comprimento da string.
public String replace(char oldChar, char newChar)
Retorna a string substituindo todas as ocorrências de oldChar nesta string por newChar.
public String substring(int beginIndex, int endIndex)
Retorna a substring da string iniciando na posição especificada no argumento
beginIndex até a posição especificada no argumento endIndex.
public char[] toCharArray()
Retorna o array de caracteres da string.
public String trim()
Retorna a string suprimindo todos os seus espaços em branco.
public static String valueOf(-)
Este método recebe um argumento de tipo simples como boolean, integer ou character,
ou ainda um Object e retorna a String equivalente ao argumento passado para o
método.
Tabela 2: Alguns métodos da classe String

Introdução à Programação II 8
JEDITM

Observe como estes métodos são utilizados na seguinte classe:

class StringDemo {
public static void main(String args[]) {
String name = "Jonathan";
System.out.println("name: " + name);
System.out.println("3rd character of name: " + name.charAt(2));
System.out.println("Jonathan compared to Solomon: " +
name.compareTo("Solomon"));
System.out.println("Solomon compared to Jonathan: " +
"Solomon".compareTo("Jonathan"));
System.out.println("Jonathan compared to jonathan: " +
name.compareTo("jonathan"));
System.out.println("Jonathan compared to jonathan (ignore " +
"case): " + name.compareToIgnoreCase("jonathan"));
System.out.println("Is Jonathan equal to Jonathan? " +
name.equals("Jonathan"));
System.out.println("Is Jonathan equal to jonathan? " +
name.equals("jonathan"));
System.out.println("Is Jonathan equal to jonathan (ignore " +
"case)? " + name.equalsIgnoreCase("jonathan"));
char charArr[] = "Hi XX".toCharArray();
"Jonathan".getChars(0, 2, charArr, 3);
System.out.print("content of charArr after getChars method: ");
System.out.println(charArr);
System.out.println("Length of name: " + name.length());
System.out.println("Replace a's with e's in name: " +
name.replace('a', 'e'));
System.out.println("A substring of name: " +
name.substring(0, 2));
System.out.println("Trim \" a b c d e f \": \"" +
" a b c d e f ".trim() + "\"");
System.out.println("String representation of boolean " +
"expression 10>10: " + String.valueOf(10>10));
System.out.println("String representation of boolean " +
"expression 10<10: " + (10<10));
System.out.println("name: " + name);
}
}

A execução desta classe mostrará o seguinte resultado:

name: Jonathan
3rd character of name: n
Jonathan compared to Solomon: -9
Solomon compared to Jonathan: 9
Jonathan compared to jonathan: -32
Jonathan compared to jonathan (ignore case): 0
Is Jonathan equal to Jonathan? true
Is Jonathan equal to jonathan? false
Is Jonathan equal to jonathan (ignore case)? true
content of charArr after getChars method: Hi Jo
Length of name: 8
Replace a's with e's in name: Jonethen
A substring of name: Jo
Trim " a b c d e f ": "a b c d e f"
String representation of boolean expression 10>10: false
String representation of boolean expression 10<10: false
name: Jonathan

Introdução à Programação II 9
JEDITM

3.4. Classe StringBuffer


Uma vez que um objeto do tipo String foi criado, não pode mais ser modificado. Um objeto
StringBuffer é similar a um objeto String, exceto pelo fato que o objeto StringBuffer é mutável,
ou seja, pode ser modificado. Reforçando: um objeto String é imutável, objetos StringBuffer são
mutáveis. Seus comprimentos e conteúdos podem ser modificados por meio da chamada de
alguns métodos.

Aqui estão alguns dos métodos da Classe StringBuffer. Para maiores informações consulte a
documentação da API Java.

Métodos da classe StringBuffer


public int capacity()
Retorna a capacidade atual do objeto StringBuffer.
public StringBuffer append(-)
Anexa a representação em string do argumento passado para o método ao objeto
StringBuffer. O argumento passado para este método pode ser de um dos seguintes
tipos: boolean, char, char [], double, float, int, long, Object, String and StringBuffer.
Possui outras versões overloaded.
public char charAt(int index)
Retorna o caracter localizado na posição especificada no argumento index.
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
Obtém os caracteres do objeto compreendidos no intervalo definido entre a posição
definida pelo argumento srcBegin e a posição definida pelo argumento srcEnd e copia
estes caracteres para o array definido pelo argumento dst iniciando na posição
dstBegin.
public StringBuffer delete(int start, int end)
Exclui os caracteres dentro do intervalo especificado.
public StringBuffer insert(int offset, -)
Insere a representação em string do segundo argumento na posição especificada pelo
argumento offset. É um método overloaded. São tipos possíveis para o segundo
argumento: boolean, char, char [], double, float, int, long, Object and String. Ainda
possui outras versões overloaded.
public int length()
Retorna o número de caracteres no objeto StringBuffer.
public StringBuffer replace(int start, int end, String str)
Substitui os caracteres do objeto StringBuffer compeendidos no intervalo definido pelos
dois primeiros argumentos (start e end) pelos caracteres do terceiro argumento (str).
public String substring(int start, int end)
Retorna a substring do objeto iniciando na posição definida pelo argumento start e
terminando na posição definida pelo argumento end.
public String toString()
Converte o objeto StringBuffer para String.
Tabela 3: Alguns métodos da classe StringBuffer

A seguinte classe demonstra o uso destes métodos:

class StringBufferDemo {
public static void main(String args[]) {

Introdução à Programação II 10
JEDITM

StringBuffer sb = new StringBuffer("Jonathan");


System.out.println("sb = " + sb);
System.out.println("capacity of sb: " + sb.capacity());
System.out.println("append \'O\' to sb: " +
sb.append("O"));
System.out.println("sb = " + sb);
System.out.println("3rd character of sb: " +
sb.charAt(2));
char charArr[] = "Hi XX".toCharArray();
sb.getChars(0, 2, charArr, 3);
System.out.print("getChars method: ");
System.out.println(charArr);
System.out.println("Insert \'jo\' at the 3rd cell: " +
sb.insert(2, "jo"));
System.out.println("Delete \'jo\' at the 3rd cell: " +
sb.delete(2,4));
System.out.println("length of sb: " + sb.length());
System.out.println("replace: " +
sb.replace(3, 9, " Ong"));
System.out.println("substring (1st three characters): " +
sb.substring(0, 3));
System.out.println("implicit toString(): " + sb);
}
}

A execução desta classe mostrará o seguinte resultado:

sb = Jonathan
capacity of sb: 24
append 'O' to sb: JonathanO
sb = JonathanO
3rd character of sb: n
getChars method: Hi Jo
Insert 'jo' at the 3rd cell: JojonathanO
Delete 'jo' at the 3rd cell: JonathanO
length of sb: 9
replace: Jon Ong
substring (1st three characters): Jon
implicit toString(): Jon Ong

Sinta-se à vontade para experimentar esta classe modificando os argumentos, a melhor forma de
aprender é através da prática.

3.5. Mutabilidade

Falamos de mutabilidade de objetos e foi dito que um objeto da classe String não pode ter o seu
valor modificado, entretanto observaremos as seguintes instruções:

String objString = new String("Hello");


objString = objString.concat(" World!!!");
System.out.println(objString);

Teremos como resultado o texto Hello World!!!, então significa que o objeto da classe String foi
modificado certo? Errado, ocorreu na segunda instrução a destruição e a recriação do objeto.
Analisaremos a seguinte classe:

class MutabilityDemo {
public static void main(String args[]) {
String objString = new String("Hello");
System.out.println(objString + " : " + objString.hashCode());

Introdução à Programação II 11
JEDITM

objString = objString.concat(" World!!");


System.out.println(objString + " : " + objString.hashCode());

StringBuffer objStringBuffer = new StringBuffer("Hello");


System.out.println(objStringBuffer + " : " +
objStringBuffer.hashCode());
objStringBuffer = objStringBuffer.append(" World!!");
System.out.println(objStringBuffer + " : " +
objStringBuffer.hashCode());
}
}

E teremos como resultado da execução desta:

Hello : 69609650
Hello World!! : 22678948
Hello : 17523401
Hello World!! : 17523401

O método hashCode() gera automaticamente um OID (ObjectID) único para cada objeto criado,
observe que no caso do objeto da classe String este número mudou, ou seja, foi criado um novo
objeto, e no caso do objeto da classe StringBuffer este número permanece o mesmo,
demonstrando assim a imutabilidade deste.

Introdução à Programação II 12
JEDITM

4. Classes Wrapper
Obviamente, os tipos primitivos como int, char e long não são objetos. Desta forma, variáveis
destes tipos não podem acessar métodos da classe Object. Somente objetos reais, que são
declarados para serem referenciados como tipos de dados, podem acessar métodos da classe
Object. Todavia, existem casos em que você precisará de uma representação em objeto de
variáveis de tipos primitivos para usar métodos internos de Java. Por exemplo, você pode querer
adicionar variáveis de tipo primitivo em uma Collection de objetos. É aqui que a classe wrapper
entra. Classes wrapper são, simplesmente, representações em objetos de variáveis que não são
objetos, como as de tipos primitivos. Aqui está uma lista de classes wrapper:

Tipos Primitivos de Dados Classes Wrapper Correspondentes


boolean Boolean
char Character
byte Byte
short Short
int Integer
long Long
float Float
double Double
Tabela 4: Tipos de dados primitivos e suas classes wrapper correspondentes

Os nomes das diferentes classes wrapper são fáceis de lembrar, porque são muito similares aos
tipos de dados primitivos que representam. Note também que as classes wrapper iniciam com
letra maiúscula, comparando-as com os tipos primitivos.

Aqui está um exemplo do uso da classe wrapper para o tipo primitivo boolean.

class BooleanWrapperDemo {
public static void main(String args[]) {
boolean booleanVar = 1>2;
Boolean booleanObj = new Boolean("TRue");
Boolean booleanObj2 = new Boolean(booleanVar);
System.out.println("booleanVar = " + booleanVar);
System.out.println("booleanObj = " + booleanObj);
System.out.println("booleanObj2 = " + booleanObj2);
System.out.println("compare 2 wrapper objects: " +
booleanObj.equals(booleanObj2));
booleanVar = booleanObj.booleanValue();
System.out.println("booleanVar = " + booleanVar);
}
}

A execução desta classe mostrará o seguinte resultado:

booleanVar = false
booleanObj = true
booleanObj2 = false
compare 2 wrapper objects: false
booleanVar = true

Introdução à Programação II 13
JEDITM

5. Classes Process e Runtime


5.1. Classe Process
A classe Process define métodos para manipulação de processos que podem, por exemplo,
terminar a execução de um processo, iniciar a execução de processos e verificar o status de
processos. Esta classe representa as instruções quando são executadas. Aqui estão alguns
métodos desta classe:

Métodos da classe Process


public abstract void destroy()
Finaliza os processos em execução.
public abstract int waitFor() throws InterruptedException
Não sai até que o processo termine.
Tabela 5: Alguns métodos da classe Process

5.2. Classe Runtime


Enquanto a classe Process representa os processos em execução, a classe Runtime representa o
ambiente de execução. Dois métodos importantes desta classe são: getRuntime e exec.

Métodos da classe Runtime


public static Runtime getRuntime()
Retorna o ambiente de execução associado a aplicação Java atual.
public Process exec(String command) throws IOException
Executa o comando passado como argumento em command. Permite-lhe executar
novos processos.
Tabela 6: Alguns métodos da classe RunTime

5.3. Abrindo o Editor de Registro


Esta classe abre o editor de registro sem que seja necessário, explicitamente, digitar o comando
na linha de comando:

class RuntimeDemo {
public static void main(String args[]) {
Runtime rt = Runtime.getRuntime();
Process proc;
try {
proc = rt.exec("regedit");
proc.waitFor();
} catch (Exception e) {
System.out.println("regedit is an unknown command.");
}
}
}

A execução desta classe mostrará o seguinte resultado:

Introdução à Programação II 14
JEDITM

Figura 1: O editor de registro aberto

Introdução à Programação II 15
JEDITM

6. Classe System
A classe System oferece muitos atributos e métodos úteis como a entrada padrão (input), a saída
padrão (output) e um método utilitário para copiar rapidamente partes de um array. Aqui estão
alguns métodos interessantes desta classe. Note que todos os métodos dessa classe são static.

Métodos da classe System


public static void arraycopy(Object src, int srcPos, Object dest, int
destPos, int length)
Copia os ítens do array src, passado como argumento para o método, especificados no
argumento length iniciando na posição especificada no argumento srcPos para o array
dest, terminando na posição especificada no argumento destPos. É mais rápido do que
utilizar um algoritmo próprio para realizar a cópia.
public static long currentTimeMillis()
Retorna a diferença entre o tempo atual (data/hora) e 1º de Janeiro de 1970 (UTC). O
valor de retorno se dá em milissegundos.
public static void exit(int status)
Termina a execução da Máquina Virtual Java (JVM) atual. Um valor diferente de zero
para o status, por convenção, indica uma saída anormal.
public static void gc()
Executa o garbage collector, que irá liberar espaços em memória que não estão mais
sendo utilizados.
public static void setIn(InputStream in)
Troca o stream associado a System.in, que por padrão, refere-se ao teclado.
public static void setOut(PrintStream out)
Troca o stream associado a System.out, que por padrão, refere-se ao console (tela).

Tabela 7: Alguns metodos da classe System

Aqui está uma demonstração do uso de alguns destes métodos:

import java.io.*;

class SystemDemo {
public static void main(String args[]) throws IOException {
long startTime, endTime;
System.setOut(new PrintStream("C:/tempOut.txt"));
int arr1[] = new int[5000000];
int arr2[] = new int[5000000];
for (int i = 0; i < arr1.length; i++) {
arr1[i] = i + 1;
}
startTime = System.currentTimeMillis();
for (int i = 0; i < arr1.length; i++) {
arr2[i] = arr1[i];
}
endTime = System.currentTimeMillis();
System.out.println("Manual: " + (endTime-startTime) + " ms.");
startTime = System.currentTimeMillis();
System.arraycopy(arr1, 0, arr2, 0, arr1.length);
endTime = System.currentTimeMillis();
System.out.println("Automatic: " + (endTime-startTime) + " ms.");
}
}

Introdução à Programação II 16
JEDITM

A execução desta classe pode variar. O resultado contido no arquivo em C:\tempOut.txt, pode ser
por exemplo:

Manual: 47 ms.
Automatic: 31 ms.

Introdução à Programação II 17
Módulo 2
Introdução à Programação II

Lição 5
Aplicações Textuais

Versão 1.0 - Mar/2007


JEDITM

1. Objetivos
Nesta lição, será mostrada uma revisão sobre como utilizar os argumentos de linha de comando.
Além disso, serão mostradas mais informações sobre como utilizar fluxos de dados para obter
entrada do usuário durante a execução da sua aplicação para manipular arquivos.

Ao final desta lição, o estudante será capaz de:

• Obter entrada através da linha de comando


• Explicar como manipular propriedades do sistema
• Ler através da entrada padrão
• Ler e escrever em arquivos

Introdução à Programação II 4
JEDITM

2. Argumentos de Linha de Comando e Propriedades


do Sistema
Como foi visto no módulo anterior, Java permite ao usuário enviar dados na linha de comando
para a classe que está sendo executada. Por exemplo, passar os argumentos 1 e 2 para uma
classe nomeada como Calculate, pode-se digitar a seguinte linha de comando:

java Calculate 1 2

Neste exemplo, o valor 1 é armazenado na posição args[0] do argumento args, enquanto que o
valor 2 é armazenado na posição args[1] do argumento args. Deste modo, a finalidade de
declarar "String args[]" como um argumento no método main fica clara.

Estes são os passos para passar argumentos na linha de comando no NetBeans:

1. Procurar o nome do projeto no painel dos projetos à esquerda


2. Clicar com o botão direito do mouse sobre o nome ou o ícone do projeto
3. Selecionar a opção Properties
4. Clicar em Run no painel de Categories à esquerda
5. Entrar os argumentos separados por espaço no campo texto do item Arguments:
6. Clicar no botão OK
7. Compilar e executar a classe.

Para compreender mais facilmente estas etapas, observe as imagens a seguir.

Figura 1: Passando Argumentos na Linha de Comando com o NetBeans – Passos 1 e 2

Introdução à Programação II 5
JEDITM

Figura 2: Passando Argumentos na Linha de Comando com o NetBeans - Passo 3

Figura 3: Passando Argumentos na Linha de Comando com o NetBeans – Passo 4

Além de passar argumentos ao método main, também é possível manipular propriedades do


sistema a partir da linha de comando.

Propriedades de sistema são bastante semelhantes às variáveis de ambiente. Porém, não são

Introdução à Programação II 6
JEDITM

dependentes de plataforma. Uma propriedade é simplesmente um mapeamento entre o nome da


propriedade e o seu valor correspondente. Isto é representado em Java com a classe Properties.
A classe System provê alguns métodos para determinar as propriedades correntes do sistema, o
método getProperties retorna um objeto do tipo Properties. O método getProperty possui duas
formas:

public static String getProperty(String key)


Esta versão retorna o valor de uma propriedade do sistema, indicada pela chave
especificada. Retorna nulo se não houver nenhuma propriedade com a chave
especificada.
public static String getProperty(String key, String def)
Esta versão retorna também o valor de uma propriedade do sistema, indicada pela
chave especificada. Retorna def, valor padrão, se não houver nenhuma propriedade
com a chave especificada.
Tabela 1: método getProperty() da classe System

Não enfatizaremos os detalhes das propriedades do sistema. Iremos manipular diretamente as


propriedades do sistema.

É possível utilizar a opção -D, como argumento da linha de comando Java, para incluir uma nova
propriedade.

java -D<name>=value

Por exemplo, na propriedade de sistema user.home iremos inserir o valor philippines, vamos
digitar o seguinte comando:

java -Duser.home=philippines

Para exibir a lista de propriedades do sistema disponíveis e seus valores correspondentes, deve-
se utilizar o método getProperties, como segue:

System.getProperties().list(System.out);

Aqui temos uma amostra da lista de propriedades do sistema:

-- listing properties --
java.runtime.name=Java(TM) 2 Runtime Environment, Stand...
sun.boot.library.path=C:\Program Files\Java\jdk1.5.0_06\jre...
java.vm.version=1.5.0_06-b05
java.vm.vendor=Sun Microsystems Inc.
java.vendor.url=http://java.sun.com/
path.separator=;
java.vm.name=Java HotSpot(TM) Client VM
file.encoding.pkg=sun.io
user.country=US
sun.os.patch.level=Service Pack 2
java.vm.specification.name=Java Virtual Machine Specification
user.dir=C:\Documents and Settings\becca\Neste...
java.runtime.version=1.5.0_06-b05
java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment
java.endorsed.dirs=C:\Program Files\Java\jdk1.5.0_06\jre...
os.arch=x86
java.io.tmpdir=C:\DOCUME~1\becca\LOCALS~1\Temp\
line.separator=
java.vm.specification.vendor=Sun Microsystems Inc.
user.variant=

Introdução à Programação II 7
JEDITM

os.name=Windows XP
sun.jnu.encoding=Cp1252
java.library.path=C:\Program Files\Java\jdk1.5.0_06\jre...
java.specification.name=Java Platform API Specification
java.class.version=49.0
sun.management.compiler=HotSpot Client Compiler
os.version=5.1
user.home=C:\Documents and Settings\becca
user.timezone=
java.awt.printerjob=sun.awt.windows.WPrinterJob
file.encoding=Cp1252
java.specification.version=1.5
user.name=becca
java.class.path=C:\Documents and Settings\becca\Neste...
java.vm.specification.version=1.0
sun.arch.data.model=32
java.home=C:\Program Files\Java\jdk1.5.0_06\jre
java.specification.vendor=Sun Microsystems Inc.
user.language=en
awt.toolkit=sun.awt.windows.WToolkit
java.vm.info=mixed mode, sharing
java.version=1.5.0_06
java.ext.dirs=C:\Program Files\Java\jdk1.5.0_06\jre...
sun.boot.class.path=C:\Program Files\Java\jdk1.5.0_06\jre...
java.vendor=Sun Microsystems Inc.
file.separator=\
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
sun.desktop=windows
sun.cpu.isalist=

Introdução à Programação II 8
JEDITM

3. Lendo da Entrada Padrão


Ao invés de obter uma entrada do usuário através da linha de comando, a maioria dos usuários
prefere entrar com os dados quando requisitados pela classe enquanto ela estiver em execução.
Um modo de realizar isto é com o uso dos fluxos. Um fluxo é uma abstração de um arquivo ou de
um dispositivo que permite ler ou escrever uma série de itens. Eles são conectados com
dispositivos físicos, tais como: teclados, consoles e arquivos. Há dois tipos gerais de fluxo de
dados: fluxo de bytes e fluxo de caracteres. Os fluxos de bytes são para os dados binários,
enquanto os fluxos de caracteres são para os caracteres Unicode. System.in e System.out são
dois exemplos de objetos de fluxos de bytes pré-definidos em Java. O primeiro, por padrão,
refere-se ao teclado e o último, ao monitor.

Para ler caracteres do teclado, utilize o System.in, que é um fluxo de bytes traduzido em um
objeto do tipo BufferedReader. A linha seguinte mostra como realizar isto:

BufferedReader br = new BufferedReader(


new InputStreamReader(System.in));

O método read do objeto do tipo BufferedReader é utilizado para ler do dispositivo de entrada.

ch = (int)br.read(); // método read retorna um inteiro

Vejamos esta classe como exemplo:

import java.io.*;

class FavoriteCharacter {
public static void main(String args[]) throws IOException {
System.out.println("Hi, what's your favorite character?");
char favChar;
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
favChar = (char) br.read();
System.out.println(favChar + " is a good choice!");
}
}

Executando esta classe e informando o caractere "a" como entrada, obteremos a seguinte saída:

Hi, what's your favorite character?


a
a is a good choice!

Para ler uma linha inteira, em vez de um caractere de cada vez, é possível utilizar o método
readLine.

str = br.readLine();

Vejamos uma classe similar ao exemplo anterior. Esta classe lê uma linha inteira em vez de um
único caractere.

import java.io.*;

class GreetUser {
public static void main(String args[]) throws IOException {
System.out.println("Hi, what's your name?");
String name;
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));

Introdução à Programação II 9
JEDITM

name = br.readLine();
System.out.println("Nice to meet you, " + name + "! :)");
}
}

A saída esperada da classe GreetUser, quando o usuário entrar com a palavra Rebecca é:

Hi, what's your name?


Rebecca
Nice to meet you, Rebecca! :)

Ao utilizar fluxos, não esqueça de importar o pacote java.io como mostrado:

import java.io.*;

Ao ler fluxos é possível que ocorram exceções. Não se deve esquecer de tratar estas exceções
usando o bloco try-catch ou de indicá-las na cláusula throws do método.

Introdução à Programação II 10
JEDITM

4. Manipulação de Arquivo
Em alguns casos, as entradas de dados são armazenadas nos arquivos. Além disso, há também
situações na qual queremos armazenar a saída de uma determinada classe para um arquivo.

Em um sistema informatizado de matrícula, os dados do estudante que podem ser utilizados


como uma entrada para o sistema são, provavelmente, armazenados em um arquivo. Então, uma
possível saída do sistema é a informação sobre os assuntos registrados pelos estudantes. Outra
vez, a saída, neste caso, pode ser armazenada em um arquivo. Como visto nesta aplicação, há
necessidade de ler e escrever em um arquivo. Aprenderemos sobre entrada e saída de arquivo
ainda nesta seção.

4.1. Lendo um Arquivo


Para ler um arquivo, pode-se utilizar a classe FileInputStream. Este é um dos construtores desta
classe:

FileInputStream(String filename)

O construtor cria uma conexão para um arquivo real, cujo o nome será especificado como um
argumento. Uma exceção do tipo FileNotFoundException é lançada quando o arquivo não existe
ou não pode ser aberto para leitura.

Após ter criado um fluxo de entrada, é possível utilizá-lo para ler um arquivo associado através
do método read que retorna um valor do tipo inteiro e o valor -1 quando o fim do arquivo for
encontrado.

Aqui está um exemplo:

import java.io.*;

class ReadFile {
public static void main(String args[]) throws IOException {
System.out.println(
"What is the name of the file to read from?");
String filename;
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in));
filename = br.readLine();
System.out.println(
"Now reading from " + filename + "...");
FileInputStream fis = null;
try {
fis = new FileInputStream(filename);
} catch (FileNotFoundException ex) {
System.out.println("File not found.");
}
char data;
int temp;
do {
temp = fis.read();
data = (char) temp;
if (temp != -1)
System.out.print(data);
} while (temp != -1);
System.out.println("Problem in reading from the file.");
}
}

Introdução à Programação II 11
JEDITM

Assumindo que temp.txt existe e seja o arquivo de texto, está é uma possível saída desta classe:

What is the name of the file to read from?


temp.txt
Now reading from temp.txt...
temporary file

4.2. Escrevendo em um Arquivo


Para escrever em um arquivo, é possível utilizar a classe FileOutputStream. Este é um dos
construtores desta classe:

FileOutputStream(String filename)

O construtor vincula um fluxo de saída a um arquivo real para escrita. Uma exceção do tipo
FileNotFoundException é lançada quando o arquivo não puder ser aberto para escrita.

Uma vez que o fluxo de saída é criado, pode-se utilizá-lo para escrever no arquivo vinculado
através do método write, que possui a seguinte assinatura:

void write(int b)

O argumento b refere-se ao dado a ser escrito para o arquivo real, associado ao fluxo de saída.

A classe seguinte demonstra a escrita em um arquivo:

import java.io.*;

class WriteFile {
public static void main(String args[]) throws IOException {
System.out.println(
"What is the name of the file to be written to?");
String filename;
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in));
filename = br.readLine();
System.out.println(
"Enter data to write to " + filename + "...");
System.out.println("Type q$ to end.");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(filename);
} catch (FileNotFoundException ex) {
System.out.println("File cannot be opened for writing.");
}
try {
boolean done = false;
int data;
do {
data = br.read();
if ((char)data == 'q') {
data = br.read();
if ((char)data == '$') {
done = true;
} else {
fos.write('q');
fos.write(data);
}
} else {

Introdução à Programação II 12
JEDITM

fos.write(data);
}
} while (!done);
} catch (IOException ex) {
System.out.println("Problem in reading from the file.");
}
}
}

Exemplo de execução da classe WriteFile:

What is the name of the file to be written to?


temp.txt
Enter data to write to temp.txt...
Type q$ to end.
what a wonderful world
1, 2, step
q$

O arquivo temp.txt deverá conter os seguintes dados:

what a wonderful world


1, 2, step

Introdução à Programação II 13
Módulo 2
Introdução à Programação II

Lição 6
Algoritmos de Ordenação

Versão 1.0 - Mar/2007


JEDITM

1. Objetivos
Ordenação tem a tarefa de organizar elementos em uma ordem particular, e isto é implementado
em uma variedade de aplicações. Considerando uma aplicação bancária, a qual exibe a lista de
contas de clientes ativos, por exemplo. A maioria dos usuários deste sistema provavelmente
preferem ter a lista em uma ordem crescente, por conveniência.

Nesta lição veremos vários algoritmos de ordenação foram inventados porque essa tarefa é
fundamental e freqüentemente utilizada. Por estas razões, examinar os algoritmos existentes
será muito benéfico.

Ao final desta lição, o estudante será capaz de:

• Explicar os algoritmos utilizados em ordenação por inserção, ordenação por seleção,


Merge Sort e Quick Sort
• Implementar seu próprio algoritmo utilizando essas técnicas

Introdução à Programação II 4
JEDITM

2. Ordenação por inserção


Um dos mais simples algoritmos desenvolvidos é o de ordenação por inserção. A idéia de
algoritmo é absolutamente intuitiva. A seguinte sinopse descreve como a ordenação por inserção
funciona para ordenar uma série de cartas. Desejamos ordenar uma série de cartas do menor até
o maior da categoria. Todas as cartas estão inicialmente colocadas em uma tabela e a
chamaremos de 1ª tabela, seguindo estritamente a ordem da esquerda para a direita, do topo ao
fundo. Nós temos outra tabela, chamada de 2ª tabela, onde as cartas serão posicionadas. Escolha
a primeira carta disponível da esquerda na 1ª tabela, e que esteja no topo, e coloque esta carta
no local adequado (ou seja, ordenado) posicionando na 2ª tabela. Escolha a próxima carta
disponível da 1ª tabela e compare-a com as cartas da 2ª tabela e coloque-a na posição
adequada. O processo continua até que todas as cartas sejam colocadas na 2ª tabela.

O algoritmo de ordenação por inserção basicamente divide os elementos a serem ordenados em


dois grupos: os não ordenados (semelhante à 1ª tabela) e os ordenados (semelhante à 2ª
tabela). O primeiro elemento disponível é selecionado dentre os não ordenados do array e este é
corretamente posicionado na parte ordenada do array. Esse passo é repetido até que não hajam
mais elementos à esquerda, na parte não ordenada do array.

2.1. O algoritmo

public void insertionSort(Object array[], int startIdx, int endIdx) {


for (int i = startIdx; i < endIdx; i++) {
int k = i;
for (int j = i + 1; j < endIdx; j++) {
if (((Comparable) array[k]).compareTo(array[j])>0) {
k = j;
}
}
swap(array[i], array[k]);
}
}

2.2. Um exemplo

Dados 1º passo 2º passo 3º passo 4º passo


Manga Manga Maçã Laranja Banana
Maçã Maçã Manga Maçã Laranja
Pêssego Pêssego Pêssego Manga Maçã
Laranja Laranja Laranja Pêssego Manga
Banana Banana Banana Banana Pêssego
Figura 1: Exemplo de ordenação por inserção

Introdução à Programação II 5
JEDITM

3. Ordenação por seleção


Ao se criar um primeiro algoritmo de ordenação, provavelmente foi criado algo parecido com o
algoritmo de ordenação por inserção. Como o algoritmo de ordenação por inserção, esse
algoritmo é muito intuitivo e fácil de implementar.

Novamente vamos observar como este algoritmo funciona em uma escala de maço de cartas.
Considere que as cartas serão organizadas em ordem crescente. Inicialmente, as cartas estão
organizadas linearmente na tabela da esquerda para a direita e do topo até embaixo. Confira o
nível de cada carta e escolha a carta com o menor nível. Troque a posição dessa carta com a da
primeira carta, a que está no topo da esquerda. Depois, localize a carta com o menor nível entre
as cartas restantes, excluindo a primeira carta escolhida. Troque novamente a carta selecionada
com a carta na segunda posição. Repita esse mesmo passo até que, da segunda à última posição
na tabela sejam analisadas e possivelmente trocadas por cartas com o menor valor.

A idéia principal por trás do algoritmo de ordenação por seleção é selecionar o elemento com o
menor valor e então trocar o elemento selecionado com o elemento na i posição. O valor de i
inicia com 1 até n, onde n é o número total de elementos menos 1.

3.1. O algoritmo

public void selectionSort(Object array[], int startIdx, int endIdx) {


int min;
for (int i = startIdx; i < endIdx; i++) {
min = i;
for (int j = i + 1; j < endIdx; j++) {
if (((Comparable) array[min]).compareTo(array[j])>0) {
min = j;
}
}
swap(array[min], array[i]);
}
}

3.2. Um exemplo

Dados 1º passo 2º passo 3º passo 4º passo


Maricar Hannah Hannah Hannah Hannah
Vanessa Vanessa Margaux Margaux Margaux
Margaux Margaux Vanessa Maricar Maricar
Hannah Maricar Maricar Vanessa Rowena
Rowena Rowena Rowena Rowena Vanessa
Figura 2: Exemplo de ordenação por seleção

Introdução à Programação II 6
JEDITM

4. Merge Sort
Antes de examinar o algoritmo Merge Sort, vamos primeiramente dar uma rápida olhada no
paradigma do dividir-e-conquistar para que melhor se compreenda o Merge Sort.

4.1. Paradigma do dividir-e-conquistar

Vários algoritmos utilizam a repetição (recursividade) para solucionar um determinado problema.


O problema original é dividido em subproblemas, então as soluções dos subproblemas conduzem
a solução do poblema principal. Esse tipo de algoritmo tipicamente seguem o paradigma do
dividir-e-conquistar.

Em cada nível de recursividade, o paradigma consiste de três passos.

1.Dividir
Dividir o problema principal em subproblemas.

2.Conquistar
Conquistar os subproblemas resolvendo-os através da recursividade. No caso em que os
subproblemas são simples e pequenos o suficiente, resolver de maneira direta.

3.Combinar
Unir as soluções dos subproblemas, direcionando à solução do problema principal.

4.2. Entendendo Merge Sort

Como mencionado anteriormente, Merge Sort utiliza a técnica do dividir-e-conquistar. Dessa


foma, a descrição deste algoritmo é seguida como exemplo depois dos três passos do paradigma
do dividir-e-conquistar. Aqui está como o Merge Sort funciona.

1.Dividir
Dividir a sequência dos elementos dados em duas partes.

2.Conquistar
Conquistar cada parte de modo repetitivo, chamando o método Merge Sort.

3.Combinar
Combinar ou fundir as duas partes recursivamente para apresentar a seqüência ordenada.

A repetição acaba quando o objetivo básico é alcançado. Este é o caso onde a parte a ser
ordenada possui exatamente um elemento. Já que apenas um elemento seja separado para ser
ordenado, essa parte já está organizada na sua própria sequência.

4.3. O algoritmo

void mergeSort(Object array[], int startIdx, int endIdx) {


if (array.length != 1) {
mergeSort(leftArr, startIdx, midIdx);
mergeSort(rightArr, midIdx+1, endIdx);
combine(leftArr, rightArr);
}
}

Introdução à Programação II 7
JEDITM

4.4. Um exemplo

Dados:

7 2 5 6

Dividir o array de dados em dois:

ArrayEsq ArrayDir
7 2 5 6

Dividir o ArrayEsq em dois:

ArrayEsq ArrayDir
7 2

Combinar

2 7

Dividir ArrDir em dois:

ArrayEsq ArrayDir
5 6

Combinar

5 6

Combinar

ArrayEsq e ArrayDir.

2 5 6 7
Figura 3: Exemplo de Merge sort

Introdução à Programação II 8
JEDITM

5. Quick Sort
Quick Sort foi criado por C.A.R. Hoare. Como o Merge Sort, este algoritmo é baseado no
paradigma do dividir-e-conquistar. Mas ao invés de possuir as três fases, ele envolve apenas as
seguintes fases:

1.Dividir
Separação dos arrays em dois subarrays A[p...q-1] e A[q+1...r] onde cada elemento em
A[p...q-1] é menor ou igual a A[q] e cada elemento em A[q+1...r] é maior ou igual a A[q].
A[q] é chamado de eixo. Cálculo de q é parte do processo de separação.

2.Conquistar
Ordenar os subarrays pela recursividade, chamado de método quickSort.

Não existe a fase de "Combinar" pois os subarrays são ordenados localmente.

5.1. O algoritmo

void quickSort(Object array[], int leftIdx, int rightIdx) {


int pivotIdx;
if (rightIdx > leftIdx) {
pivotIdx = partition(array, leftIdx, rightIdx);
quickSort(array, leftIdx, pivotIdx-1);
quickSort(array, pivotIdx+1, rightIdx);
}
}

5.2. Um exemplo

Array dado:

3 1 4 1 5 9 2 6 5 3 5 8

Escolher o primeiro elemento para ser o eixo = 3.

3 1 4 1 5 9 2 6 5 3 5 8

Inicializar a esquerda com o ponteiro no segundo elemento, e a direita com o ponteiro no último
elemento.

Esq. Dir.
3 1 4 1 5 9 2 6 5 3 5 8

Mover o ponteiro da esquerda na direção da direita até ser localizado um valor maior do que o do
eixo. Mover o ponteiro direito na direção esquerda até ser localizado um valor menor do que o
eixo.
Esq. Dir.
3 1 4 1 5 9 2 6 5 3 5 8

Trocar os elementos referidos com os ponteiros esquerdo e direito.

Introdução à Programação II 9
JEDITM

Esq. Dir.
3 1 3 1 5 9 2 6 5 4 5 8

Mover os ponteiros direito e esquerdo novamente.

Esq. Dir.
3 1 3 1 5 9 2 6 5 4 5 8

Trocar os elementos.

Esq. Dir.
3 1 3 1 2 9 5 6 5 4 5 8

Mover os ponteiros esquerdos e direitos novamente.

Dir. Esq.
3 1 3 1 2 9 5 6 5 4 5 8

Observe que os ponteiros da esquerda e direita se cruzaram e o direito < esquerdo. Neste caso,
trocar o eixo pelo valor do ponteiro direito.

pivô
2 1 3 1 3 9 5 6 5 4 5 8

Figura 4: Exemplo de Quick Sort

A caminhada do eixo agora está completa. Ordenação de arrays por recursividade em cada lado,
utilizando o eixo.

Introdução à Programação II 10
Módulo 2
Introdução à Programação II

Lição 7
Abstract Window Toolkit e Swing

Versão 1.0 - Mar/2007


JEDITM

1. Objetivos
Mesmo sem conhecer interface gráfica com o usuário ou GUI (Graphical User Interface) é possível
criar uma grande variedade de diferentes projetos. Entretanto, estas aplicações não teriam
grandes chances de serem agradáveis aos usuários, tão acostumados aos ambientes gráficos
como Windows, Solaris e Linux. Ter um projeto desenvolvido em GUI afeta o uso de sua aplicação
pois resulta em facilidade de uso e melhor experiência para os usuários de seus aplicativos. Java
fornece ferramentas como Abstract Window Toolkit (AWT) e Swing para desenvolver aplicações
GUI interativas.

Ao final desta lição, o estudante será capaz de:

• Explicar similaridades e diferenças entre AWT e Swing


• Diferenciar entre os containers e componentes
• Criar aplicações GUI utilizando AWT
• Criar aplicações GUI utilizando Swing
• Descrever como os gerenciadores de layout, tais como FlowLayout, BorderLayout e
GridLayout, posicionam os componentes GUI
• Criar layouts complexos ao elaborar aplicações GUI

Introdução à Programação II 4
JEDITM

2. AWT (Abstract Window Toolkit) vs. Swing


A JFC (Java Foundation Classes) é uma importante parte de Java SDK. Refere-se a uma coleção
de APIs que simplificam o desenvolvimento de aplicações Java GUI. Consistem basicamente em
cinco APIs incluindo AWT e Swing. As outras três APIs são Java2D, Accessibility, e Drag and Drop.
Todas essas APIs dão suporte aos desenvolvedores na criação e implementação de aplicações
visualmente destacadas.

Ambas AWT e Swing dispõem de componentes GUI que podem ser usadas na criação de
aplicações Java e applets. Aprenderemos sobre applets mais tarde. Diferentemente de alguns
componentes AWT que usam código nativo, Swing é escrito inteiramente usando a linguagem de
programação Java. Em consequência, Swing fornece uma implementação independente de
plataforma que assegura que aplicações desenvolvidas em diferentes plataformas tenham a
mesma aparência. AWT, entretanto, assegura que o look and feel (a aparência) de uma aplicação
executada em duas máquinas diferentes sejam compatíveis. A API Swing é construída sobre um
número de APIs que implementa várias partes da AWT. Como resultado, componentes AWT ainda
podem ser usados com componentes Swing.

Introdução à Programação II 5
JEDITM

3. Componentes GUI AWT

3.1. Fundamental Window Classes


No desenvolvimento de aplicações GUI, os componentes como os botões ou campos de texto são
localizados em containers. Essa é uma lista de importantes classes containers fornecidas pela
AWT.

Classe AWT Descrição


Component Uma classe abstrata para objetos que podem ser exibidos no console
e interagir com o usuário. A raiz de todas as outras classes AWT.
Container Uma subclasse abstrata da classe Component. Um componente que
pode conter outros componentes.
Panel Herda a classe Container. Uma área que pode ser colocada em um
Frame, Dialog ou Window. Superclasse da classe Applet.
Window Também herda a classe Container. Uma janela top-level, que significa
que ela não pode ser contida em nenhum outro objeto. Não tem
bordas ou barra de menu.
Dialog Uma janela contendo a barra de título e o botão de fechar, utilizada
para criar janelas para comunicação com o usuário.
Frame Uma janela completa com um título, barra de menu, borda, e cantos
redimensionáveis. Possui quatro construtores, dois deles possuem as
seguintes assinaturas:
Frame()
Frame(String title)

Tabela 1: Classes Container AWT

Para configurar o tamanho da janela, podemos utilizar o método setSize, do seguinte modo:

void setSize(int width, int height)

Reconfigura o tamanho da janela para o width (largura) e height (altura) fornecidos como
argumentos.

void setSize(Dimension d)

Reconfigura o tamanho da janela para os atributos d.width e d.height baseado em um objeto


instanciado da classe Dimension especificado como argumento.

Por padrão uma janela não é visível a não ser que seja configurada a sua visibilidade para true.
Esta é a sintaxe para o método setVisible:

void setVisible(boolean b)

Ao criar aplicações GUI, o objeto Frame é o mais comumente utilizado. Aqui está um exemplo de
como criar uma aplicação dessas:

import java.awt.*;

public class FrameDemo extends Frame {


public static void main(String args[]) {
FrameDemo sf = new FrameDemo();

Introdução à Programação II 6
JEDITM

sf.setSize(100, 100); //Tente removendo esta linha


sf.setVisible(true); //Tente removendo esta linha
}
}

Este é o resultado esperado pela execução da classe SampleFrame:

Figura 1: Executando SampleFrame

Note que o botão de fechar ainda não funciona porque nenhum mecanismo de suporte a eventos
foi adicionado a classe até o momento. Conheceremos sobre suporte a eventos no próximo
módulo.

3.2. Graphics
Vários métodos gráficos são encontrados na classe Graphics. Aqui está a lista de alguns desses
métodos.

drawLine() drawPolyline() setColor()


fillRect() drawPolygon() getFont()
drawRect() fillPolygon() setFont()
clearRect() getColor() drawString()
Tabela 2: Alguns métodos da classe Graphics

Relacionada a essa classe está a classe Color, que tem três construtores.

Formato do Construtor Descrição


Color(int r, int g, int b) Valor inteiro de 0 a 255.
Color(float r, float g, float b) Valor decimal de 0.0 a 1.0.
Color(int rgbValue) Valor variável de 0 a 224-1 (preto a branco).
Vermelho: bits 16-23
Verde: bits 8-15
Azul: bits 0-7
Tabela 3: Construtores Color

Aqui está uma classe demonstrando a utilização de alguns métodos da classe Graphics:

import java.awt.*;

public class PanelDemo extends Panel {


PanelDemo() {
setBackground(Color.black); //Constante na classe Color
}
public void paint(Graphics g) {
g.setColor(new Color(0,255,0)); // verde
g.setFont(new Font("Helvetica",Font.PLAIN,16));
g.drawString("Hello GUI World!", 30, 100);
g.setColor(new Color(1.0f,0,0)); // vermelho
g.fillRect(30, 100, 150, 10);

Introdução à Programação II 7
JEDITM

}
public static void main(String args[]) {
Frame f = new Frame("Testing Graphics Panel");
PanelDemo painel = new PanelDemo();
f.add(painel);
f.setSize(600, 300);
f.setVisible(true);
}
}

Para um panel se tornar visível, ele deve ser colocado em uma janela visível como um frame.

Executando o código apresentado temos o seguinte resultado esperado:

Figura 2: Executando GraphicsPanel

3.3. Mais Componentes AWT


Aqui está uma lista de controles AWT. Controles são componentes como botões ou campos textos
que permitem ao usuário interagir com a aplicação GUI. Essas são todas as subclasses da classe
Component.

Label Button Choice

TextField Checkbox List

TextArea CheckboxGroup Scrollbar

Tabela 4: Componentes AWT

Introdução à Programação II 8
JEDITM

A seguinte classe cria um frame com alguns componentes:

import java.awt.*;

class ControlsDemo extends Frame {


public static void main(String args[]) {
ControlsDemo fwc = new ControlsDemo();
fwc.setLayout(new FlowLayout());
fwc.setSize(600, 100);
fwc.add(new Button("Test Me!"));
fwc.add(new Label("Labe"));
fwc.add(new TextField());
CheckboxGroup cbg = new CheckboxGroup();
fwc.add(new Checkbox("chk1", cbg, true));
fwc.add(new Checkbox("chk2", cbg, false));
fwc.add(new Checkbox("chk3", cbg, false));
List list = new List(3, false);
list.add("MTV");
list.add("V");
fwc.add(list);
Choice chooser = new Choice();
chooser.add("Avril");
chooser.add("Monica");
chooser.add("Britney");
fwc.add(chooser);
fwc.add(new Scrollbar());
fwc.setVisible(true);
}
}

Está e a janela que será mostrada na execução da classe ControlsDemo:

Figura 3: Executando ControlsDemo

Introdução à Programação II 9
JEDITM

4. Gerenciadores de Layout
A posição e o tamanho dos componentes em cada container é determinado pelo gerenciador de
layout. O gerenciador de layout gerencia a disposição dos componentes no container. Esses são
alguns dos gerenciadores de layout incluídos no Java.

• FlowLayout
• BorderLayout
• GridLayout
• GridBagLayout
• CardLayout
• BoxLayout

O gerenciador de layout pode ser configurado usando o método setLayout da classe Container. O
método possui a seguinte assinatura:

void setLayout(LayoutManager mgr)

Caso seja não seja necessário utilizar nenhum gerenciador de layout, é possível passar o layout
do tipo nulo (NullLayout) como argumento para esse método, ao se fazer isso será necessário
posicionar todos os elementos manualmente com a utilização do método setBounds da classe
Component. Este método possui a seguinte assinatura:

public void setBounds(int x, int y, int width, int height)

O método controla a posição baseada nos argumentos x (esquerda) e y (topo), e o tamanho


width (largura) e height (altura) especificados. Isso seria bastante difícil e tedioso de programar,
principalmente ao se possuir um layout com diversos objetos Component e Container. Teríamos
de chamar esse método para cada componente, além de conhecer sua determinada posição em
pixels.

4.1. O Gerenciador FlowLayout


O FlowLayout é o gerenciador padrão para a classe Panel e suas subclasses, incluindo a classe
Applet. Ele posiciona os componentes da esquerda para a direita e de cima para baixo,
começando no canto superior esquerdo. Imagine como se utilizasse um editor de textos. É assim
que o gerenciador FlowLayout funciona.

Ele possui três construtores que são como os listados abaixo:

Construtores FlowLayout
FlowLayout()
Cria um novo objeto FlowLayout com o alinhamento centralizado e 5 unidades de
intervalo horizontal e vertical aplicado aos componentes por padrão.
FlowLayout(int align)
Cria um novo objeto FlowLayout com o alinhamento especificado e o intervalo padrão de
5 unidades horizontal e vertical aplicado aos componentes.
FlowLayout(int align, int hgap, int vgap)
Cria um novo objeto FlowLayout com o primeiro argumento como o alinhamento
aplicado, o intervalo horizontal hgap e o itervalo vertical vgap aplicado aos
componentes.
Tabela 5: Construtores FlowLayout

O intervalo se refere ao espaçamento entre os componentes e é medido em pixels. O argumento


alinhamento deve ser um dos seguintes:
• FlowLayout.LEFT
• FlowLayout.CENTER

Introdução à Programação II 10
JEDITM

• FlowLayout.RIGHT

Observe a seguinte classe:

import java.awt.*;

class FlowLayoutDemo extends Frame {


public static void main(String args[]) {
FlowLayoutDemo fld = new FlowLayoutDemo();
fld.setLayout(new FlowLayout(FlowLayout.RIGHT, 10, 10));
fld.add(new Button("ONE"));
fld.add(new Button("TWO"));
fld.add(new Button("THREE"));
fld.setSize(100, 100);
fld.setVisible(true);
}
}

O resultado da execução sobre a plataforma Windows é apresentado abaixo.

Figura 4: Executando FlowLayoutDemo

4.2. O Gerenciador BorderLayout


O BorderLayout divide o Container em cinco partes – north (norte), south (sul), east (leste), west
(oeste) e center (centro). Cada componente é adicionado a uma região específica. As regiões
north e south espalham-se horizontalmente enquanto que as regiões east e west ajustam-se
verticalmente. A região centro, por outro lado, ajusta-se em ambos horizontalmente e
verticalmente. Esse layout é o padrão para objetos Window, incluindo as subclasses Frame e
Dialog.

Construtores BorderLayout
BorderLayout()
Cria um novo objeto BorderLayout sem nenhum espaçamento aplicado sobre os
diferentes componentes.
BorderLayout(int hgap, int vgap)
Cria um novo objeto BorderLayout com espaçamento horizontal hgap e vertical vgap
aplicado sobre os diferentes componentes.
Tabela 6: Construtores BorderLayout

Como no gerenciador FlowLayout, os parâmetros hgap e vgap aqui também se referem ao


espaçamento entre os componentes no container.

Para adicionar um componente a uma região específica, use o método add e passe dois
argumentos: o componente a ser adicionado e a região onde o componente deve ser posicionado.
Note que apenas um componente pode ser colocado em uma região. Adicionar mais de um
componente a um container resulta em exibir apenas o último componente adicionado. A lista a
seguir apresenta as regiões válidas que são campos predefinidos na classe BorderLayout.

• BorderLayout.NORTH

Introdução à Programação II 11
JEDITM

• BorderLayout.SOUTH
• BorderLayout.EAST
• BorderLayout.WEST
• BorderLayout.CENTER

Aqui está uma classe demonstrando como a BorderLayout pode ser utilizada:

import java.awt.*;

class BorderLayoutDemo extends Frame {


public static void main(String args[]) {
BorderLayoutDemo bld = new BorderLayoutDemo();
bld.setLayout(new BorderLayout(10, 10)); //pode remover
bld.add(new Button("NORTH"), BorderLayout.NORTH);
bld.add(new Button("SOUTH"), BorderLayout.SOUTH);
bld.add(new Button("EAST"), BorderLayout.EAST);
bld.add(new Button("WEST"), BorderLayout.WEST);
bld.add(new Button("CENTER"), BorderLayout.CENTER);
bld.setSize(200, 200);
bld.setVisible(true);
}
}

Aqui está o resultado desta classe. A segunda figura mostra o efeito do redimensionamento do
frame.

Figura 5: Executando BorderLayoutDemo

4.3. O gerenciador GridLayout


Com o gerenciador GridLayout, os componentes também são posicionados da esquerda para a
direita e de cima para baixo como no gerenciador FlowLayout. Além disso, o gerenciador
GridLayout divide o container em um número de linhas e colunas. Todas essas regiões são do
mesmo tamanho. Ele sempre ignora o tamanho preferido do componente.

A seguir, são apresentados os construtores disponíveis para a classe GridLayout.

Construtores GridLayout
GridLayout()
Cria um novo objeto GridLayout com uma única linha e uma única coluna por padrão.
GridLayout(int rows, int cols)
Cria um novo objeto GridLayout com o número especificado de linhas e colunas.
GridLayout(int rows, int cols, int hgap, int vgap)

Introdução à Programação II 12
JEDITM

Cria um novo objeto GridLayout com o número especificado de linhas e colunas. Os


espaçamentos horizontal hgap e vertical vgap são aplicados aos componentes.
Tabela 7: Construtores GridLayout

Vejamos a seguinte classe:

import java.awt.*;

class GridLayoutDemo extends Frame {


public static void main(String args[]) {
GridLayoutDemo gld = new GridLayoutDemo();
gld.setLayout(new GridLayout(2, 3, 4, 4));
gld.add(new Button("ONE"));
gld.add(new Button("TWO"));
gld.add(new Button("THREE"));
gld.add(new Button("FOUR"));
gld.add(new Button("FIVE"));
gld.setSize(200, 200);
gld.setVisible(true);
}
}

Esse é o resultado da classe (observe o efeito do redimensionamento sobre o frame na segunda


figura):

Figura 6: Executando GridLayoutDemo

4.4. Painéis e Layouts Complexos


Para criar layouts mais complexos, é possível combinar os diferentes gerenciadores de layout com
o uso de objetos do tipo Panel. Lembre-se que Panel é um Container e um Component ao mesmo
tempo. É possível inserir Components em um Panel e adicionar este a uma região específica do
Container.

Observe a técnica utilizada na classe a seguir:

import java.awt.*;

class ComplexDemo extends Frame {


public static void main(String args[]) {

Introdução à Programação II 13
JEDITM

ComplexDemo cl = new ComplexDemo();


Panel panelNorth = new Panel();
Panel panelCenter = new Panel();
Panel panelSouth = new Panel();
/* Painel North */
//Painéis usam FlowLayout por padrão
panelNorth.add(new Button("ONE"));
panelNorth.add(new Button("TWO"));
panelNorth.add(new Button("THREE"));
/* Painel Center */
panelCenter.setLayout(new GridLayout(4,4));
panelCenter.add(new TextField("1st"));
panelCenter.add(new TextField("2nd"));
panelCenter.add(new TextField("3rd"));
panelCenter.add(new TextField("4th"));
/* Painel South */
panelSouth.setLayout(new BorderLayout());
panelSouth.add(new Checkbox("Choose me!"),
BorderLayout.CENTER);
panelSouth.add(new Checkbox("I'm here!"),
BorderLayout.EAST);
panelSouth.add(new Checkbox("Pick me!"),
BorderLayout.WEST);
/* Adicionando os Panels ao Frame container */
//Frames usam BorderLayout por padrão
cl.add(panelNorth, BorderLayout.NORTH);
cl.add(panelCenter, BorderLayout.CENTER);
cl.add(panelSouth, BorderLayout.SOUTH);
cl.setSize(300,300);
cl.setVisible(true);
}
}

Este é o resultado da classe:

Figura 7: Executando Layout Complexo

Introdução à Programação II 14
JEDITM

5. Componentes GUI Swing


Como o pacote AWT, o pacote Swing fornece classes para criar aplicações GUI. O pacote é
encontrado em javax.swing. A diferença principal entre esses dois é que o componente Swing é
escrito inteiramente usando Java enquanto o outro não. Como resultado, Projetos GUI escritos
utilizando classes do pacote Swing possuem a mesma aparência mesmo quando executado sobre
plataformas completamente diferentes. Além disso, Swing fornece componentes mais
interessantes como o que permite selecionar cores e a OptionPane (painel de opções).

Os nomes dos componentes de Swing são quase similares aos componentes AWT. Uma diferença
óbvia é a convenção de nomes dos componentes. Basicamente, os nomes dos componentes
Swing são os mesmos nomes dos componentes AWT mas com um prefixo em que é adicionado a
letra "J". Por exemplo, um componente no AWT é a classe Button, o mesmo componente
correspondente a este no pacote Swing é a classe JButton. Descrito abaixo, está uma lista de
alguns dos componentes Swing:

Componente Descrição
JComponent A classe raiz para todos os componentes Swing, excluindo containers
hierarquicamente superiores.
JButton Um botão do tipo "pressionar". Corresponde a classe Button no pacote
AWT.
JCheckBox Um item que pode ser marcado ou desmarcado pelo usuário.
Corresponde a classe Checkbox no pacote AWT.
JFileChooser Permite ao usuário que selecione um arquivo. Corresponde a classe
FileChooser no pacote AWT.
JTextField Permite a edição de uma única linha de texto. Corresponde a classe
TextField no pacote AWT.
JFrame Herda e corresponde a classe Frame no pacote AWT, mas as duas são
ligeiramente incompatíveis em termos de adição de componentes a
esse container. É preciso pegar o conteúdo do pane atual antes de
adicionar um componente.
JPanel Herança de um JComponent. É uma classe container simples.
Corresponde a classe Panel no pacote AWT.
JApplet Herança da classe Applet no pacote AWT. Também ligeiramente
incompatível com a classe Applet em termos de adição de componentes
a esse container.
JOptionPane Herda JComponent. Fornece uma maneira fácil de exibir caixas de
diálogo pop-up.
JDialog Herança da classe Dialog no pacote AWT. Normalmente utilizado para
informar o usuário de alguma coisa ou alertá-lo para uma entrada.
JColorChooser Herda JComponent. Permite ao usuário selecionar uma cor.

Tabela 8: Alguns componentes Swing

Para a lista completa de componentes Swing, por favor recorra à documentação API.

5.1. Configurando Containers JFrame e JApplet


Como mencionado, os containers top-level como o JFrame e o JApplet no pacote Swing são
ligeiramente incompatíveis com seus correspondentes AWT. Isso em termos de adição de

Introdução à Programação II 15
JEDITM

componentes ao container. Ao invés de adicionar diretamente um componente ao container como


nos containers AWT, é necessário primeiro pegar o conteúdo do pane do container. Para fazer
isso utiliza-se o método getContentPane do container:

import javax.swing.*;
import java.awt.*;

class SwingDemo extends JFrame {


public SwingDemo() {
super("My First Swing Application");
this.setSize(300,300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String args[]) {
new SwingDemo();
}
}

Note que o pacote java.awt ainda é importado porque os gerenciadores de layout em uso são
definidos neste pacote. Além disso, dar um título ao frame e empacotar os componentes no
frame também é aplicável para aos frames AWT.

Dicas de programação:

1. Compare o estilo de código aplicado neste exemplo para AWT.


2. Componentes são declarados como campos, um método launchFrame é
definido, e a inicialização e adição de componentes são todas feitas no
método launchFrame.
3. Não herdamos a classe Frame, mas a classe JFrame.
4. A vantagem de utilizar este estilo se tornará aparente quando chegarmos
ao suporte a evento no tópico sobre tratamento de eventos.

Aqui está um resultado demonstrativo:

Figura 8: Executando SwingDemo

Introdução à Programação II 16
Módulo 2
Introdução à Programação II

Lição 8
Tratamento de Eventos em Interfaces Gráficas

Versão 1.0 - Mar/2007


JEDITM

1. Objetivos
Neste módulo, aprenderemos como tratar eventos disparados quando o usuário interage com a
interface gráfica de sua aplicação (GUI). Após completar este módulo seremos capazes de
desenvolver aplicações gráficas que responderão às interações do usuário.

Ao final desta lição, o estudante será capaz de:

• Enumerar os componentes do modelo de delegação de eventos


• Explicar como o modelo de delegação de eventos funciona
• Criar aplicações gráficas que interajam com o usuário
• Discutir os benefícios das classes adapter
• Discutir as vantagens de utilizar inner e anonymous inner class

Introdução à Programação II 4
JEDITM

2. Modelo de Delegação de Eventos


O modelo de Delegação de eventos descreve o modo como sua classe pode responder a uma
interação do usuário. Para compreender o modelo, estudaremos primeiro três importantes
componentes:

1. Event Source (Gerador de Evento)


O event source refere-se ao componente da interface que origina o evento. Por exemplo, se o
usuário pressiona um botão, o event source neste caso é o botão.

2. Event Listener/Handler (Monitor de Eventos/Manipulador)


O event listener recebe informações de eventos e processa as interações do usuário. Quando
um botão é pressionado, o event listener pode tratá-lo exibindo uma informação útil ao
usuário.

3. Event Object (Objeto Evento)


Quando um evento ocorre (por exemplo, quando o usuário interage com um componente da
interface gráfica), um objeto Event é criado. Este objeto contém todas as informações
necessárias sobre o evento gerado. As informações incluem o tipo de evento, digamos, "o
mouse foi clicado". Há diversas classes de evento para diferentes categorias de ações do
usuário. Um objeto event tem o tipo de dado de uma dessas classes.

Aqui está representado o modelo de delegação de eventos:

Figura 1: Modelo de Delegação de Eventos

Inicialmente, um listener deverá ser registrado pelo event source. Assim ele poderá receber
informações sobre os eventos quando ocorrerem no event source. Somente um listener
registrado poderá receber notificações dos eventos. Uma vez registrado, um listener
simplesmente aguarda até que ocorra um evento.

Quando alguma coisa acontece no event source, um objeto event, que descreve o evento, é
criado. O evento é então disparado pelo gerador para os listener registrados.

Quando o listener recebe um objeto event (ou seja, uma notificação) de um event source, ele
executa sua função. Ele decifra a notificação e processa o evento ocorrido.

Introdução à Programação II 5
JEDITM

2.1. Registro de Listeners

O event source registra um listener através dos métodos add<Tipo>Listener.

void add<Tipo>Listener(<Tipo>Listener listenerObj)

<Tipo> depende do tipo de event source. Ele pode ser Key, Mouse, Focus, Component, Action e
outros.

Diversos listener podem ser registrados para um event source para recepção de notificações de
eventos.

Um listener registrado pode também ser removido através do método remove<Tipo>Listener.

void remove<Tipo>Listener(<Tipo>Listener listenerObj)

Introdução à Programação II 6
JEDITM

3. Classes Event
Um EventObject tem uma classe de evento que indica seu tipo. Na raiz da hierarquia das classes
Event estão a classe EventObject, que é encontrada no pacote java.util. Uma subclasse imediata
da classe EventObject é a classe AWTEvent. A classe AWTEvent está declarada no pacote
java.awt. Ela é a raiz de todos os eventos baseados em AWT. A seguir temos algumas das classes
de evento AWT:

Classes de Evento Descrição


ComponentEvent Estende a classe AWTEvent. Instanciada quando um componente
é movido, redimensionado, tornado visível ou invisível.
InputEvent Estende a classe ComponentEvent. Classe abstrata de evento,
raiz a partir da qual são implementadas todas as classes de
componentes de entrada de dados.
ActionEvent Estende a classe AWTEvent. Instanciada quando um botão é
pressionado, um item de uma lista recebe duplo-clique ou quando
um item de menu é selecionado.
ItemEvent Estende a classe AWTEvent. Instanciada quando um item é
selecionado ou desmarcado pelo usuário, seja numa lista ou caixa
de seleção (checkbox).
KeyEvent Estende a classe InputEvent. Instanciado quando uma tecla é
pressionada, liberada ou digitada (pressionada e liberada).
MouseEvent Estende a classe InputEvent. Instanciada quando um botão do
mouse é pressionado, liberado, clicado (pressionado e liberado)
ou quando o cursor do mouse entra ou sai de uma parte visível
de um componente.
TextEvent Estende a classe AWTEvent. Instanciada quando o valor de um
campo texto ou area de texto sofre alteração.
WindowEvent Estende a classe ComponentEvent. Instanciada quando um
objeto Window é aberto, fechado, ativado, desativado,
minimizado, restaurado ou quando o foco é transferido para
dentro ou para fora da janela.
Tabela 1: Classes Event

Tome nota: todas as subclasses de AWTEvent seguem esta convenção de nomeação:

<Tipo>Event

Introdução à Programação II 7
JEDITM

4. Listeners de Evento
Listeners de evento são classes que implementam as interfaces <Tipo>Listener. A tabela a seguir
algumas interfaces utilizadas com maior freqüência:

Listeners de Evento Descrição


ActionListener Recebe eventos de ação, estes podem ser um pressionamento do
mouse ou da barra de espaço sobre o objeto.
MouseListener Recebe eventos do mouse.
MouseMotionListener Recebe eventos de movimento do mouse, que incluem arrastar e
mover o mouse.
WindowListener Recebe eventos de janela (abrir, fechar, minimizar, entre
outros).
Tabela 2: Event Listeners

4.1. Método de ActionListener


Este é o método da interface ActionListener que deve ser implementado:

Médoto de ActionListener
public void actionPerformed(ActionEvent e)
Chamado quando o mouse é pressionado ou foi utilizada a barra de espaço sobre um
botão por exemplo.
Tabela 3: Método de ActionListener

4.2. Métodos de MouseListener


Estes são os métodos da interface MouseListener que devem ser implementados:

Métodos de MouseListener
public void mouseClicked(MouseEvent e)
Chamado quando o mouse é pressionado (pressionar e soltar).
public void mouseEntered(MouseEvent e)
Chamado quando o cursor do mouse entra em um componente.
public void mouseExited(MouseEvent e)
Chamado quando o cursor do mouse sai de um componente.
public void mousePressed(MouseEvent e)
Chamado quando o botão do mouse é pressionado sobre um componente (pressionar).
public void mouseReleased(MouseEvent e)
Chamado quando o botão do mouse é solto sobre um componente (soltar).
Tabela 4: Métodos de MouseListener

4.3. Métodos de MouseMotionListener


Estes são os métodos da interface MouseMotionListener que devem ser implementados:

Introdução à Programação II 8
JEDITM

Métodos MouseListener
public void mouseDragged(MouseEvent e)
Chamado quando o mouse é pressionado sobre um componente e então arrastado
(dragged). É chamado tantas vezes quanto o mouse for arrastado.
public void mouseMoved(MouseEvent e)
Chamado quando o cursor do mouse é movido sobre um componente, sem que o
mouse esteja pressionado. Será chamado múltiplas vezes, tantas quantas o mouse for
movido.
Tabela 5: Métodos MouseMotionListener

4.4. Métodos WindowListener


Estes são os métodos da interface WindowListener que devem ser implementados:

Métodos WindowListener
public void windowOpened(WindowEvent e)
Chamado quando uma janela é aberta (quando o objeto Window torna-se visível pela
primeira vez)
public void windowClosing(WindowEvent e)
Chamado quando uma janela é encerrada (objeto Window).
public void windowClosed(WindowEvent e)
Chamado quando a janela foi fechada após a liberação de recursos utilizados pelo
objeto (EventSource).
public void windowActivated(WindowEvent e)
Chamado quando uma janela é ativada, ou seja, está em uso.
public void windowDeactivated(WindowEvent e)
Chamado quando uma janela deixa de ser a janela ativa.
public void windowIconified(WindowEvent e)
Chamado quando a janela é iconificada (Este evento é utilizado especialmente para o
ambiente Macintosh).
public void windowDeiconified(WindowEvent e)
Chamado quando a janela retorna do estado iconificado para o normal (Este evento é
utilizado especialmente para o ambiente Macintosh).
Tabela 6: Métodos WindowListener

4.5. Guia para criação de Aplicações Gráficas com tratamento de


eventos
Estes são os passos a serem lembrados ao criar uma aplicação gráfica com tratamento de
eventos.

1. Criar uma classe que descreva e mostre a aparência da sua aplicação gráfica.
2. Criar uma classe que implemente a interface listener apropriada. Esta classe poderá estar
inserida na classe do primeiro passo.
3. Na classe implementada, sobrepor TODOS os métodos da interface listener. Descrever em
cada método como o evento deve ser tratado. Podemos deixar vazio um método que não
desejamos tratar.
4. Registrar o objeto listener (a instância da classe listener do passo 2) no EventSource utilizando
o método add<Tipo>Listener.

Introdução à Programação II 9
JEDITM

4.6. Exemplo do Evento Action


import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class ActionDemo extends JFrame implements ActionListener {


private JTextField tf;
private JButton bt;
public ActionDemo(String title){
super(title);
tf = new JTextField();
bt = new JButton("Clicked");
add(tf, BorderLayout.SOUTH);
add(bt, BorderLayout.NORTH);
setSize(300,300);
bt.addActionListener(this);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void actionPerformed(ActionEvent actionEvent) {
if (tf.getText().equals("Action"))
tf.setText("");
else
tf.setText("Action");
}
public static void main(String args[]) {
new ActionDemo("Action Demo");
}
}

A seguir vemos algumas imagens da janela criada pela classe ActionDemo:

4.7. Anonymous inner class


Anonymous inner class são classes internas que não são declaradas. O uso de anonymous inner
class simplifica a classe. A seguir temos o mesmo exemplo apresentado anteriormente modificado
para utilizar este recurso.

Introdução à Programação II 10
JEDITM

4.8. Exemplo do Evento Action


import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class ActionDemo extends JFrame {


private JTextField tf;
private JButton bt;
public ActionDemo(String title){
super(title);
tf = new JTextField();
bt = new JButton("Clicked");
add(tf, BorderLayout.SOUTH);
add(bt, BorderLayout.NORTH);
setSize(300,300);
bt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
method();
}
});
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void method() {
if (tf.getText().equals("Action"))
tf.setText("");
else
tf.setText("Action");
}
public static void main(String args[]) {
new ActionDemo("Action Demo");
}
}

Observe que a classe se encontra de forma mais organizada, criamos um objeto em tempo de
execução para o evento, este fará a chamada um método, chamado method, que se encarregará
de executar as instruções.

4.9. Exemplo de Eventos do Mouse

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class MouseEventsDemo extends JFrame {


private TextField tf;
public MouseEventsDemo(String title){
super(title);
tf = new TextField(60);
add(tf, BorderLayout.SOUTH);
setSize(300,300);
this.addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent mouseEvent) {
eventMouse1(mouseEvent);
}
public void mouseEntered(MouseEvent mouseEvent) {
eventMouse2(mouseEvent);
}
public void mouseExited(MouseEvent mouseEvent) {
eventMouse3(mouseEvent);

Introdução à Programação II 11
JEDITM

}
public void mousePressed(MouseEvent mouseEvent) {
eventMouse4(mouseEvent);
}
public void mouseReleased(MouseEvent mouseEvent) {
eventMouse5(mouseEvent);
}
});
this.addMouseMotionListener(new MouseMotionListener() {
public void mouseDragged(MouseEvent mouseEvent) {
eventMouse6(mouseEvent);
}
public void mouseMoved(MouseEvent mouseEvent) {
eventMouse7(mouseEvent);
}
});
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void eventMouse1(MouseEvent me) {
tf.setText("Mouse clicked.");
}
public void eventMouse2(MouseEvent me) {
tf.setText("Mouse entered component.");
}
public void eventMouse3(MouseEvent me) {
tf.setText("Mouse exited component.");
}
public void eventMouse4(MouseEvent me) {
tf.setText("Mouse pressed.");
}
public void eventMouse5(MouseEvent me) {
tf.setText("Mouse released.");
}
public void eventMouse6(MouseEvent me) {
tf.setText("Mouse dragged at " + me.getX() + "," + me.getY());
}
public void eventMouse7(MouseEvent me) {
tf.setText("Mouse moved at " + me.getX() + "," + me.getY());
}
public static void main(String args[]) {
new MouseEventsDemo("Mouse Events Demo");
}
}

A seguir vemos algumas imagens da janela criada pela classe MouseEventsDemo:

Introdução à Programação II 12
JEDITM

Figura 2: Executando MouseEventsDemo

Figura 3: Executando MouseEventsDemo: Mouse "entra" na janela

Figura 4: Executando MouseEventsDemo: Mouse sai da janela

Introdução à Programação II 13
JEDITM

4.10. Exemplo Close Window

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class WindowDemo extends JFrame {


public WindowDemo(String title) {
super(title);
this.setSize(300,300);
this.addWindowListener(new WindowListener() {
public void windowActivated(WindowEvent windowEvent) {
}
public void windowClosed(WindowEvent windowEvent) {
}
public void windowClosing(WindowEvent windowEvent) {
closed();
}
public void windowDeactivated(WindowEvent windowEvent) {
}
public void windowDeiconified(WindowEvent windowEvent) {
}
public void windowIconified(WindowEvent windowEvent) {
}
public void windowOpened(WindowEvent windowEvent) {
}
});
this.setVisible(true);
}
public void closed() {
System.exit(0);
}
public static void main(String args[]) {
new WindowDemo("Close Window Example");
}
}

Executando esta classe, será exibida a janela abaixo:

Figura 5: Executando CloseFrame

Introdução à Programação II 14
JEDITM

5. Classes Adapter
Implementar todos os métodos de uma interface é muito trabalhoso. Freqüentemente
necessitaremos implementar somente alguns métodos da interface. Felizmente, Java nos oferece
as classes adapter que implementam todos os métodos das interfaces listener que possuem mais
de um método. As implementações dos métodos são vazias.

5.1. Exemplo Close Window

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class WindowDemo extends JFrame {


private JLabel label;
public WindowDemo(String title) {
super(title);
this.setSize(300,300);
label = new JLabel("Close the frame.");
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
closed();
}
});
this.setVisible(true);
}
public void closed() {
System.exit(0);
}
public static void main(String args[]) {
new WindowDemo("Close Window Example");
}
}

Comparando com o exemplo anterior, repare que não existe mais a necessidade de implementar
os outros métodos do listener deixando-os em branco, implementamos apenas os métodos que
realmente iremos utilizar.

Introdução à Programação II 15
JEDITM

6. Inner Class
Nesta seção faremos uma revisão de conceitos que já foram abordados no primeiro módulo do
curso. Inner class é muito útil no tratamento de eventos em interfaces gráficas.

6.1. Inner Class


Aqui está uma breve revisão sobre inner class. Uma inner class, como o nome já diz, é uma
classe declarada dentro de outra classe. O uso de uma inner class pode auxiliar na simplificação
de suas classes, especialmente quanto ao tratamento de eventos, como será mostrado no
exemplo a seguir:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class WindowDemo extends JFrame {


private JLabel label;
public WindowDemo(String title) {
super(title);
this.setSize(300,300);
label = new JLabel("Close the frame.");
this.addWindowListener(new CFListener());
this.setVisible(true);
}
private class CFListener extends WindowAdapter {
public void windowClosing(WindowEvent e) {
closed();
}
}
public void closed() {
System.exit(0);
}
public static void main(String args[]) {
new WindowDemo("Close Window Example");
}
}

Introdução à Programação II 16
Módulo 2
Introdução à Programação II

Lição 9
Threads

Versão 1.0 - Mar/2007


JEDITM

1. Objetivos
Vimos diversas classes que são executadas sequencialmente. Uma classe seqüencial refere-se a
uma classe que possui um fluxo de execução. Ela tem um ponto de início de execução, uma
seqüência de execução e o final da execução. Possui um único processo sendo executado.

Contudo, numa situação do mundo real, existe a necessidade de capturar processos


concorrentes. Sendo que estes processos são executados simultaneamente. Neste ponto entram
as threads.

Ao final desta lição, o estudante será capaz de:

• Definir o que são threads


• Enumerar os diferentes estados de uma thread
• Explicar o conceito de prioridade na thread
• Utilizar os métodos da classe Thread
• Criar suas próprias threads
• Utilizar sincronização para execução de threads concorrentes que sejam independentes
umas das outras
• Permitir que as threads se comuniquem umas com as outras concorrentemente em sua
execução
• Utilizar as utilidades da concorrência

Introdução à programação II 4
JEDITM

2. Definição e básico de threads


2.1. Definição de Thread
A thread refere-se a um fluxo seqüencial simples de controle em uma classe. Para simplificar,
pense em threads como mais de um processo simultâneo que serão executados paralelamente a
partir de um determinado ponto. Considere os modernos sistemas operacionais que permitem
rodar vários softwares ao mesmo tempo. Enquanto escrevemos um documento no computador
utilizando o editor de texto, podemos escutar uma música, navegar na rede e o relógio do
computador continua sendo atualizado. O sistema operacional instalado no seu computador
permite o que definiremos como multitarefa. Um aplicativo pode executar diversos processos
simultaneamente. Um exemplo deste tipo de aplicação é a HotJava do navegador web, que
permite a navegação através de páginas enquanto realizamos downloads de algumas imagens,
assistimos animações e ouvimos musicas.

Figura 1: Threads

2.2. Estados da thread

Figura 2: Estados da thread

Uma thread poderá assumir um dos seguintes estados:

• Read
A thread pode ser executada, mas ainda não foi lhe dado à chance. Ou após ter sido
bloqueada/suspensa, esta pronta para ser executada.

Introdução à programação II 5
JEDITM

• Running
A thread esta sendo executada e esta sob controle da CPU.
• Sleeping
A thread é interrompida por determinado tempo.
• Waiting
A thread é interrompida por indeterminado tempo.
• Blocked
Uma thread bloqueada não é capaz de rodar, pois esta esperando por um recurso
disponível ou que algum evento aconteça.
• Dead
A thread terminou tudo o que foi ordenada a fazer.

2.3. Prioridades
É possível informar ao controle da CPU que uma thread possui uma prioridade maior sobre outra.
A prioridade é um valor inteiro entre 1 e 10. Quanto maior a prioridade da thread, maior a chance
de ser executado executada primeiro.

Assumiremos a existência de duas threads e supomos que ambas estejam prontas para rodar. A
primeira thread é atribuído atribuída a prioridade 5 (normal) enquanto que a segunda possui a
prioridade 10 (máxima). Digamos que a primeira thread esteja executando enquanto que que a
segunda esteja pronta para ser executada. Então, a segunda thread poderia receber o controle da
CPU e tornar-se executável por possuir a maior prioridade comparada com a thread corrente.
Este cenário é um exemplo de troca de contexto.

A troca de contexto ocorre quando uma thread perde o controle da CPU para outra thread.
Existem várias formas na qual a troca de contexto pode ocorrer. Um cenário é quando uma
thread está sendo executada e voluntariamente cede o controle da CPU para que outra thread
tenha oportunidade de ser executada. Neste caso, a thread de maior prioridade que esteja pronta
para executar recebe o controle da CPU. Outra forma para que a troca de contexto ocorra é
quando uma thread perde seu lugar para outra thread de maior prioridade como visto no exemplo
anterior.

É possível que exista mais de uma thread disponível de maior prioridade e prontas para serem
executadas. Para decidir qual das threads com a mesma prioridade receberá o controle da CPU
isso dependerá do sistema operacional. No Windows 95/98/NT utilizará fracionamento de tempo e
revezamento para resolver este caso. Cada thread de mesma prioridade é dado tempo limite para
ser executada antes da CPU passar o controle para outra thread de igual prioridade. Por outro
lado, o Solaris permite que threads sejam executadas antes de completarem sua tarefa, ou antes,
de voluntariamente ceder o controle à CPU.

Introdução à programação II 6
JEDITM

3. A classe Thread
3.1. Construtor
A classe Thread possui oito construtores. Vejamos rapidamente alguns destes.

Construtores da Thread
Thread()
Cria um novo objeto Thread.
Thread(String name)
Cria um novo objeto Thread com um nome específico.
Thread(Runnable target)
Cria um novo objeto Thread baseado no objeto Runnable. target refere-se ao objeto no
qual o método executado será chamado.
Thread(Runnable target, String name)
Cria um novo objeto Thread com um nome específico e baseado no objeto Runnable.
Tabela 1: Construtores Thread

3.2. Constantes
A classe Thread provê constantes para valores de prioridade. Segue a tabela que nos mostra um
resumo dos campos da classe Thread.

Constantes Thread
public final static int MAX_PRIORITY
O maior valor de uma prioridade, 10.
public final static int MIN_PRIORITY
O menor valor de uma prioridade, 1.
public final static int NORM_PRIORITY
O valor padrão de uma prioridade, 5.
Tabela 2: Constantes Thread

3.3. Métodos
Aqui estão alguns dos métodos encontrados na classe Thread.

Métodos Thread
public static Thread currentThread()
Retorna a referência para a thread corrente que esteja sendo executada.
public final String getName()
Retorna o nome da thread.
public final void setName(String name)
Renomeia a thread para o argumento especificado name. Poderá lançar
SecurityException.
public final int getPriority()

Introdução à programação II 7
JEDITM

Retorna a prioridade atribuída à thread.


public final boolean isAlive()
Indica se a thread esta executando ou não.
public final void join([long millis, [int nanos]])
Um método sobrecarregado. A thread corrente que esta sendo executada poderá
esperar até que esta thread morra (se nenhum parâmetro for especificado), ou até que
tempo especificado transcorra.
public static void sleep(long millis)
Suspende a thread por um tempo millis. Poderá lançar InterruptedException.
public void run()
A execução da thread inicia com este método.
public void start()
Ocasiona o início da execução da thread chamando o método run.
Tabela 3: Métodos Thread

3.4. Um Exemplo de Thread


Neste primeiro exemplo de uma thread, veremos como funciona um contador.

import javax.swing.*;
import java.awt.*;

class ThreadDemo extends JFrame {


JLabel label;
public ThreadDemo(String title) {
super(title);
label = new JLabel("Start count!");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(label);
this.setSize(300,300);
this.setVisible(true);
}
private void startCount() {
try {
for (int i = 10; i > 0; i--) {
Thread.sleep(500);
label.setText(i + "");
}
label.setText("Count down complete.");
} catch (InterruptedException ie) {
}
label.setText(Thread.currentThread().toString());
}
public static void main(String args[]) {
new ThreadDemo("Count down GUI").startCount();
}
}

A classe CountDownGui conta de 10 a 1 e depois mostra a informação sobre a thread que está
sendo executado executada. Estas são algumas telas que foram retiradas enquanto a classe era
executada:

Introdução à programação II 8
JEDITM

Figura 3: Telas da classe CountDownGui

Introdução à programação II 9
JEDITM

4. Criando Threads
Threads podem tanto ser criadas de duas formas, a primeira é herdando a classe Thread (sua
classe é uma thread) e a segunda é implementando a interface Runnable (sua classe tem uma
thread).

4.1. Herança (estendendo) da classe Thread

Neste próximo exemplo, veremos uma classe que mostra 100 vezes o nome do objeto thread.

class ThreadDemo extends Thread {


public ThreadDemo(String name) {
super(name);
start();
}
public void run() {
for (int i = 0; i < 100; i++)
System.out.print(getName());
}
public static void main(String args[]) {
ThreadDemo pnt1 = new ThreadDemo("A");
ThreadDemo pnt2 = new ThreadDemo("B");
ThreadDemo pnt3 = new ThreadDemo("C");
ThreadDemo pnt4 = new ThreadDemo("D");
}
}

Observe que os objetos pnt1, pnt2, pnt3, e pnt4 são utilizadas uma única vez. Para esta
aplicação, não há qualquer necessidade de se utilizar atributos para se referir a cada thread. É
possível substituir o corpo do método principal pelas seguintes instruções:

new ThreadDemo("A");
new ThreadDemo("B");
new ThreadDemo("C");
new ThreadDemo("D");

A classe produzirá diferentes saídas em cada execução. Aqui temos um exemplo de uma possível
saída:

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCDABCDABCDABCDABCD
ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDAB
CDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD
ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCD
BCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDB
CDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCD

4.2. Implementando a interface Runnable

Outra forma do usuário para se criar uma thread é implementar a interface Runnable. O único
método que a interface Runnable requer que seja implementado é o método "public void run()".
Pense neste como o método que a thread executará.

O próximo exemplo é semelhante ao exemplo anterior mostrado:

class ThreadDemo implements Runnable {


Thread thread;

Introdução à programação II 10
JEDITM

public ThreadDemo(String name) {


thread = new Thread(this, name);
thread.start();
}
public void run() {
String name = thread.getName();
for (int i = 0; i < 100; i++) {
System.out.print(name);
}
}
public static void main(String args[]) {
new ThreadDemo("A");
new ThreadDemo("B");
new ThreadDemo("C");
new ThreadDemo("D");
}
}

4.3. É uma (extends Thread) x Tem uma (implements Runnable)

Estas são as duas únicas formas de se obter threads, escolher entre elas é uma questão de gosto
ou de necessidade. Implementar por exemplo a interface Runnable pode ser mais trabalhoso já
que ainda teremos que declarar um objeto Thread e comunicar os métodos thread sobre este
objeto. Herdar a classe Thread, no entanto, significaria que a classe não poderia mais estender
qualquer outra classe, pois Java proíbe heranças múltiplas. Uma troca entre implementação fácil
e possibilidade de estender a classe é feita de acordo com o estilo selecionado. Pese o que é mais
necessário.

4.4. Utilizando o método join

Agora que já vimos como criar threads, iremos ver como o método join funciona. O exemplo
abaixo utiliza o método join sem qualquer argumento. Este método (quando chamado sem
argumento) causa a espera da execução da thread corrente até que a thread que chama este
método termine a sua execução.

class ThreadDemo implements Runnable {


Thread thread;
public ThreadDemo(String name) {
thread = new Thread(this, name);
thread.start();
}
public void run() {
String name = thread.getName();
for (int i = 0; i < 100; i++) {
System.out.print(name);
}
}
public static void main(String args[]) {
ThreadDemo t1 = new ThreadDemo("A");
ThreadDemo t2 = new ThreadDemo("B");
ThreadDemo t3 = new ThreadDemo("C");
ThreadDemo t4 = new ThreadDemo("D");
System.out.println("Running threads...");
try {
t1.thread.join();
t2.thread.join();
t3.thread.join();

Introdução à programação II 11
JEDITM

t4.thread.join();
} catch (InterruptedException ie) {
}
System.out.println("\nThreads killed."); //printed last!
}
}

Execute esta classe. O que notamos? Através da chamada do método join, temos a certeza que o
último trecho foi executado até a última parte.

Aqui está um exemplo de saída da execução do código:

Running Threads…
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCDBCDBCDBCDBCBCBCBCBCBCDB
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
Threads killed.

Comente o bloco try-catch onde o método join foi executado. Existe alguma diferença na saída
da classe?

Introdução à programação II 12
JEDITM

5. Sincronização
Até agora, temos visto exemplos de threads que estão sendo executadas concorrentemente, mas
são independentes umas da outras. Ou seja, threads que são executadas no seu próprio ritmo
sem a preocupação pelo status ou pelas atividades de outras threads que são executadas
concorrentemente. Desta forma, cada thread não requer qualquer fonte ou método externo e,
como resultado, não precisa se comunicar com outras threads.

Em muitas situações, executar threads concorrentemente pode requerer fontes e métodos


externos. Assim, existe a necessidade de se comunicar com outras threads executadas
concorrentemente para saber seus status e atividades. Um exemplo neste cenário é o problema
produtor-consumidor. O problema envolve dois objetos principais, um que funcionará como um
produtor gerando valores ou dados e outro como consumidor para receber ou consumir estes
valores.

5.1. Um exemplo não sincronizado

Vejamos a seguinte classe que mostra uma seqüência de Strings em uma ordem específica:

class TwoStrings {
static void print(String str1, String str2) {
System.out.print(str1);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
System.out.println(str2);
}
}
class PrintStringsThread implements Runnable {
Thread thread;
String str1, str2;
PrintStringsThread(String str1, String str2) {
this.str1 = str1;
this.str2 = str2;
thread = new Thread(this);
thread.start();
}
public void run() {
TwoStrings.print(str1, str2);
}
}
class ThreadDemo {
public static void main(String args[]) {
new PrintStringsThread("Hello ", "there.");
new PrintStringsThread("How are ", "you?");
new PrintStringsThread("Thank you ", "very much!");
}
}

É esperado que a classe mostre dois argumentos dos objetos Runnable consecutivamente. O
problema, no entanto, é que a invocação do método sleep acarreta a execução de outras threads
quando alguma outra thread ainda não terminou com a execução do método print da classe
TwoStrings. Aqui está um exemplo de saída:

Hello How are Thank you there.


you?

Introdução à programação II 13
JEDITM

very much!

Nesta execução, as três threads devem ter seus primeiros argumentos mostrados antes dos
segundos argumentos. Isto resulta em uma saída oculta.

Na verdade, o este exemplo não coloca um problema muito sério, mas para outras aplicações,
isto pode ocasionar algumas exceções ou problemas.

5.2. Travando um objeto


Para garantir que apenas uma thread tenha acesso a um método, Java permite travar um objeto
incluindo seus métodos com o uso de monitores. O objeto entra com o monitor implícito quando a
sincronização de métodos é invocada. Assim que um objeto estiver sendo monitorado, o monitor
garante que nenhuma outra thread acesse o mesmo método. Como conseqüência, isso garante
que apenas uma thread por vez irá executar o método do objeto.

Para sincronizar um método, utilizamos a palavra-chave synchronized na assinatura do método.


Neste caso não podemos modificar o código fonte da definição do método, podemos sincronizar o
objeto no qual o método pertence. A sintaxe para sincronizar um objeto é a seguinte:

synchronized (<object>) {
//trecho de código a ser sincronizado
}

Com isso, os métodos do objeto podem ser invocados uma vez por thread.

5.3. Primeiro Exemplo Sincronizado


Aqui esta o código modificado onde o método print da classe TwoString está sincronizado.

class TwoStrings {
synchronized static void print(String str1, String str2) {
System.out.print(str1);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
System.out.println(str2);
}
}

class PrintStringsThread implements Runnable {


Thread thread;
String str1, str2;
PrintStringsThread(String str1, String str2) {
this.str1 = str1;
this.str2 = str2;
thread = new Thread(this);
thread.start();
}
public void run() {
TwoStrings.print(str1, str2);
}
}

class ThreadDemo {
public static void main(String args[]) {
new PrintStringsThread("Hello ", "there.");
new PrintStringsThread("How are ", "you?");
new PrintStringsThread("Thank you ", "very much!");

Introdução à programação II 14
JEDITM

}
}

A classe agora produz os trechos corretos:

Hello there.
How are you?
Thank you very much!

5.4. Segundo Exemplo Sincronizado

Esta é uma outra versão da classe anterior. O método print da classe TwoString está
sincronizado. Porém, ao invés de utilizar a palavra reservada synchronized no método, está sendo
aplicado no objeto.

class TwoStrings {
static void print(String str1, String str2) {
System.out.print(str1);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
System.out.println(str2);
}
}

class PrintStringsThread implements Runnable {


Thread thread;
String str1, str2;
TwoStrings ts;
PrintStringsThread(String str1, String str2, TwoStrings ts)
{
this.str1 = str1;
this.str2 = str2;
this.ts = ts;
thread = new Thread(this);
thread.start();
}
public void run() {
synchronized (ts) {
ts.print(str1, str2);
}
}
}

class TestThread {
public static void main(String args[]) {
TwoStrings ts = new TwoStrings();
new PrintStringsThread("Hello ", "there.", ts);
new PrintStringsThread("How are ", "you?", ts);
new PrintStringsThread("Thank you ", "very much!", ts);
}
}

A classe também mostrará os trechos corretos.

Introdução à programação II 15
JEDITM

6. Comunicação entre threads


Nesta seção, iremos aprender sobre os métodos básicos utilizados para permitir a comunicação
entre threads concorrentementes enquanto são executadas.

Métodos para Comunicação entre threads


public final void wait()
Faz com que esta thread espere até que outra chame o método notify ou notifyAll neste
objeto. Poderá lançar InterruptedException.
public final void notify()
Torna executável a thread que teve o método wait chamado neste objeto.
public final void notifyAll()
Torna executáveis as threads que tiveram o método wait chamado neste objeto.
Tabela 4: Método para Comunicação entre Threads

Para facilitar o entendimento destes métodos, vamos considerar o cenário garçom/cliente. No


restaurante, o garçom espera (waits) que o cliente faça um pedido, ao invés de estar sempre
perguntado se alguém deseja fazer um pedido. Quando o cliente entra, significa que o cliente
está interessado na comida do restaurante. Desta forma, o cliente ao entrar no restaurante
notifica (notifies) o garçom que irá necessitar dos seus serviços. Contudo, nem sempre o cliente
está preparado para fazer um pedido. Seria chato se garçom ficasse continuamente perguntando
ao cliente se o mesmo deseja fazer o pedido. Então, o garçom aguarda o cliente notificá-lo
(notifies) que está pronto. Uma vez que o cliente entregou o pedido, seria um incomodo
continuar importunando o garçom se o seu pedido já está entregue. Normalmente o cliente
aguarda o garçom notificá-lo (notifies) servindo a comida.

Observe neste cenário que a parte que aguarda é executada assim que o cliente informa o
garçom. O mesmo é verdade nas threads.

Figura 4: Cenário Cliente/Garçom

Introdução à programação II 16
JEDITM

6.1. Exemplo Produtor-Consumidor


O seguinte exemplo é uma implementação do problema Produtor-Consumidor. A classe que provê
métodos para gerar e consumir um valor inteiro são separadas as classes threads Produtor e
Consumidor

class SharedData {
int data;
synchronized void set(int value) {
System.out.println("Generate " + value);
data = value;
}
synchronized int get() {
System.out.println("Get " + data);
return data;
}
}

class Producer implements Runnable {


SharedData sd;
Producer(SharedData sd) {
this.sd = sd;
new Thread(this, "Producer").start();
}
public void run() {
for (int i = 0; i < 10; i++) {
sd.set((int)(Math.random()*100));
}
}
}

class Consumer implements Runnable {


SharedData sd;
Consumer(SharedData sd) {
this.sd = sd;
new Thread(this, "Consumer").start();
}
public void run() {
for (int i = 0; i < 10 ; i++) {
sd.get();
}
}
}
class ProducerConsumerDemo {
public static void main(String args[]) throws Exception {
SharedData sd = new SharedData();
new Producer(sd);
new Consumer(sd);
}
}

Este é um exemplo da saída desta classe:

Generate 8
Generate 45
Generate 52
Generate 65
Get 65
Generate 23

Introdução à programação II 17
JEDITM

Get 23
Generate 49
Get 49
Generate 35
Get 35
Generate 39
Get 39
Generate 85
Get 85
Get 85
Get 85
Generate 35
Get 35
Get 35

Isto não é o que gostaríamos que a classe produzisse. Para todos os valores produzidos pelo
produtor, nós esperamos que o consumidor obtenha cada valor. Aqui está uma saída que seria
desejável:

Generate 76
Get 76
Generate 25
Get 25
Generate 34
Get 34
Generate 84
Get 84
Generate 48
Get 48
Generate 29
Get 29
Generate 26
Get 26
Generate 86
Get 86
Generate 65
Get 65
Generate 38
Get 38
Generate 46
Get 46

Para consertar o problema com este código, utilizamos os métodos de comunicação entre
threads. A seguinte implementação do problema Produtor-Consumidor utiliza os métodos para
comunicação entre as threads.

class SharedData {
int data;
boolean valueSet = false;
synchronized void set(int value) {
if (valueSet) { //has just produced a value
try {
wait();
} catch (InterruptedException ie) {
}
}
System.out.println("Generate " + value);
data = value;
valueSet = true;
notify();
}

Introdução à programação II 18
JEDITM

synchronized int get() {


if (!valueSet) { //producer hasn't set a value yet
try {
wait();
} catch (InterruptedException ie) {
}
}
System.out.println("Get " + data);
valueSet = false;
notify();
return data;
}
}

/* A parte remanescente do código não muda. */


class Producer implements Runnable {
SharedData sd;
Producer(SharedData sd) {
this.sd = sd;
new Thread(this, "Producer").start();
}
public void run() {
for (int i = 0; i < 10; i++) {
sd.set((int)(Math.random()*100));
}
}
}

class Consumer implements Runnable {


SharedData sd;
Consumer(SharedData sd) {
this.sd = sd;
new Thread(this, "Consumer").start();
}
public void run() {
for (int i = 0; i < 10 ; i++) {
sd.get();
}
}
}

class TestProducerConsumer {
public static void main(String args[]) throws Exception {
SharedData sd = new SharedData();
new Producer(sd);
new Consumer(sd);
}
}

Introdução à programação II 19
JEDITM

7. Utilidades concorrentes
Com a versão do J2SE 5.0, o novo controle de threads e das suas características concorrentes
foram adicionados à Java. Estas novas características são encontradas no pacote
java.util.concurrent. Nesta seção, duas destas características concorrentes serão vistas.

7.1. A Interface Executor


Uma das mais importantes características herdadas para desenvolver aplicações multi-thread é o
framework Executor. A interface é incluída no pacote java.util.concurrent. Objetos deste tipo
executam tarefas do tipo Runnable.

Sem o uso desta interface, executamos tarefas do tipo Runnable criando instâncias Thread e
chamando o método start do objeto Thread. O seguinte código demonstra uma forma de fazer
isso:

new Thread(<aRunnableObject>).start();

Com a disponibilidade desta nova interface, objetos Runnable submetidos são executados usando
o método execute como a seguir:

<anExecutorObject>.execute(<aRunnableObject>);

O novo framework Executor é útil para aplicações multithread. Visto que a thread necessita da
pilha de alocação dinâmica de memória, a criação de threads pode ser relativamente cara. Como
resultado, a criação de várias threads pode causar um erro pela falta de memória. Uma forma de
resolver este problema é com um pool de threads. No pool de threads, uma thread ao invés de
morrer é enfileirada no pool após completar a sua tarefa designada. No entanto, implementar um
esquema bem projetado de pool de thread não é simples. Outro problema é a dificuldade em
cancelar e terminar as threads.

O framework Executor resolve estes problemas desacoplando à submissão de tarefas do


mecanismo de como cada tarefa será executado executada, incluindo detalhes do uso de threads,
agendamento e outros. Ao invés de criação e execução da thread através do métodos start para
cada tarefa, ele é mais cauteloso, utilizar o seguinte fragmento de código:

Executor <executorName> = <anExecutorObject>;


<executorName>.execute(new <RunnableTask1>());
<executorName>.execute(new <RunnableTask2>());
...

Visto Executor ser uma interface, esta não pode ser instanciada. Para criar um objeto de
Executor, deve-se criar uma classe implementando esta interface ou utilizar um método de
fábrica disponível na classe Executors. Esta classe também está disponível no mesmo pacote da
interface. A classe Executors provê métodos para o gerenciamento do pool de threads. Aqui esta
um resumo destes métodos de fábrica:

Métodos de Fábrica da classe Executors


public static ExecutorService newCachedThreadPool()
Cria um pool de thread que cria novas thread threads quando necessário, porém
reutilizará threads previamente construídas quando disponíveis. Existe um método
sobrescrito, que aceita com como parâmetro um objeto ThreadFactory.
public static ExecutorService newFixedThreadPool(int nThreads)
Cria um pool de thread que reutiliza uma lista fixa de threads operando em segundo
plano de uma fila ilimitada. Um método sobrescrito, o qual recebe um objeto
ThreadFactory como parâmetro adicional.

Introdução à programação II 20
JEDITM

public static ScheduledExecutorService newScheduledThreadPool(int


corePoolSize)
Cria um pool de thread que pode programar comando para serem executados após
um período de tempo, ou periodicamente. Um método sobrescrito, o qual recebe um
objeto ThreadFactory como parâmetro adicional.
public static ExecutorService newSingleThreadExecutor()
Cria um Executor que utiliza uma thread simples que trabalha operando em segundo
plano de uma fila ilimitada. Um método sobrescrito, o qual recebe um objeto
ThreadFactory como parâmetro adicional.
public static ScheduledExecutorService newSingleThreadScheduledExecutor()
Cria uma simples thread executora que pode programar comando a serem executados
após um período de tempo, ou periodicamente. Um método sobrescrito, o qual recebe
um objeto ThreadFactory como parâmetro adicional.
Tabela 5: Métodos de Fábrica da classe Executor

A tarefa Runnable é executada e finalizada sob o controle da interface Executor. Para parar
threads, podemos invocar o método shutdown da interface como segue:

executor.shutdown();

7.2. A Interface Callable


Existem duas formas de se criar threads. Podemos tanto estender a classe Thread ou
implementar a interface Runnable. Em qualquer técnica utilizada, customizamos as
funcionalidades sobrescrevendo o método run. O método possui a seguinte assinatura:

public void run()

Os malefícios em se criar threads desde modo são:

1. O método run não permite retornar um resultado, pois seu tipo de retorno é void.
2. Requer que seja capturado as exceções verificáveis, visto ser um método a ser implementado
e não possuir a cláusula throws.

A interface Callable é basicamente a mesma da interface Runnable sem estes problemas.


Devemos utilizar outro mecanismo para obter o resultado de uma tarefa Runnable. Uma técnica
seria utilizar uma variável de instância para armazenar o resultado. A classe a seguir mostra
como isso pode ser feito.

public MyRunnable implements Runnable {


private int result = 0;
public void run() {
...
result = someValue;
}
public int getResult() {
return result;
}
}

Vejamos como obter o resultado com a utilização da interface Callable:

import java.util.concurrent.*;

public class MyCallable implements Callable {


public Integer call() throws java.io.IOException {
...

Introdução à programação II 21
JEDITM

return someValue;
}
}

O método call possui a seguinte assinatura:

<V> call() throws Exception

Onde <V> é um tipo genérico, que significa que o tipo de retorno do método call poderá ser uma
referencia a qualquer tipo. Futuramente iremos aprender mais sobre tipos genéricos (generics).

Introdução à programação II 22
Módulo 2
Introdução à Programação II

Lição 10
Redes

Versão 1.0 - Mar/2007


JEDITM

1. Objetivos
A linguagem Java permite que facilmente sejam criadas aplicações que desempenham diversas
tarefas através de uma rede. Esse é um dos principais benefícios de Java, uma vez que a
linguagem foi criada tendo em vista seu uso para a Internet. Antes de aprender sobre o uso e a
funcionalidade Java em redes, devemos ter conhecimento de alguns conceitos básicos de redes.

Ao final desta lição, o estudante será capaz de:

• Explicar os conceitos básicos de redes


• Endereço IP
• Protocolo
• Portas
• Paradigma Cliente/Servidor
• Sockets
• Criar aplicações usando o pacote de Java para redes
• As classes ServerSocket e Socket
• As classes MulticastSocket e DatagramPacket

Introdução à Programação II 4
JEDITM

2. Conceitos Básicos sobre Redes


A Internet é uma rede mundial que reúne diferentes tipos de computadores que são interligados
de diversas maneiras. Apesar da diversidade de hardware e software interconectados, é
extraordinário como a Internet permanece interconectada (funcional). Isso é possível devido aos
padrões de comunicação definidos e respeitados. Esses padrões asseguram a compatibilidade e a
confiabilidade de comunicação entre uma ampla diversidade de sistemas na Internet. Vejamos
alguns desses padrões.

2.1. Endereço IP
Cada um dos computadores conectados à Internet tem um único endereço IP. Do ponto de vista
lógico, o endereço IP é similar ao tradicional endereço para correspondência enviada pelos
correios, conhecido como CEP, no sentido de que um endereço identifica unicamente um
determinado objeto. O endereçamento IP é um número de 32 bits usado para identificar
exclusivamente cada computador conectado à Internet. O número 192.1.1.1 é um exemplo de
um endereço IP. Esses endereços podem também ser expressos em formato símbólico, como por
exemplo: docs.rinet.ru.

2.2. Protocolo
Uma vez que existem muitos tipos de comunicações que ocorrem ativamente na Internet, é
necessário existir um número igual de mecanismos para dar conta deles. Cada tipo de
comunicação exige um protocolo específico e único.

Um protocolo refere-se a um conjunto de regras e padrões que definem um certo tipo de


comunicação via Internet. O protocolo descreve o formato dos dados enviados através da
Internet, juntamente com as informações de como e quando está sendo enviado.

Na realidade, o conceito de protocolo não é novo. Considere quantas vezes estivemos envolvidos
neste tipo de conversação:

"Alô"
"Alô. Eu poderia falar com Joana?"
"Aguarde um momento, por favor"
"Obrigado"

Esse é um protocolo social usado quando se trata de uma conversa telefônica. Esse tipo de
protocolo nos proporciona confiança e familiaridade sobre como nos comportarmos em
determinadas situações.

Examinemos agora alguns protocolos importantes usados na Internet. Sem dúvida, o Hypertext
Transfer Protocol (HTTP, ou Protocolo de Transferência de Hipertexto) é um dos protocolos mais
comumente usados. Ele é usado para transferir documentos HTML na Web. Existe também o File
Transfer Protocol (FTP, ou Protocolo de Transferência de Arquivos), que geralmente é conhecido,
em comparação com o HTTP; e permite que seja transferido arquivos binários pela Internet. Os
dois protocolos têm seu próprio conjunto de regras e padrões de como os dados sobre
transferência de dados. Java dá suporte a ambos os protocolos.

2.3. Portas
Note que os protocolos somente fazem sentido quando usados no contexto de um serviço. Por
exemplo, o protocolo HTTP é usado quando se está disponibilizando conteúdo de Web através de
um serviço HTTP. Cada computador na Internet pode disponibilizar uma diversidade de serviços

Introdução à Programação II 5
JEDITM

por meio dos diversos protocolos suportados. O problema, porém, é que o tipo de serviço que
precisa ser conhecido, antes que as informações possam ser transferidas. É nesse contexto que
as portas são relevantes.

Uma porta é um número de 16 bits que identifica cada serviço oferecido por um servidor de rede.
Para usar determinado serviço, e portanto estabelecer uma linha de comunicação e conexão por
meio de um protocolo específico, é necessário conectar-se à porta apropriada. As portas são
associadas a um número, e alguns desses números são especificamente associados a um
determinado tipo de serviço. Essas portas às quais são alocados serviços específicos são
denominadas portas padrão. Por exemplo, o serviço FTP está localizado na porta 21, o passo que,
enquanto o serviço HTTP está localizado na porta 80. Ao necessitar executar uma transferência
de arquivo via FTP, é imprescindível conectar-se à porta 21 do servidor. Todos os serviços
alocados de forma padrão são atribuídos a valores de portas abaixo de 1024. Os valores de
portas acima de 1024 são disponíveis para comunicações personalizadas. Caso um valor de porta
acima de 1024 já esteja em uso por alguma comunicação personalizada, deve-se procurar outros
valores ociosos.

2.4. O Paradigma Cliente/Servidor


O Paradigma Cliente/Servidor é à base das aplicações de redes em Java. Evidentemente, esse
esquema compreende dois elementos principais, o cliente e o servidor. O termo cliente refere-se
à máquina que necessita algum tipo de informação, ao passo que o servidor é a máquina onde
essa informação está armazenada, aguardando para ser fornecida.

O paradigma descreve um cenário simples. Normalmente, um cliente conecta-se a um servidor


para consultar determinada informação. O servidor então analisa a consulta e retorna a
informação nele disponível para o cliente.

Figure 1: Client/Server model

2.5. Sockets
O último conceito geral de redes que iremos abordar antes de mergulhar em redes em Java
relaciona-se com a classe sockets. A maior parte da programação em Java para redes é utilizado
um determinado tipo de comunicação em rede denominada sockets.

Socket é uma abstração, na forma de software, para um meio de entrada ou saída de


comunicação. É por meio do uso de sockets que a linguagem Java executa toda a sua
comunicação de baixo nível em redes. Os sockets são canais de comunicação que permitem a
transferência de dados através de uma determinada porta; em resumo, um socket refere-se a
uma porta-fim (endpoint) para comunicação entre duas máquinas.

Introdução à Programação II 6
JEDITM

3. O Pacote Java para Redes


O java.net package oferece classes especificas para o desenvolvimento de aplicações para redes.
Para obter uma lista completa de classes e interfaces relacionadas com redes, por favor, consulte
a documentação da API de Java. Vamos nos concentrar nestas quatro classes: ServerSocket,
Socket, MulticastSocket, e DatagramPacket.

3.1. As Classes ServerSocket e Socket


A Classe ServerSocket disponibiliza as funcionalidades básicas de um servidor. A tabela a seguir
descreve dois dos quatro construtores da classe ServerSocket:

Construtores da classe ServerSocket


ServerSocket(int port)
Instancia um servidor que é vinculado à porta especificada. Uma porta 0 aloca o
servidor a qualquer porta ociosa. Por default, o comprimento máximo de fila para
conexão (chegando) é fixado (como igual a) em 50.
ServerSocket(int port, int backlog)
Parâmetro backlog (fila acumulada).
Table 1: ServerSocket constructors

Abaixo segue alguns dos métodos desta classe:

Métodos da classe ServerSocket


public Socket accept()
Faz com que o servidor aguarde e escute conexões de clientes, e então as aceite.
public void close()
Fecha o socket do servidor. Uma vez fechado o socket, os clientes não podem mais
conectar-se ao servidor, a menos que o socket seja aberto novamente.
public int getLocalPort()
Retorna a porta à qual o socket está vinculado.
public boolean isClosed()
Indica se o socket está fechado ou não.
Table 2: ServerSocket methods

O exemplo a seguir é uma implementação de um servidor simples, que simplesmente ecoa a


informação enviada pelo cliente.

import java.net.*;
import java.io.*;

public class EchoingServer {


public static void main(String[] args) {
ServerSocket server = null;
Socket client;
try {
server = new ServerSocket(1234);
// 1234 é um número de porta não utilizado
} catch (IOException ie) {
System.out.println("O socket não pode ser aberto.");
System.exit(1);

Introdução à Programação II 7
JEDITM

}
while(true) {
try {
client = server.accept();
OutputStream clientOut = client.getOutputStream();
PrintWriter pw = new PrintWriter(clientOut, true);
InputStream clientIn = client.getInputStream();
BufferedReader br = new BufferedReader(new
InputStreamReader(clientIn));
pw.println(br.readLine());
} catch (IOException ie) {
}
}
}
}

A classe ServerSocket implementa socket de servidor e a classe Socket implementa um socket de


cliente. A classe Socket possui oito construtores, dos quais dois já foram descartados.
Examinemos brevemente dois desses construtores.

Construtores da classe Socket


Socket(String host, int port)
Cria um socket de cliente que se conecta ao número fornecido de porta no host
especificado.
Socket(InetAddress address, int port)
Cria um socket de cliente que se conecta ao número fornecido de porta, no endereço IP
especificado.
Table 3: Socket constructors

Segue alguns métodos da classe:

Métodos da classe Socket


public void close()
Fecha o socket cliente.
public InputStream getInputStream()
Recupera o fluxo de entrada associado a esse socket.
public OutputStream getOutputStream()
Recupera o fluxo de saída associado a esse socket.
public InetAddress getInetAddress()
Retorna o endereço de IP ao qual o socket está conectado
public int getPort()
(Returna) Retorna a porta remota à qual este socket está conectado.
public boolean isClosed()
Indica se o socket está fechado ou não.
Table 4: Socket methods

O exemplo a seguir é uma implementação de um cliente simples, que apenas envia dados para
um servidor.

Introdução à Programação II 8
JEDITM

import java.io.*;
import java.net.*;

public class MyClient {


public static void main(String args[]) {
try {
Socket client = new Socket(InetAddress.getLocalHost(), 1234);
InputStream clientIn = client.getInputStream();
OutputStream clientOut = client.getOutputStream();
PrintWriter pw = new PrintWriter(clientOut, true);
BufferedReader br = new BufferedReader(new
InputStreamReader(clientIn));
BufferedReader stdIn = new BufferedReader(new
InputStreamReader(System.in));
System.out.println("Digite uma mensagem para o servidor: ");
pw.println(stdIn.readLine());
System.out.println("Mensagem do Servidor: ");
System.out.println(br.readLine());
pw.close();
br.close();
client.close();
} catch (ConnectException ce) {
System.out.println("Não foi possível se conectar ao servidor.");
} catch (IOException ie) {
System.out.println("Erro de I/O.");
}
}
}

A execução de EchoingServer deixa-o pronto para aceitar mensagens do cliente. Depois que um
cliente, como MyClient, envia uma mensagem ao servidor, o servidor devolve a mensagem de
volta para o cliente. Abaixo, um exemplo da execução de MyClient depois da inicialização de
EchoingServer:

Digite uma mensagem para o servidor:


Primeira mensagem para o servidor
Mensagem do Servidor:
Primeira mensagem para o servidor

3.2. As Classes MulticastSocket e DatagramPacket


A classe MulticastSocket é útil para aplicações que implementam comunicações em grupos. Os
endereços IP para um grupo multicast ficam na faixa de 224.0.0.0 a 239.255.255.255.
Entretanto, o endereço 224.0.0.0 é reservado, e não deve ser usado. Essa classe tem três
construtores, mas consideraremos, aqui, apenas um desses construtores.

Construtores da classe MulticastSocket


MulticastSocket(int port)
Cria um multicast socket vinculado ao número de porta fornecido.
Tabela 1.5: Construtor de MulticastSocket

A tabela abaixo dá uma descrição de alguns métodos de MulticastSocket.

Métodos da classe MulticastSocket


public void joinGroup(InetAddress mcastaddr)
Entrar em um grupo multicast no endereço especificado.

Introdução à Programação II 9
JEDITM

public void leaveGroup(InetAddress mcastaddr)


Sair de um a grupo multicast no endereço especificado.
public void send(DatagramPacket p)
Um método herdado da classe DatagramSocket. Envia um pacote a partir desse socket.
Tabela 5: Métodos de MulticastSocket

Antes que alguém possa enviar uma mensagem para um grupo, é preciso primeiro ser um
membro do grupo multicast usando o método joinGroup. Um membro pode então enviar
mensagens usando o método send. Depois que você tiver terminado de falar com o grupo,
poderá usar o método leaveGroup para encerrar sua participação no grupo.

Antes de examinar um exemplo de uso da classe MulticastSocket, vamos antes dar uma olhada
rápida na classe DatagramPacket. Observe que no método send da classe MulticastSocket, o
parâmetro necessário é um objeto DatagramPacket. Assim, precisamos compreender esse tipo de
(objetos) objeto, antes de usar o método send.

A classe DatagramPacket é usada para enviar dados por intermédio de um protocolo sem
conexão, como um multicast. Um problema nisso é que o envio de pacotes não é garantido.
Consideremos, agora, dois de seus seis construtores.

Construtores da classe DatagramPacket


DatagramPacket(byte[] buf, int length)
Constrói um pacote datagrama para receber pacotes com um comprimento length.
length precisa ser menor ou igual ao tamanho do buffer buf.
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
Constrói um pacote datagrama para enviar pacotes com um comprimento length para a
porta de número especificado, no hospedeiro especificado.
Tavela 6: Construtores de datagramPacket

Segue alguns métodos interessantes da classe DatagramPacket.

Métodos da classe DatagramPacket


public byte[] getData()
Retorna o buffer no qual dados foram armazenados.
public InetAddress getAddress()
Retorna o endereço IP da máquina para onde o pacote está sendo enviado ou de onde
foi recebido.
public int getLength()
Retorna o comprimento dos dados que estejam sendo enviados ou recebidos.
public int getPort()
Retorna o número da porta no hospedeiro remoto para onde os pacotes estão sendo
enviados ou de onde foram recebidos.
Table 7: Métodos deDatagramPacket

Nosso exemplo de multicast também consiste em duas classes, uma servidora e uma cliente. A
servidora recebe mensagens do cliente e imprime essas mensagens.

Aqui está a classe servidora.

Introdução à Programação II 10
JEDITM

import java.net.*;

public class ChatServer {


public static void main(String args[]) throws Exception {
MulticastSocket server = new MulticastSocket(1234);
InetAddress group = InetAddress.getByName("234.5.6.7");
//getByName - retorna o endereço IP dado para o host
server.joinGroup(group);
boolean infinite = true;
/* O servidor recebe continuamente os dados e imprimindo-os */
while(infinite) {
byte buf[] = new byte[1024];
DatagramPacket data = new DatagramPacket(buf, buf.length);
server.receive(data);
String msg = new String(data.getData()).trim();
System.out.println(msg);
}
server.close();
}
}

Aqui está a classe cliente.

import java.net.*;
import java.io.*;

public class ChatClient {


public static void main(String args[]) throws Exception {
MulticastSocket chat = new MulticastSocket(1234);
InetAddress group = InetAddress.getByName("234.5.6.7");
chat.joinGroup(group);
String msg = "";
System.out.println("Digite uma mensagem ao servidor:");
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
msg = br.readLine();
DatagramPacket data = new DatagramPacket(msg.getBytes(),
0, msg.length(), group, 1234);
chat.send(data);
chat.close();
}
}

Aqui está uma amostra de execução das classes ChatServer e ChatClient, assumindo que
ChatServer foi executada antes de rodarmos a classe cliente:

/* Executando a classe ChatServer para mostrar as mensagens aceitas do


cliente */

/* Executando ChatClient – simplesmente passe as mensagens para o


servidor */
Digite a mensagem para o Servidor:
Primeira mensagem para o Servidor

/* A classe ChatServer recebe e mostra as mensagens dos clientes */


Primeira mensagem do Servidor

/* Executando ChatClient novamente */


Digite a mensagem para o Servidor:
Segunda mensagem para o Servidor

Introdução à Programação II 11
JEDITM

/* A classe ChatServer recebe e mostra a mensagem do cliente */


Segunda mensagem do Servidor

Introdução à Programação II 12
Módulo 2
Introdução à Programação II

Lição 11
Applets

Versão 1.0 - Mar/2007


JEDITM

1. Objetivos
Applets é uma das variedades mais interessantes de Java. Refere-se a aplicativos que são
executados por meio de um navegador de Internet. Iremos conhecer mais sobre como criar
applets nessa lição.

Ao final desta lição, o estudante será capaz de:

• Definir o que é uma applet


• Criar sua própria applet
• Explicar o ciclo de vida de uma applet
• Utilizar os métodos das applets
• Métodos para mostrar a applet
• Métodos para reproduzir clipes de áudio
• Utilizar a tag applet de HTML

Introdução à Programação II 4
JEDITM

2. Criando Applets
Uma applet é um tipo especial de classe Java que é executado pela Internet. É normalmente
executada por um navegador de Internet, tipo: Netscape Navigator, Mozilla ou Microsoft Internet
Explorer. No entanto, comparada com outras aplicações Java, applets não tem acesso ao
computador na qual está sendo executada por razões de segurança. Isso faz com que applets
sejam bastante restritas se comparadas com outras aplicações Java.

2.1. Hello World Applet

A classe Applet é uma subclasse da classe Panel definida na AWT. A melhor forma de entender
como criar uma applet, é através de exemplos. Então, aqui está uma simples applet que mostra a
mensagem "Hello world!".

import java.awt.*;
import java.applet.*;

public class AppletDemo extends Applet {


public void paint(Graphics g) {
g.drawString("Hello world!", 80, 25);
}
}

Depois da compilação, tente rodar esse exemplo usando o comando: java AppletDemo. O que
acontece? Lembre-se que as applets são aplicações Java especiais. Elas não são executadas
utilizando o comando java. Em vez disso, a applet é executada por um navegador de internet ou
através de um aplicativo denominado appletviewer. Para executar a applet através de um
navegador de Internet, crie uma página HTML utilizando a tag Applet da linguagem HTML. Para
isso, crie uma arquivo com a extensão .html contendo o seguinte código:

<applet code="AppletDemo" width=300 height=100>


</applet>

A tag no exemplo dado, indica que uma applet seja criada com a largura de 300 pixels e altura de
100 pixels. Então, o método drawString desenha a frase "Hello world!" na posição em pixels
(80,25) contando para baixo e depois à direita.

Figura 1: exemplo de Applet

Outra forma de executar uma applet é através do aplicativo appletviewer. Simplesmente siga
essa sintaxe:

appletviewer <nome do arquivo java>

Introdução à Programação II 5
JEDITM

Por exemplo, para executar o exemplo da applet, digite em uma janela de console:

appletviewer AppletDemo.java

Ao se criar uma applet, é necessário extender a classe Applet. Como foi mencionado
previamente, essa classe é encontrada no pacote java.applet. Portanto, é extremamente
necessário importar o pacote java.applet. Além disso, foi mencionado anteriormente que a classe
Applet é uma subclasse da classe Panel. Isso implica que alguns métodos da classe Applet são
encontradas na classe Panel. Para acessar os métodos ou campos na classe Panel ou outras
classes ancestrais, será necessário importar o pacote java.awt.

Introdução à Programação II 6
JEDITM

3. Métodos da Applet
Esta secção demonstrará alguns métodos de Applets extremamente interessantes

3.1. O ciclo de vida de uma Applet


Em vez de começar a execução no método main como uma aplicação Java típica, o navegador ou
o aplicativo appletviewer com a applet através dos seguintes métodos:

1.init()
init é o primeiro metódo chamado. Ele é chamado assim que a applet for carregada.

2.start()
Após chamar o método init, start é o próximo método chamado. Ele é chamado cada vez que a
página HTML da applet é exibida. Quando a applet é reexibido, a execução começa com esse
método.

3.stop()
Quando o navegador de Internet sai da página HTML do applet, esse método é chamado para
informar ao applet que ele deve interromper sua execução.

4.destroy()
Esse método é chamado quando o applet precisa ser completamente removido da memória. O
método stop é sempre chamado antes que esse método seja chamado.

Quando criamos applets, pelo menos alguns desses métodos devem ser overriden. O exemplo
seguinte de applet realiza este processo:

import java.applet.*;
import java.awt.*;

public class LifeCycleDemo extends Applet {


String msg ="";
public void init() {
msg += "initializing... ";
repaint();
}
public void start() {
msg += "starting... ";
repaint();
}
public void stop() {
msg += "stopping... ";
repaint();
}
public void destroy() {
msg += "preparing for unloading... ";
repaint();
}
public void paint(Graphics g) {
g.drawString(msg, 15, 15);
}
}

A seguir temos um exemplo de um documento HTML embutido com um applet LifeCycleDemo.

<HTML>
<TITLE>Life Cycle Demo</TITLE>

Introdução à Programação II 7
JEDITM

<applet code="LifeCycleDemo" width=300 height=100>


</applet>
</HTML>

3.2. Método paint


Outro importante método é o paint, que a classe Applet herda de sua classe ancestral
Component. Este método é chamado toda vez que a saída da applet precisa ser redesenhada. Um
exemplo deste comportamento é quando a applet, escondido por outra janela e fica visível
novamente. Esse método pode ser substituído quando for necessário customizar a aparência da
applet. No exemplo para a classe AppletDemo, onde é mostrada a mensagem "Hello world!" no
fundo depois de ter substituído o método paint.

3.3. Método showStatus


Applet tem uma janela de status, que informa o que ela está fazendo no momento. Se for
necessário mostrar alguma mensagem na janela de status, chame o método showStatus. O
exemplo a seguir é identico ao AppletDemo, entretanto com comandos adicinais que modificam o
conteúdo da janela de status.

import java.awt.*;
import java.applet.*;

public class AppletDemo extends Applet {


public void paint(Graphics g) {
g.drawString("Hello world!", 80, 25);
showStatus("This is an important information.");
}
}

A seguir, o resultado do exemplo:

Figura 2: exempo showStatus()

3.4. Reproduzindo clipes de Áudio


Applets também são providas de métodos que permitem reproduzir arquivos de áudio. Reproduzir
clipes de áudio em uma applet envolve as seguintes etapas:

1. Obter o clipe de áudio usando o método getAudioClip.


2. Para reproduzir o clipe de áudio, use o método play ou o método loop no objeto do clipe
de áudio.
3. O método play permite a reprodução única do áudio, enquanto que o método loop
reproduz o áudio continuamente, parando apenas quando o método stop for chamado.

O próximo exemplo reproduz continuamente um áudio até que o método stop da applet seja

Introdução à Programação II 8
JEDITM

acionado.

import java.awt.*;
import java.applet.*;

public class AudioApplet extends Applet {


AudioClip ac;
public void init() {
try {
/* clipe de audio foi salvo no mesmo diretório do código java */
/* spaceMusic foi baixado de java.sun.com */
ac = getAudioClip(getCodeBase(), "spaceMusic.au");
ac.loop();
} catch (Exception e) {
System.out.println(e);
}
}
public void stop() {
ac.stop();
}
public void paint(Graphics g) {
g.drawString("Playing space music!", 80, 25);
}
}

Introdução à Programação II 9
JEDITM

4. Applet HTML Tags


Nos exemplos anteriores, foi mostrado como a tag HTML de applet é utilizada nas páginas HTML
ou no fonte Java. Agora, veremos à forma mais completa da tag HTML para applet.

<APPLET
[CODEBASE = codebaseURL]
CODE = appletFile
[ATL = alternateText]
[NAME = appletInstanceName]
WIDTH = widthInPixels HEIGHT = heightInPixels
[ALIGN = alignment]
[VSPACE = vspaceInPixels] [HSPACE = hspaceInPixels]
>
[<PARAM NAME = parameterName1 VALUE = parameterValue1>]
[<PARAM NAME = parameterName2 VALUE = parameterValue2>]
...
[<PARAM NAME = parameterNamen VALUE = parameterValuen>]
[HTML que será mostrado na ausência do Java]
</APPLET>

Palavras-chave de tags HTML para Applets


CODEBASE
Diretório onde a classe applet está localizada. Por padrão, utiliza o mesmo diretório URL
do documento HTML.
CODE
Nome do arquivo que contém o código applet. Com ou sem as extensões .java ou
.class.
ALT
Texto mostrado quando o navegador conhece tags applet mas não consegue executá-
la. Pode acontecer se o Java do navegador estiver desabilitado.
NAME
Nome da applet. Usado para permitir que outras applets se comuniquem com o applet
usando esse nome.
WIDTH, HEIGHT
Largura e altura da janela da applet. Especificado em pixels.
ALIGN
Alinhamento ou posicionamento da applet. Pode receber diversos valores "left", "right",
"top", "bottom", "middle", "baseline", "texttop", "absmiddle", ou "absbottom". O
posicionamento padrão depende do ambiente.

VSPACE, HSPACE
Espaço acima e abaixo (VSPACE) e o dos lados (HSPACE) do applet.
PARAM NAME, VALUE
Serve para especificar parâmetros que podem ser passados para o applet; applets
podem chamar o método getParameter(String paramName).
Tabela 1: tags HTML para Applets

Observação:

• top – topo do applet alinhado com o item mais alto da mesma linha.

Introdução à Programação II 10
JEDITM

• bottom, baseline – parte inferior do applet alinhado com a parte inferior de outros itens
da mesma linha.
• middle – meio do applet alinhado com a parte inferior de outros componentes na mesma
linha.
• texttop – topo do applet alinhado com o topo do texto mais alto da mesma linha .
• absmiddle – meio do applet alinhado com o meio vertical de outros componentes da
mesma linha.
• absbottom – parte inferior do applet alinhado com a parte inferior de outros
componentes da mesma linha.

O exemplo abaixo demonstra como acessar parâmetros especificados na tag HTML.

import java.awt.*;
import java.applet.*;

public class ParamDemo extends Applet {


public void paint(Graphics g) {
g.drawString(getParameter("myParam"), 80, 25);
}
}

O resultado dessa classe é o mesmo da AppletDemo. Logo abaixo vemos a tela com o resultado
esperado:

Figura 3: Exemplo de execução do ParamDemo

Introdução à Programação II 11
Módulo 2
Introdução à Programação II

Lição 12
Stream de Entrada e Saída de Dados (I/O)
Avançados

Versão 1.0 - Mar/2007


JEDITM

1. Objetivos

Em lições anteriores, vimos como obter a entrada do usuário e manipular arquivos utilizando
Stream (se refere a uma sequência de dados). Agora iremos aprender mais sobre Stream e
outras classes relacionadas.

Ao final desta lição, o estudante será capaz de:

• Enumerar os tipos de Stream


• Stream de caracteres e bytes
• Stream de entrada e saída de dados
• Node Stream e Filter Stream
• Usar a classe File e seus métodos
• Usar as diferentes classes de Entrada e Saída
• Reader
• Writer
• InputStream
• OutputStream
• Explicar o conceito de encadeamento de Stream
• Definir serialização
• Explicar o uso da palavra-chave transient
• Escrever e ler a partir de um Stream

Introdução à programação II 4
JEDITM

2. Tipos Stream Gerais


2.1. Stream de caracteres e bytes
Geralmente existem dois tipos de Stream, de caracteres e de bytes. Vejamos a diferença básica
entre estes dois tipos. Stream de bytes (ou Byte Stream) são abstrações de arquivos ou
dispositivos para dados binários, enquanto Stream de caracteres (ou Character Stream) são para
os caracteres Unicode.

A classe InputStream é uma classe abstrata raiz para todos os Stream de bytes utilizados como
entrada, enquanto a classe OutputStream é a classe abstrata raiz para todos os Stream de bytes
de saída. Para Stream de caracteres, a superclasse correspondente as classes de leitura e escrita,
respectivamente as classes Reader e Writer.

2.2. Stream de entrada e saída de dados


Stream são também categorizados segundo o seu uso: se são utilizados para ler ou para
escrever. É possível ler a partir de Stream de entrada, embora não seja possível escrever nos
mesmos. Por outro lado, é possível escrever a um Stream de saída, embora não seja possível ler
a partir deles.

A classe InputStream e a classe Reader são superclasses de todos os Stream de entrada de


dados. A classe OutputStream e a classe Writer são as superclasses de todos os Stream de saída
de dados.

Stream de entrada de dados (input Stream) são também conhecidos como Source Stream, já
que obtemos informações a partir destes Stream. Enquanto isso, Stream de saída de dados
(output Stream) são também chamados Sink Stream.

2.3. Node Stream e Filter Stream


O pacote java.io difere entre Node Stream e Filter Stream. Um Node Stream é um Stream com a
funcionalidade básica de ler ou escrever a partir de um local específico como um disco ou a partir
da rede. Tipos de Node Stream incluem arquivos, memória e pipes. Filter Stream, por outro lado,
são postos sobre os Node Stream entre as tarefas ou os processos para prover funcionalidades
adicionais não encontradas nos Node Stream. Agregar camadas a um Node Stream é chamado
encadeamento de Stream ou Stream Chaining.

Introdução à programação II 5
JEDITM

3. Classe File
A classe File não é uma classe do tipo Stream, é uma representação abstrata de arquivos reais e
de caminhos de diretórios.

Para construir um objeto da classe File, pode-se utilizar o seguinte construtor:

Construtor para a classe File


File(String pathname)
Instancia um objeto File com o pathname especificado como seu nome de arquivo. O
nome do arquivo pode tanto ser absoluto (ex., contém o caminho completo) ou pode
consistir do próprio nome do arquivo e se assume que o mesmo está contido no mesmo
diretório.
Tabela 1: Construtor para a classe File

A classe File provê diversos métodos para manipulação de arquivos e diretórios. Na tabela abaixo
estão alguns destes métodos:

Métodos da classe File


public String getName()
Retorna o nome do arquivo ou o nome do diretório deste objeto File.
public boolean exists()
Testa se um arquivo ou diretório existe.
public long length()
Retorna o tamanho do arquivo.
public long lastModified()
Retorna a data em milissegundos quando o arquivo foi modificado pela última vez.
public boolean canRead()
Retorna true se é permitido ler a partir do arquivo. De outro modo, retorna false.
public boolean canWrite()
Retorna true se é permitido escrever ao arquivo. De outro modo, retorna false.
public boolean isFile()
Testa se este objeto é um arquivo, ou seja, nossa normal percepção do que é um
arquivo (não um diretório).
public boolean isDirectory()
Testa se este objeto é um diretório.
public String[] list()
Retorna a lista de arquivos e sub-diretórios contidos neste objeto. Este objeto deveria
ser um diretório.
public void mkdir()
Cria um diretório denotado por este caminho abstrato.
public void delete()
Remove o arquivo ou diretório representado por este objeto File.
Tabela 2: Métodos da classe File

Introdução à programação II 6
JEDITM

Veremos como estes métodos trabalham, através da classe a seguir:

import java.io.*;

public class FileDemo {


public static void main(String args[]) {
String fileName = "temp.txt";
File fn = new File(fileName);
System.out.println("Name: " + fn.getName());
if (!fn.exists()) {
System.out.println(fileName + " does not exists.");
/* Cria um diretório temporário. */
System.out.println("Creating temp directory...");
fileName = "temp";
fn = new File(fileName);
fn.mkdir();
System.out.println(fileName +
(fn.exists()? "exists": "does not exist"));
System.out.println("Deleting temp directory...");
fn.delete();
System.out.println(fileName +
(fn.exists()? "exists": "does not exist"));
return;
}
System.out.println(fileName + " is a " +
(fn.isFile()? "file." :"directory."));
if (fn.isDirectory()) {
String content[] = fn.list();
System.out.println("The content of this directory:");
for (int i = 0; i < content.length; i++) {
System.out.println(content[i]);
}
}
if (!fn.canRead()) {
System.out.println(fileName + " is not readable.");
return;
}
System.out.println(fileName + " is " + fn.length() +
" bytes long.");
System.out.println(fileName + " was last modified on " +
fn.lastModified() + ".");
if (!fn.canWrite()) {
System.out.println(fileName + " is not writable.");
}
}
}

Este é o resultado da execução da classe FileDemo:

Name: temp.txt
temp.txt is a file.
temp.txt is 34 bytes long.
temp.txt was last modified on 1149150489177.

temp.txt, deve ser colocado no diretório raiz do seu projeto e contém o seguinte texto:

what a wonderful world


1, 2, step

Introdução à programação II 7
JEDITM

4. Classe Reader
Esta seção descreve Stream de caracteres que são utilizados para leitura.

4.1. Métodos de Reader


A classe Reader consiste de diversos métodos para leitura de caracteres. Aqui estão alguns dos
métodos desta classe:

Métodos da Classe Reader


public int read(-) throws IOException
Possui três versões. Lê caractere(s), uma matriz inteira de caracteres, ou uma porção
de uma matriz de caracteres.
public int read() - Lê um único caracter.
public int read(char[] cbuf)- Lê caracteres e os armazena na matriz de caracteres
cbuf.
public abstract int read(char[] cbuf, int offset, int length)- Lê até length
número de caracteres e os armazena na matriz de caracteres cbuf começando no offset
especificado.
public abstract void close() throws IOException
Fecha este Stream. Chamar os outros métodos Reader após fechar o Stream iria causar
a ocorrência de uma exceção IOException.
public void mark(int readAheadLimit) throws IOException
Marca a posição atual no Stream. Após marcar, chamadas ao método reset() irão tentar
reposicionar o Stream neste ponto. Nem todos os Stream de entrada de caracteres
suportam esta operação.
public boolean markSupported()
Indica se um Stream suporta a operação de marca ou não. Não é suportado por padrão.
Não deveria ser sobrescrito por subclasses.
public void reset() throws IOException
Reposiciona o Stream na última posição marcada.
Tabela 3: Métodos da classe Reader

4.2. Subclasses de Reader


A seguir temos algumas das subclasses de Reader:

Subclasses de Reader
FileReader
Para leitura a partir de arquivos de caracteres.
CharArrayReader
Implementa um buffer de caracteres a partir do qual pode-se ler.
StringReader
Para leitura a partir de uma String.
PipedReader

Introdução à programação II 8
JEDITM

Usado em pares (com um correspondente PipedWriter) por duas tarefas que queiram
comunicar-se. Uma destas tarefas lê caracteres a partir desta fonte.
Tabela 4: Subclasses de Reader

4.3. Subclasses de FilterReader


Para adicionar funcionalidades às classes Reader básicas, é possível utilizar as subclasses
FilterReader. Aqui estão algumas destas subclasses:

Subclasses de FilterReader
BufferedReader
Permite o armazenamento de caracteres em um buffer, de forma a prover uma eficiente
leitura de caracteres, matrizes, e linhas.
FilterReader
Para ler Stream de caracteres filtrados.
InputStreamReader
Converte bytes lidos em caracteres.
LineNumberReader
Uma subclasse da classe BufferedReader que é capaz de manter registro do número das
linhas.
PushbackReader
Uma subclasse da classe FilterReader que permite que caracteres sejam devolvidos ou
não copiados ao Stream.
Tabela 5: Subclasses de FilterReader

Introdução à programação II 9
JEDITM

5. Classe Writer
Nesta seção descrevemos os Stream de caracteres que são utilizados para escrita.

5.1. Métodos de Writer


A classe Writer consiste de diversos métodos para escrita de caracteres. Aqui estão alguns dos
métodos desta classe:

Métodos da classe Writer


public void write(-) throws IOException
Possue cinco versões:
public void write(int c) – Escreve um único caracter representado pelo valor
inteiro dado.
public void write(char[] cbuf) – Escreve o conteúdo da matriz de caracteres cbuf.
public abstract void write(char[] cbuf, int offset, int length) – Escreve
length número de caracteres a partir da matriz cbuf , começando no offset especificado.
public void write(String str) – Escreve a string string.
public void write(String str, int offset, int length) – Escreve length número
de caracteres a partir da string str, começando no offset especificado.
public abstract void close() throws IOException
Fecha este Stream após descarregar quaisquer caracteres que não tenham sido
escritos. Invocação de outros métodos depois de fechar este Stream iriam causar a
ocorrência de uma exceção IOException.
public abstract void flush()
Descarrega o Stream (ex., caracteres salvos no buffer são imediatamente escritos à
destinação pretendida).
Tabela 6: Métodos da classe Writer

5.2. Subclasses de Writer


A seguir temos algumas das subclasses de Writer:

Subclasses de Writer
FileWriter
Para escrever caracteres a um arquivo.
CharArrayWriter
Implementa um buffer de caracteres para o qual pode-se escrever.
StringWriter
Para escrever em uma String.
PipedWriter
Usado em pares (com um correspondente PipedReader) por duas tarefas que queiram
comunicar-se. Uma destas tarefas escreve caracteres a este Stream.
Tabela 7: Subclasses de Writer

Introdução à programação II 10
JEDITM

5.3. Subclasses de FilterWriter


Para adicionar funcionalidades às classes Writer básicas, é possível utilizar as subclasses
FilterWriter. Aqui estão algumas destas classes:

Subclasses de FilterWriter
BufferedWriter
Permite o uso de buffers de caracteres de forma a prover eficiente escrita de caracteres,
matrizes, e linhas.
FilterWriter
Para escrever Stream de caracteres filtrados.
OutputStreamWriter
Codifica caracteres escritos a ele em bytes.
PrintWriter
Imprime representações formatadas dos objetos a um Stream de saída de texto.
Tabela 8: Subclasses de Filter Writer

Introdução à programação II 11
JEDITM

6. Um Exemplo de Reader/Writer
O exemplo a seguir utiliza as classes FileReader e FileWriter para ler a partir de um arquivo
especificado pelo usuário e copiar o conteúdo deste para um outro arquivo:

import java.io.*;

class CopyDemo {
private void copy(String input, String output) {
FileReader reader;
FileWriter writer;
int data;
try {
reader = new FileReader(input);
writer = new FileWriter(output);
while ((data = reader.read()) != -1) {
writer.write(data);
}
reader.close();
writer.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}

public static void main(String args[]) {


CopyDemo cf = new CopyDemo();
cf.copy("temp.txt", "temp2.txt");
}
}

Execute a classe e observe o que acontece com os arquivos manipulados.

Usando temp.txt a partir de nosso exemplo anterior, aqui está o resultado quando passamos
temp.txt como o inputFile e temp2.txt como o outputFile:

Figura 1: Saída de dados para CopyFile

Introdução à programação II 12
JEDITM

7. Exemplo Reader/Writer modificado


O exemplo a seguir é similar ao anterior, entretanto é mais eficiente. Ao invés de ler e escrever
um Stream de cada vez, caracteres lidos são primeiramente armazenados em um buffer antes de
que caracteres sejam escritos linha por linha. O programa usa a técnica de encadeamento de
Stream desde que as classes FileReader e FileWriter sejam decoradas com as classes
BufferedReader e BufferedWriter, respectivamente:

import java.io.*;

class CopyDemo {
void copy(String input, String output) {
BufferedReader reader;
BufferedWriter writer;
String data;
try {
reader = new BufferedReader(new FileReader(input));
writer = new BufferedWriter(new FileWriter(output));
while ((data = reader.readLine()) != null) {
writer.write(data, 0, data.length());
}
reader.close();
writer.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}

public static void main(String args[]) {


CopyDemo cf = new CopyDemo();
cf.copy("temp.txt", "temp2.txt");
}
}

Aqui está o resultado desta versão de CopyDemo.

Figura 2: Saída de Dados para CopyDemo

Introdução à programação II 13
JEDITM

8. Classe InputStream
Esta seção dá uma visão geral dos diferentes Stream de bytes que são utilizados para leitura.

8.1. Métodos de InputStream


A classe InputStream consiste em diversos métodos para leitura de bytes. Aqui estão alguns dos
métodos desta classe:

Métodos da classe InputStream


public int read(-) throws IOException
Um método sobrecarregado, o qual também tem três versões como as da classe
Reader. Lê bytes.
public abstract int read() - Lê o próximo byte de dados a partir deste Stream.
public int read(byte[] bBuf)- Lê certo número de bytes e os armazena na matriz
de bytes bBuf.
public abstract int read(char[] cbuf, int offset, int length)- Lê até length
número de bytes e os armazena na matriz de bytes bBuf começando no offset
especificado.
public abstract void close() throws IOException
Fecha este Stream. Chamar os outros métodos InputStream após ter fechado o Stream
iria causar a ocorrência de uma exceção IOException.
public void mark(int readAheadLimit) throws IOException
Marca a posição atual no Stream. Após marcar, chamadas ao método reset() irão tentar
reposicionar o Stream neste ponto. Nem todos os Stream de entrada de bytes suportam
esta operação.
public boolean markSupported()
Indica se um Stream suporta as operações marca e limpeza. Não suportado por padrão.
Deve ser feito override pelas subclasses.
public void reset() throws IOException
Reposiciona o Stream na última posição marcada.
Tabela 9: Métodos da classe InputStream

8.2. Subclasses de InputStream


As seguintes são algumas das subclasses de InputStream:

Subclasses de InputStream
FileInputStream
Para leitura de bytes a partir de um arquivo.
BufferedInputStream
Implementa um buffer que contém bytes, os quais podem ser lidos a partir do Stream.
PipedInputStream
Deveria estar conectado a um PipedOutputStream. Estes Stream são tipicamente
usados por duas tarefas desde que um destas tarefas leia dados a partir desta fonte
enquanto a outra tarefa escreve ao correspondente PipedOutputStream.
Tabela 10: Subclasses de InputStream

Introdução à programação II 14
JEDITM

8.3. Subclasses de FilterInputStream


Para adicionar funcionalidades às classes InputStream básicas, utilizamos as subclasses de
FilterInputStream. Aqui estão algumas destas subclasses:

Subclasses de FilterInputStream
BufferedInputStream
Uma subclasse de FilterInputStream que permite o uso de um buffer de entrada de
forma a prover a eficiente leitura de bytes.
FilterInputStream
Para ler Stream de bytes filtrados, os quais podem transformar a fonte básica de dados
no decorrer do processo e prover funcionalidades adicionais.
ObjectInputStream
Usado para serialização de objetos. De-serializa objetos e dados primitivos previamente
escritos usando um ObjectOutputStream.
DataInputStream
Uma subclasse de FilterInputStream que permite que uma aplicação leia dados Java
primitivos a partir de um Stream de entrada de dados subjacente, independente do tipo
de máquina.
LineNumberInputStream
Uma subclasse de FilterInputStream que permite monitorar o número de linha atual.
PushbackInputStream
Uma subclasse da classe FilterInputStream que permite que bytes sejam devolvidos ou
não transferidos ao Stream.
Tabela 11: Subclasses de Filter InputStream

Introdução à programação II 15
JEDITM

9. Classe OutputStream
Esta seção dá uma visão geral dos diferentes Stream de bytes que são utilizados para escrita.

9.1. Métodos de OutputStream


A classe OutputStream consiste em diversos métodos para escrever bytes. Aqui estão alguns dos
métodos desta classe:

Métodos da classe OutputStream


public void write(-) throws IOException
Um método sobrecarregado para escrever bytes ao Stream. Ele tem três versões:
public abstract void write(int b) – Escreve o valor em bytes b especificado a este
Stream de saída de dados.
public void write(byte[] bBuf) – Escreve o conteúdo da matriz de bytes bBuf neste
Stream.
public void write(byte[] bBuf, int offset, int length) – Escreve length
número de bytes a partir da matriz bBuf neste Stream, começando pelo offset
especificado para este Stream.
public abstract void close() throws IOException
Fecha este Stream e libera quaisquer recursos do sistema associados com este Stream.
Invocação de outros métodos após chamar este método iria causar a ocorrência de uma
exceção IOException.
public abstract void flush()
Descarrega o Stream (ex., bytes salvos no buffer são imediatamente escritos à
destinação pretendida).
Tabela 12: Métodos da classe OutputStream

9.2. Subclasses de OutputStream


As seguintes são algumas das subclasses de OutputStream:

Subclasses de OutputStream
FileOutputStream
Para escrever bytes a um arquivo.
BufferedOutputStream
Implementa um buffer que contém bytes, os quais podem ser escritos no Stream.
PipedOutputStream
Deveria estar conectado a um PipedInputStream. Estes Stream são tipicamente usados
por duas tarefas desde que uma destas escreva dados a este Stream enquanto a outra
tarefa lê a partir do correspondente PipedInputStream.
Tabela 13: Subclasses de OutputStream

Introdução à programação II 16
JEDITM

9.3. Subclasses de FilterOutputStream


Para adicionar funcionalidades às classes OutputStream básicas, utilizamos as subclasses de
Filter Stream. Aqui estão algumas destas subclasses:

Subclasses de FilterOutputStream
BufferedOutputStream
Uma subclasse de FilterOutputStream que permite o uso de buffers de saída de forma a
prover uma eficiente escrita de bytes. Permite escrever bytes ao Stream de saída de
dados subjascente sem necessariamente causar uma chamada ao sistema subjascente
para cada byte escrito.
FilterOutputStream
Para escrever Stream de bytes filtrados, os quais podem transformar a fonte de dados
básica ao longo do processo e prover funcionalidades adicionais.
ObjectOutputStream
Usado para serialização de objetos. Serializa objetos e dados primitivos a um
OutputStream.
DataOutputStream
Uma subclasse de FilterOutputStream que permite que uma aplicação escreva dados
Java primitivos a um Stream de saída de dados subjascent, independentemente do tipo
de máquina.
PrintStream
Uma subclasse de FilterOutputStream que provê capacidade para imprimir
representações de diversos valores de dados convenientemente.
Tabela 14: Classes Filter OutputStream

Introdução à programação II 17
JEDITM

10. Um Exemplo de InputStream/OutputStream


O exemplo a seguir utiliza as classes FileInputStream e FileOutputStream para ler a partir de um
arquivo especificado pelo usuário e copiar o conteúdo deste para um outro arquivo:

import java.io.*;

class CopyDemo {
void copy(String input, String output) {
FileInputStream inputStr;
FileOutputStream outputStr;
int data;
try {
inputStr = new FileInputStream(input);
outputStr = new FileOutputStream(output);
while ((data = inputStr.read()) != -1) {
outputStr.write(data);
}
inputStr.close();
outputStr.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}

public static void main(String args[]) {


CopyDemo cf = new CopyDemo();
cf.copy("temp.txt", "temp2.txt");
}
}

Aqui está o resultado da execução desta classe:

Figura 3: Saída de dados para CopyFile

Introdução à programação II 18
JEDITM

11. Exemplo InputStream/OutputStream Modificado


Este exemplo utiliza a classe PushbackInputStream que decora um objeto FileInputStream
usando a classe PrintStream.

import java.io.*;

class CopyDemo {
void copy(String input) {
PushbackInputStream inputStr;
PrintStream outputStr;
int data;
try {
inputStr = new PushbackInputStream(new
FileInputStream(input));
outputStr = new PrintStream(System.out);
while ((data = inputStr.read()) != -1) {
outputStr.println("read data: " + (char) data);
inputStr.unread(data);
data = inputStr.read();
outputStr.println("unread data: " + (char) data);
}
inputStr.close();
outputStr.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}

public static void main(String args[]) {


CopyDemo cf = new CopyDemo();
cf.copy("temp.txt");
}
}

Teste este código em um arquivo contendo algumas poucas linhas ou caracteres. Supondo um
arquivo chamado temp.txt contendo o seguinte texto:

one 1
two

Ao executarmos esta classe obteremos a seguinte saída:

read data: o unread data:


unread data: o read data:
read data: n
unread data: n unread data:
read data: e
unread data: e read data: t
read data: unread data: t
unread data: read data: w
read data: 1 unread data: w
unread data: 1 read data: o
read data: unread data: o

Introdução à programação II 19
JEDITM

12. Serialização
A Máquina Virtual Java ou JVM possui a habilidade de ler ou escrever um objeto a um Stream.
Esta capacidade é chamada Serialização, corresponde ao processo de "achatar" um objeto de
forma tal que o mesmo possa ser salvo a uma fonte de armazenamento permanente ou passado
a outro objeto via a classe OutputStream. Ao escrever um objeto, é importante que o seu estado
seja escrito em uma forma serializada de tal modo que o objeto possa ser reconstruído conforme
o mesmo está sendo lido. Salvar um objeto a alguma forma de armazenamento permanente é
conhecido como persistência.

Os Stream podem ser utilizados para de-serializar e re-serializar. São representados


respectivamente pelas classes ObjectInputStream e ObjectOutputStream.

Para permitir que um objeto seja serializável (isto é, possa ser salvo e recuperado), a classe deve
implementar a interface Serializable. A classe também deve prover um construtor padrão (ou um
construtor sem argumentos). Uma das coisas interessantes a respeito de serialização é que a
mesma é herdada, o que significa que não precisamos implementar Serializable em cada classe.
Isso significa menos trabalho para os programadores. É possível simplesmente implementar
Serializable uma única vez ao longo da hierarquia de classes.

12.1. A Palavra-chave transient


Quando um objeto é serializado, apenas os dados do objeto são preservados. Métodos e
construtores não são parte do Stream serializado. Há, no entanto, alguns objetos que não são
serializáveis porque os dados que eles representam mudam constantemente. Alguns exemplos de
tais objetos são FileInputStream e Thread. Uma exceção NotSerializableException é lançada se a
operação de serialização falhar por qualquer motivo.

Não há necessidade em se desesperar. Uma classe contendo um objeto não serializável ainda
pode ser serializada se a referência e este objeto não serializável for marcada com a palavra-
chave transient. Considere o seguinte exemplo:

class MyClass implements Serializable {


transient Thread thread; //tente remover transient
int data;
/* alguns outros dados */
}

A palavra-chave transient previne que os dados associados sejam serializados. Objetos


instanciados a partir desta classe podem agora ser escritos a um OutputStream.

12.2. Serialização: Escrevendo um Stream de Objetos


Para escrever um objeto a um Stream, é necessário utilizar a classe ObjectOutputStream e seu
método writeObject. O método writeObject tem a seguinte assinatura:

public final void writeObject(Object obj) throws IOException

onde obj é o objeto que será escrito ao Stream.

O exemplo abaixo escreve um objeto Boolean a um ObjectOutputStream. A classe Boolean


implementa a interface Serializable. Deste modo, os objetos instanciados a partir desta classe
podem ser escritos e lidos a partir de um Stream.

import java.io.*;

Introdução à programação II 20
JEDITM

public class SerializeDemo {


public SerializeDemo() {
Boolean booleanData = new Boolean("true");
try {
FileOutputStream fos = new
FileOutputStream("boolean.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(booleanData);
oos.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}
public static void main(String args[]) {
new SerializeDemo();
}
}

12.3. De-serialização: Lendo um Stream de Objetos


Para ler um objeto a partir de um Stream, é necessário utilizar a classe ObjectInputStream e seu
método readObject. O método readObject tem a seguinte assinatura:

public final Object readObject()


throws IOException, ClassNotFoundException

onde obj é o objeto a ser lido a partir do Stream.

O tipo Object retornado deveria sofrer typecasting ao nome de classe apropriado antes que
métodos naquela classe possam ser executados.

O exemplo abaixo lê um objeto Boolean a partir de um ObjectInputStream. Esta é uma


continuação do exemplo anterior que tratava de serialização.

import java.io.*;

public class UnserializeDemo {


public UnserializeDemo() {
Boolean booleanData = null;
try {
FileInputStream fis = new
FileInputStream("boolean.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
booleanData = (Boolean) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Unserialized Boolean from " +
"boolean.txt");
System.out.println("Boolean data: " + booleanData);
System.out.println("Compare data with true: " +
booleanData.equals(new Boolean("true")));
}
public static void main(String args[]) {
new UnserializeDemo();
}
}

O seguinte é a saída de dados esperada de UnserializeBoolean:

Introdução à programação II 21
JEDITM

Unserialized Boolean from boolean.ser


Boolean data: true
Compare data with true: true

Introdução à programação II 22
Módulo 2
Introdução à Programação II

Lição 13
Introdução à Generics

Versão 1.0 - Mar/2007


JEDITM

1. Objetivos
A versão 5 do Java trouxe grandes avanços na programação. Inclui extensões significantes à
sintaxe da linguagem. A mais visível delas foi a adição de Generics. Nessa lição iremos
conhecer os conceitos básicos relacionados a Generics.

Ao final desta lição, o estudante será capaz de:

• Enumerar os benefícios de Generics


• Declarar classes utilizando Generics
• Utilizar Generics limitados
• Declarar métodos utilizando Generics
• Usar coleções Java com Generics

Introdução à Programação II 4
JEDITM

2. Por que Generics?


Um dos maiores problemas na linguagem de programação Java é a necessidade constante de
fazer typecast ou casting (conversões de tipo explícitas) em expressões para tipos de dados
mais específicos do que seus tipos estáticos. Por exemplo, um objeto ArrayList permite
adicionarmos objetos de qualquer tipo de referência à coleção, mas quando recuperarmos
estes elementos, precisaremos fazer um typecast nos objetos para o tipo de referência
específico à nossa necessidade. O casting é um perigo em potencial para gerar uma
ClassCastException. Ele também torna nossos códigos mais poluídos e, portanto, menos
legíveis. Além disso, o casting efetivamente destrói os benefícios de uma linguagem com os
tipos fortemente definidos, uma vez que anula a segurança trazida pela checagem embutida
de tipos.

O principal objetivo da adição de Generics ao Java é solucionar este problema. Tipos Generics
permite que uma única classe trabalhe com uma grande variedade de tipos. Eles são uma
forma natural de se eliminar a necessidade do cast.

Primeiro iremos considerar um objeto ArrayList e ver como os tipos Generics ajudariam a
melhorar nosso código. Um objeto ArrayList possui a capacidade de armazenar elementos de
qualquer tipo de referência em uma coleção de objetos. Uma instância de ArrayList,
entretanto, sempre força a realizar um casting nos objetos que recuperamos da coleção.
Considere a seguinte linha de instrução:

String myString = (String) myArrayList.get(0);

A versão utilizando Generics, da classe ArrayList foi desenvolvida para trabalhar nativamente
com qualquer tipo de classe. Ao mesmo tempo, ela também preserva os benefícios da
checagem de tipos. Podemos eliminar a necessidade do casting no elemento que obtemos da
coleção e ter a seguinte linha de instrução:

String myString = myArrayList.get(0);

Embora o casting já tenha sido removido, isso não significa que possamos atribuir qualquer
tipo ao valor de retorno do método get e eliminar o casting também. Ao atribuir outra coisa
que não uma String à saída do método get, obteremos um erro de equiparação de tipos em
tempo de compilação tal como essa mensagem:

found: java.lang.String
required: java.lang.Integer
Integer data = myArrayList.get(0);

Para se ter uma idéia de como Generics é usado, antes de entrarmos em mais detalhes,
considere o seguinte fragmento de código:

ArrayList <String> genArrList = new ArrayList <String>();


genArrList.add("A generic string");
String myString = genArrList.get(0);
JoptionPane.showMessageDialog(this, myString);

Analisando estas instruções, observamos a palavra <String> aparecendo imediatamente após


a referência do tipo ArrayList. Podemos interpretar esta como o primeiro comando da criação
de uma instância de uma versão da classe ArrayList utilizando Generics, e esta versão contém
objetos do tipo String. genArrList está preso ao tipo String. Portanto, “prender” um Integer ou
outro tipo não String ao resultado da função get seria ilegal. A próxima instrução não seria
válida:

int myInt = genArrList.get();

Introdução à Programação II 5
JEDITM

3. Declarando uma Classe Utilizando Generics


Para que o fragmento de código anterior funcione, deveríamos ter definido uma versão da
classe ArrayList que utilize Generics. Felizmente, a versão mais recente do Java fornece aos
usuários versões que fazem uso de Generics para todas as implementações de Collection.
Nessa seção, aprenderemos como declarar sua própria classe utilizando Generics.

Ao invés de uma longa discussão sobre como declarar uma classe utilizando Generics, veremos
um exemplo:

class BasicGeneric <A> {


private A data;
public BasicGeneric(A data) {
this.data = data;
}
public A getData() {
return data;
}
}
public class GenericDemo {
public String method(String input) {
String data1 = input;
BasicGeneric <String> basicGeneric = new
BasicGeneric <String>(data1);
String data2 = basicGeneric.getData();
return data2;
}
public Integer method(int input) {
Integer data1 = new Integer(input);
BasicGeneric <Integer> basicGeneric = new
BasicGeneric <Integer>(data1);
Integer data2 = basicGeneric.getData();
return data2;
}
public static void main(String args[]) {
GenericDemo sample = new GenericDemo();
System.out.println(sample.method("Some generic data"));
System.out.println(sample.method(1234));
}
}

Na execução desta classe será mostrada a seguinte saída:

Some generic data


1234

Iremos agora passar pelas instruções que possuem a sintaxe que utilizam Generics.

Para a declaração da classe BasicGeneric:

class BasicGeneric <A>

o nome da classe é seguido por um par de sinais “menor que” e “maior que” envolvendo a
letra maiúscula A: <A>. Isto é chamado de um parâmetro de tipo. Os usos desses sinais
“menor que” e “maior que” indicam que a classe declarada é uma classe que utiliza Generics.
Isso significa que a classe não trabalha com nenhuma referência a um tipo específico. Por isso,
observe que o atributo da classe foi declarado para ser do tipo A:

private A data;

Introdução à Programação II 6
JEDITM

Essa declaração especifica que o atributo data é de um tipo Generic, e depende do tipo de
dado com que o objeto BasicGeneric for desenvolvido para trabalhar.

Quando declarar uma instância da classe, deve ser especificada a referência ao tipo com que
se deseja trabalhar. Por exemplo:

BasicGeneric <String> basicGeneric = new BasicGeneric <String>(data1);

A sintaxe <String> após a declaração de BasicGeneric especifica que essa instância da classe
irá trabalhar com variáveis do tipo String.

Podemos trabalhar com variáveis do tipo Integer ou qualquer outro tipo de referência. Para
trabalhar com um Integer, o fragmento do código teria a seguinte instrução:

BasicGeneric <Integer> basicGeneric = new BasicGeneric <Integer>(data1);

Consideremos a declaração para o método getData:

public A getData() {
return data;
}

O método getData retorna um valor do tipo A, que é um tipo Generic. Isso significa que o
método terá um tipo de dado em tempo de execução, ou mesmo em tempo de compilação.
Depois de declarar um objeto do tipo BasicGeneric, A será “preso” a um tipo de dado
específico. Essa instância atuará como se tivesse sido declarada para ter esse tipo de dado
específico, e apenas esse, desde o início.

No seguinte código, duas instâncias da classe BasicGeneric foram criadas.

BasicGeneric <String> basicGeneric = new BasicGeneric <String>(data1);


String data2 = basicGeneric.getData();

BasicGeneric <Integer> basicGeneric = new BasicGeneric <Integer>(data1);


Integer data2 = basicGeneric.getData();

Note que a criação de uma instância de uma classe que utiliza Generics é bem similar à criação
de uma classe normal, exceto pelo tipo de dado específico dentro dos sinais <> logo após o
nome do construtor. Essa informação adicional indica o tipo de dado com que você trabalhará
para essa instância da classe BasicGeneric em particular. Depois de criada a instância, é
possível agora acessar os elementos da classe através dela. Não existe mais a necessidade do
typecast no valor do retorno do método getData, uma vez que já foi decidido que ele irá
trabalhar com um tipo de dado de referência específico.

3.1. Limitação "Primitiva"


Uma limitação de Generics em Java, é que eles são restritos a tipos de referência (Objetos) e
não funcionarão com tipos primitivos.

Por exemplo, o comando a seguir seria ilegal, uma vez que int é um tipo de dado primitivo.

BasicGeneric <int> basicGeneric = new


BasicGeneric <int>(data1);

Você terá que encapsular os tipos primitivos primeiro, antes de usá-los como argumentos
Generics.

Introdução à Programação II 7
JEDITM

3.2. Compilando Generics

Para compilar códigos fonte Java com Generics usando JDK (v. 1.5.0), utilize a seguinte
sintaxe:

javac -version -source "1.5" -sourcepath src -d classes


src/SwapClass.java

onde src refere-se à localização do código fonte java, enquanto class refere-se à localização
onde o arquivo da classe será gravado.

Aqui está um exemplo:

javac -version -source "1.5" -sourcepath c:\temp -d c:\temp


c:/temp/SwapClass.java

Introdução à Programação II 8
JEDITM

4. Generics Limitados
No exemplo mostrado anteriormente, os parâmetros de tipo da classe BasicGeneric podem ser
de qualquer tipo de dado de referência. Há casos, entretanto, onde você quer restringir os
tipos em potencial usados em instanciações de uma classe do tipo Generics. Java permite
limitar o conjunto de possíveis tipos utilizados como argumento na instanciação de classes
desse tipo, para um conjunto de subtipos de um determinado tipo “amarrado” à classe.

Por exemplo, podemos definir uma classe ScrollPane que utiliza Generics que serviria como um
molde para um Container comum com a funcionalidade da barra de rolagem. Em tempo de
execução, o tipo da instância dessa classe será, geralmente, uma subclasse de Container, mas
o tipo estático ou geral é simplesmente Container.

Para limitar as instanciações de tipo de uma classe, nós usamos a palavra-chave extends
seguida pela classe que limita (ou restringe) o tipo Generics como parte de um parâmetro de
tipo.

O exemplo a seguir limita as instanciações de tipo da classe ScrollPane para subtipos da classe
Container.

class ScrollPane <MyPane extends Container> {


...
}
class TestScrollPane {
public static void main(String args[]) {
ScrollPane <Panel> scrollPane1 = new ScrollPane <Panel>();
// O comando seguinte é ilegal
ScrollPane <Button> scrollPane2 = new ScrollPane <Button>();
}
}

A instanciação de scrollPane1 é válida, uma vez que Panel é uma subclasse de Container,
enquanto a criação de scrollPane2 causaria um erro em tempo de compilação, uma vez que
Button não é uma subclasse de Container.

Usar Generics limitados nos dá um adicional, que é a checagem estática de tipos. Como
resultado, nós temos a garantia que toda instanciação de um tipo Generics respeita os limites
(ou restrições) que atribuímos a ele.

Uma vez que asseguramos que toda instância de tipo é uma subclasse do limite atribuído,
podemos chamar, de forma segura, qualquer método encontrado no tipo estático do objeto. Se
não tivéssemos colocado nenhum limite explícito no parâmetro, o limite default seria Object.
Isso significa que não podemos invocar métodos em uma instância do limite que não apareçam
na classe Object.

Introdução à Programação II 9
JEDITM

5. Declarando Métodos Generics


Além de declarar classe Generics, também podemos declarar métodos Generics. Estes
métodos são chamados polimórficos, e são definidos para serem métodos parametrizados pelo
tipo.

Parametrizar métodos é útil quando queremos realizar tarefas onde as dependências de tipo
entre os argumentos e o valor de retorno são Generics, mas não depende de nenhuma
informação do tipo da classe, e mudará a cada chamada ao método.

Por exemplo, suponha que queremos adicionar um método make em uma classe ArrayList.
Este método estático admitiria um único argumento, que seria o único elemento do objeto
ArrayList. Para fazer com que nosso ArrayList receba qualquer tipo de elemento, o argumento
e o retorno do método make deve utilizar Generics.

Para declarar tipos Generics no nível de métodos, considere o exemplo a seguir:

class Utilities {
/* T extends Object implicitamente */
public static <T> ArrayList<T> make(T first) {
return new ArrayList<T>(first);
}
}

Java também utiliza um mecanismo de inferência de tipos, para inferir automaticamente os


tipos dos métodos polimórficos baseado no tipo dos argumentos. Isso diminui o excesso de
palavras, e a complexidade nas invocações de métodos.

Para construir uma nova instância de ArrayList<Integer>, nós simplesmente teríamos o


seguinte comando:

Utilities.make(Integer(0));

Introdução à Programação II 10
JEDITM

6. Generics e Coleções Java


Uma discussão sobre métodos da interface Collection já foi mostrada em lições anteriores.
Entretanto, no JDK 5.0, esses métodos foram atualizados para acomodar Generics. A tabela a
seguir mostra os métodos do JDK 5.0 equivalentes àqueles que você estudou anteriormente.

Métodos da interface Collection


public boolean add(E o)
Insere o elemento específico o nessa coleção. Retorna true se o foi adicionado com
sucesso à coleção.
public void clear()
Remove todos os elementos dessa coleção.
public boolean remove(Object o)
Remove uma única instância de Object o dessa coleção, se ele estiver presente.
Retorna true se o foi encontrado e removido da coleção.
public boolean contains(Object o)
Retorna true se essa coleção contém o Object o.
public boolean isEmpty()
Retorna true se essa coleção não contém nenhum objeto ou elemento.
public int size()
Retorna o número de elementos nessa coleção.
public Iterator<E> iterator()
Retorna um iterator que nos permite acessar elementos da coleção.
public boolean equals(Object o)
Retorna true se o Object o é igual a essa coleção.
public int hashCode()
Retorna o valor do hash code (i.e., o ID) para essa coleção. Mesmos objetos ou
coleções têm o mesmo valor de hash code ou ID.
Table 1: métodos da interface Collection

Aqui está um exemplo de uma classe que não utiliza a versão Generics para a criação de uma
lista, observe que podemos incluir sem problemas um objeto String entre os outros elementos

import java.util.*;

class GenericDemo {
public static void main(String args[]) {
List list = new ArrayList();
list.add(new Integer(1));
list.add(new Integer(2));
list.add("String");
System.out.println(list);
Collections.sort(list);
System.out.println(list);
}
}

Executar esta classe é gerada a seguinte saída:

[1, 2, String]
Exception in thread "main" java.lang.ClassCastException:
java.lang.String
at java.lang.Integer.compareTo(Integer.java:35)
at java.util.Arrays.mergeSort(Arrays.java:1156)
at java.util.Arrays.sort(Arrays.java:1080)
at java.util.Collections.sort(Collections.java:117)
at GenericDemo.main(GenericDemo.java:10)
Java Result: 1
Pelo simples motivo que o Java não sabe como ordenar uma String juntamente com dois

Introdução à Programação II 11
JEDITM

objetos inteiros, agora vejamos a mesma classe utilizando agora o Generics:

import java.util.*;

class GenericDemo {
public static void main(String args[]) {
List<Integer> list = new ArrayList<Integer>();
list.add(new Integer(1));
list.add(new Integer(2));
list.add("String");
System.out.println(list);
Collections.sort(list);
System.out.println(list);
}
}

O que acontecerá será um erro de compilação na linha 8, ou seja, o Generics bloqueia os


elementos estranhos a lista não permitindo que esta tenha elementos diversos fora o
especificado.

Introdução à Programação II 12
JEDITM

Parceiros que tornaram JEDITM possível

Instituto CTS
Patrocinador do DFJUG.

Sun Microsystems
Fornecimento de servidor de dados para o armazenamento dos vídeo-aulas.

Java Research and Development Center da Universidade das Filipinas


Criador da Iniciativa JEDITM.

DFJUG
Detentor dos direitos do JEDITM nos países de língua portuguesa.

Banco do Brasil
Disponibilização de seus telecentros para abrigar e difundir a Iniciativa JEDITM.

Politec
Suporte e apoio financeiro e logístico a todo o processo.

Borland
Apoio internacional para que possamos alcançar os outros países de língua
portuguesa.

Instituto Gaudium/CNBB
Fornecimento da sua infra-estrutura de hardware de seus servidores para que
os milhares de alunos possam acessar o material do curso simultaneamente.

Introdução à Programação II 13