Você está na página 1de 192

UNIVERSIDADE DE SO PAULO INSTITUTO DE MATEMTICA E ESTATSTICA Departamento de Cincia da Computao

Introduo Cincia da Computao com Java e Orientao a Objetos


1a edio

Alfredo Goldman Fabio Kon Paulo J. S. Silva


Editado e Revisado por: Raphael Y. de Camargo

Ficha Catalogrca Elaborada pela Biblioteca do IME-USP

QA724 K82i

Kon, Fabio; Goldman, Alfredo; Silva P. J. S. Introduo cincia da computao com Java e orientao a objetos, editado e revisado por Raphael Y. de Camargo. 1. ed. So Paulo : IME-USP, 2006. 190p. ISBN: 85-88697-10-6 1. Linguagem de Programao 2. Programao orientada a objeto 3. Java I. Goldman, Alfredo II. Silva, Paulo J. S. III. Camargo, Raphael Y. de, ed. e rev. IV. Universidade de So Paulo, Instituto de Matemtica e Estatstica. Departamento de Cincia da Computao.

CDD 600

Atribuio-Uso No-Comercial-Compartilhamento pela mesma licena 2.5 Voc pode: copiar, distribuir, exibir e executar a obra criar obras derivadas Sob as seguintes condies: Atribuio. Voc deve dar crdito ao autor original, da forma especicada pelo autor ou licenciante.

Uso No-Comercial. Voc no pode utilizar esta obra com nalidades comerciais.

Compartilhamento pela mesma Licena. Se voc alterar, transformar, ou criar outra obra com base nesta, voc somente poder distribuir a obra resultante sob uma licena idntica a esta. Para cada novo uso ou distribuio, voc deve deixar claro para outros os termos da licena desta obra. Qualquer uma destas condies podem ser renunciadas, desde que Voc obtenha permisso do autor. Qualquer direito de uso legtimo (ou "fair use") concedido por lei, ou qualquer outro direito protegido pela legislao local, no so em hiptese alguma afetados pelo disposto acima.

Este um sumrio para leigos da Licena Jurdica (que pode ser obtida na ntegra em http://creativecommons.org/licenses/by-nc-sa/2.5/legalcode). Termo de exonerao de responsabilidade Esta Licena Simplicada no uma licena propriamente dita. Ela apenas uma referncia til para entender a Licena Jurdica (a licena integral) - ela uma expresso dos seus termos-chave que pode ser compreendida por qualquer pessoa. A Licena Simplica em si no tem valor legal e seu contedo no aparece na licena integral. O Creative Commons no um escritrio de advocacia e no presta servios jurdicos. A distribuio, exibio ou incluso de links para esta Licena Simplicada no estabelece qualquer relao advocatcia.

ii

iii

Sugestes e Correes
Se voc encontrar erros ou tiver sugestes para melhorias neste livro, favor enviar para o email kon@ime.usp.br.

iv

A nossas esposas e lhos, fonte de fora e alegria em nossas vidas.

vi

vii

Agradecimentos

Este livro no seria possvel sem a colaborao de inmeros alunos e professores do IME/USP. Leo Kazuhiro Ueda e Nelson Posse Lago atuaram como assistentes de ensino na primeira vez em que esta disciplina foi ministrada e foram responsveis por inmeras contribuies. O apndice sobre o Dr. Java foi preparado pelo Leo. Fabiano Mitsuo Sato, George Henrique Silva e Igor Ribeiro Sucupira foram monitores da disciplina tambm em 2003 e colaboraram com alguns exerccios. Raphael Y. de Camargo realizou um excelente trabalho na edio e reviso do livro alm de colaborar com alguns exerccios. O Prof. Joo Eduardo Ferreira, nosso colega no ensino da disciplina de introduo, o Prof. Valdemar Setzer, nosso experiente e sbio colega de departamento, e o Prof. Marcos Chaim, da USPLeste, nos deram inmeras sugestes teis que, sempre que possvel, foram incorporadas ao texto nal. Agradecemos ao Prof. Walter Savitch da Universidade da California em San Diego por ter autorizado o uso de sua classe para entrada de dados. Agradecemos tambm a Giuliano Mega pela diagramao da capa e a Stefano Mega pelos objetos nadando na xcara de Java. Finalmente, agradecemos aos alunos e professores que no foram citados mas que deram sugestes e nos incentivaram a escrever este livro.

viii

Sumrio
Prefcio 1 Teatro de Objetos 1.1 Disputa de pnaltis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Histria da Computao 2.1 Histria da Computao e Arquitetura do Computador . . . . . . . . . . . . . . . . . . . . . 2.2 Evoluo das Linguagens de Programao . . . . . . . . . . . . . . . . . . . . . . . . . . . . Conversor de Temperaturas 3.1 Analogia entre dramatizao da disputa de pnaltis e Programao Orientada a Objetos . . . . 3.2 Um exemplo real em Java: um conversor de Celsius para Fahrenheit . . . . . . . . . . . . . . Testes Automatizados Mtodos com Vrios Parmetros 5.1 Atributos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 A importncia da escolha de bons nomes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . if else Encaixados Programas com Vrios Objetos Laos e Repeties 8.1 Laos em linguagens de programao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2 O lao while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.3 Nmeros primos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Expresses e Variveis Lgicas 9.1 Condies como expresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.2 Precedncia de operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.3 Exemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix xv 1 1 7 7 12 15 15 16 19 25 26 29 33 39 45 45 46 48 53 53 56 57

4 5

6 7 8

SUMRIO 61 61 63 64 67 67 69 73 73 74 77 77 78 81 83 87 87 88 90 93 93 94 95

10 Mergulhando no while 10.1 Um pouco mais sobre primos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.2 Uma biblioteca de funes matemticas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.3 do...while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Caracteres e Cadeias de Caracteres 11.1 Um tipo para representar caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Cadeias de caracteres (Strings) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 A Memria e as Variveis 12.1 A Memria do Computador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.2 O que so as Variveis? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Manipulando Nmeros Utilizando Diferentes Bases 13.1 Sistemas de numerao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.2 Converso entre sistemas de numerao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Arrays (vetores) 14.1 Criao de programas Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 for, leitura do teclado e converso de Strings 15.1 O comando for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.2 Leitura do teclado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.3 Converso de String para nmeros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 Laos Encaixados e Matrizes 16.1 Laos encaixados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16.2 Matrizes (arrays multidimensionais) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16.3 Exemplo: LIFE, o jogo da vida . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

17 Busca e Ordenao 101 17.1 Busca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 17.2 Pondo ordem na casa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 18 Busca Binria e Fuso 105 18.1 Busca binria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 18.2 Complexidade Computacional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 18.3 Fuso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 19 Construtores e Especicadores de Acesso 109 19.1 Construtores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 19.2 Especicadores de acesso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112

SUMRIO 20 Interfaces 20.1 O conceito de interfaces . . . . . . . . . . . . 20.2 Um primeiro exemplo . . . . . . . . . . . . . 20.3 Implementando mais de uma interface por vez 20.4 Um exemplo mais sosticado . . . . . . . . . 20.5 A importncia de interfaces . . . . . . . . . . 21 Herana 21.1 O Conceito de herana . . . . . . . . . . . . 21.2 Terminologia de herana . . . . . . . . . . . 21.3 Implementao de herana na linguagem Java 21.4 Hierarquia de classes . . . . . . . . . . . . . 21.5 Relacionamento um . . . . . . . . . . . . 21.6 Resumo . . . . . . . . . . . . . . . . . . . . 22 Javadoc 23 O C Que H em Java 23.1 O C que h em Java . . . . 23.2 Detalhes de entrada e sada 23.3 Declarao de variveis . . 23.4 Parmetros de funes . . 23.5 Um ltimo exemplo . . . .

xi 115 115 115 119 121 125 129 129 130 130 132 133 133 135 141 141 143 144 144 144

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

A Utilizando o Dr. Java 149 A.1 Conversor de Temperatura simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 A.2 Tratando erros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 B Desenvolvimento Dirigido por Testes 157 B.1 O Exemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 Bibliograa 173

xii

SUMRIO

Lista de Figuras
2.1 2.2 Arquitetura do ENIAC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Arquitetura de Von Neumann . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 11

21.1 Diagrama de herana . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 21.2 Hierarquia de classes representando os seres vivos . . . . . . . . . . . . . . . . . . . . . . . . 132 21.3 Hierarquia errada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 22.1 Documentao gerada pelo Javadoc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139

xiii

xiv

LISTA DE FIGURAS

Prefcio
Caros leitores, sejam bem-vindos ao maravilhoso mundo da Cincia da Computao. Com este livro, vocs tero a oportunidade de aprender os elementos bsicos da programao de computadores e tero contato com alguns dos conceitos fundamentais da Cincia da Computao. Este livro resultado da experincia dos autores na disciplina de Introduo Cincia da Computao ministrada no IME/USP utilizando orientao a objetos e a linguagem Java de 2003 a 2006. Desde 2005, esta abordagem tambm aplicada na USPLeste com os 180 alunos do curso de Sistemas de Informao. Inuenciada pelo mtodo proposto pela ACM (Association for Computing Machinery) e pelo IEEE (Institute of Electrical and Electronics Engineers) em seu currculo Objects-rst, nossa abordagem evita o problema de se ensinar a programar sem o uso de objetos para depois exigir do estudante uma mudana de paradigma com a introduo de objetos. Elimina-se assim a necessidade de dizer esquea a forma que programamos at agora; agora vamos aprender o jeito correto. Apresentando os conceitos de orientao a objetos desde o incio do ensino de programao, a abordagem adotada aqui permite que o aluno inicie sua formao em programao de forma equilibrada. Aprendendo conceitos tanto algortmicos quanto estruturais ao mesmo tempo em que toma contato com prticas fundamentais de programao como testes automatizados e o uso de nomes claros para os elementos do cdigo, o leitor obtm uma viso bsica porm ampla do que mais importante para o desenvolvimento de software. Esperamos que este livro seja til tanto para alunos de cursos superiores de Informtica quanto para prossionais do mercado e outros curiosos que queiram adquirir conhecimentos na rea de desenvolvimento de software. Nosso objetivo que este livro os ajude na fascinante empreitada de aprender a programar de forma elegante e ecaz e que ele permita um bom incio rumo a uma formao slida em programao que uma condio fundamental que os desaos da informtica do sculo XXI nos impem.

Abraos e boa jornada!

So Paulo, maro de 2006. Alfredo Goldman, Fabio Kon e Paulo J. S. Silva

xv

xvi

PREFCIO

Captulo 1

Teatro de Objetos
Vamos iniciar a nossa jornada ao fascinante mundo da orientao a objetos de forma dramtica: com um Teatro de Objetos. Se voc est usando este livro em um curso, reserve juntamente com seu professor uma parte da primeira aula para realizar a encenao descrita neste captulo. Se voc trabalha em uma empresa, rena-se com colegas de trabalho ou com amigos interessados em programao para exercitar suas qualidades dramticas. Liberte o artista que existe dentro de voc! O objetivo do Teatro de Objetos fazer com que os alunos vivenciem um jogo interativo do qual participam vrios objetos realizando diferentes formas de aes e comunicaes. Os conceitos de orientao a objetos empregados no teatro no so explicitamente explicados j no primeiro captulo mas sero abordados ao longo do livro. Em um curso de Introduo Cincia da Computao, normalmente a primeira metade da primeira aula dedicada a uma conversa informal com os alunos explicando quais so os objetivos da disciplina (e do curso inteiro, se for o caso). sempre interessante tambm conversar sobre contatos prvios que os alunos tiveram com informtica e com programao. bom deixar claro que este livro pode ser acompanhado por uma pessoa que nunca viu um computador na frente em sua vida, mas que aprender a programar no uma tarefa fcil, preciso se empenhar. Na segunda metade da aula, exercitamos as habilidades dramticas: para ilustrar o funcionamento de um programa de computador complexo, vamos fazer de conta que somos partes de um programa de computador trabalhando em conjunto para atingir um certo objetivo. Se voc estiver organizando a encenao com seus colegas, voc pode fazer um certo suspense sobre qual o objetivo (simular uma disputa de pnaltis) e sobre como ele ser alcanado.

1.1

Disputa de pnaltis

A pea que encenaremos representar uma disputa de pnaltis entre dois times e contar com a participao de cerca de 26 atores desempenhando 8 papis. Se voc no tiver 26 atores disponveis, voc pode elaborar a sua prpria adaptao da pea. Os papis so: Tcnico (2 atores) Juiz (1 ator) Bandeirinha (2 atores) Gandula (1 ator) 1

2 Jogador. Os jogadores so divididos em dois tipos: Goleiro (2 atores desempenham este papel) Batedor de pnalti (10 atores) Torcedor. Os torcedores so divididos em dois tipos: Torcedor educado (4 atores) Torcedor mal-educado (4 atores)

CAPTULO 1. TEATRO DE OBJETOS

O professor (ou o diretor da pea, que pode ser voc) ser responsvel por escolher as pessoas que desempenharo cada papel. Se houver limitao de espao, conveniente que os 8 torcedores quem concentrados em uma rea separada (por exemplo, em uma suas prprias carteiras, se o local for uma sala de aula) para no tumultuar muito o ambiente. Obviamente, o diretor pode tambm aumentar ou diminuir o nmero de torcedores e de batedores de pnalti. Para desempenhar o papel de torcedores, uma boa dica o diretor escolher pessoas que paream bem barulhentas e faladoras (por exemplo, a turma do fundo numa sala de aula :-). Ao escolher os atores, o diretor dever entregar um carto preso com um barbante que car pendurado no pescoo do ator e conter informaes sobre o papel desempenhado pelo ator. As informaes so: 1. Nome do papel 2. Mensagens que o personagem capaz de entender 3. Atributos do personagem Os trs tipos de informao acima j devem vir pr-escritos caneta no carto mas os valores dos atributos do personagem devem ser escritos na hora a lpis pelo diretor. Alguns papis, como o de juiz, no possuem nenhum atributo. Outros papis podem possuir um ou mais atributos, o jogador, por exemplo, pode possuir como atributos o nome do time ao qual pertence e o nmero da sua camisa. No caso de o jogador ser um goleiro, o atributo nmero da camisa pode vir escrito a caneta como valendo 1. Alm do carto que ca pendurado no pescoo do ator, cada ator recebe um script descrevendo o seu comportamento: para cada mensagem recebida pelo ator, o script descreve quais aes devem ser tomadas pelo ator. O diretor no deve esquecer de trazer uma bola para esta atividade e deve tomar cuidado para que nenhuma janela seja quebrada durante a realizao da atividade. O tempo total estimado para a realizao da atividade de 50 minutos. A maior parte do tempo gasto explicando-se os procedimentos. A encenao em si, demora entre 5 e 10 minutos dependendo da qualidade dos batedores de pnalti e dos goleiros. Eis a descrio detalhada dos dados que devero aparecer nos cartes descritivos e no script (comportamento) de cada um dos 26 atores participantes da encenao. Para obter verses PDF dos cartes prontas para impresso, visite o stio deste livro: www.ime.usp.br/~kon/livros/Java

1.1. DISPUTA DE PNALTIS 1. Goleiro Carto de Identicao Nome do Papel: Goleiro Mensagens que entende: SuaVez, Cobrana Autorizada, VenceuOTimeX Atributos: Time: , Camisa nmero: 1 Comportamento (Script)

mensagem: SuaVez ao: posiciona-se na frente do gol e ca esperando pela cobrana do pnalti. mensagem: CobranaAutorizada ao: concentra-se na bola que ser chutada pelo adversrio e faz de tudo para no deixar que a bola entre no gol. O goleiro no pode se adiantar antes do chute do adversrio. Aps a cobrana sair do gol para dar lugar ao goleiro adversrio. mensagem: VenceuOTimeX ao: se TimeX igual ao atributo Time no seu carto de identicao, comemore; caso contrrio, xingue o juiz (polidamente! :-). 2. Batedor de Pnalti Carto de Identicao Nome do Papel: Batedor de Pnalti Mensagens que entende: SuaVez, CobranaAutorizada, VenceuOTimeX Atributos: Time: , Camisa nmero: Comportamento mensagem: SuaVez ao: posiciona-se na frente da bola e ca esperando pela autorizao do juiz. mensagem: CobranaAutorizada ao: chuta a bola tentando marcar um gol. Aps a cobrana voltar para junto do seu tcnico para dar lugar prxima cobrana. mensagem: VenceuOTimeX ao: se TimeX igual ao atributo Time no seu carto de identicao, comemore; caso contrrio, xingue o juiz (polidamente! :-). 3. Torcedor Educado Carto de Identicao Nome do Papel: Torcedor Educado Mensagens que entende: Ao, VenceuOTimeX Atributos: Time: , Camisa nmero: 12 Comportamento mensagem: Ao ao: assista ao jogo emitindo opinies inteligentes sobre o andamento da peleja e manifestando o seu apreo e desapreo pelo desenrolar da disputa. mensagem: VenceuOTimeX ao: se TimeX igual ao atributo Time no seu carto de identicao, comemore e faa um comentrio elogioso sobre o seu time; caso contrrio, elogie o adversrio e parabenize o seu time pelo empenho.

4 4. Torcedor Mal-Educado Carto de Identicao Nome do Papel: Torcedor Mal-Educado Mensagens que entende: Ao, VenceuOTimeX Atributos: Time: , Camisa nmero: 12 Comportamento

CAPTULO 1. TEATRO DE OBJETOS

mensagem: Ao ao: assista ao jogo emitindo opinies duvidosas sobre o andamento da peleja e manifestando a sua raiva ou alegria pelo desenrolar do jogo. mensagem: VenceuOTimeX ao: se TimeX igual ao atributo Time no seu carto de identicao, xingue o adversrio. Caso contrrio, xingue o adversrio desesperadamente (mas, por favor, no se esquea que estamos em uma universidade). 5. Juiz Carto de Identicao Nome do Papel: Juiz Mensagens que entende: Ao, Irregularidade Comportamento mensagem: Ao ao: coordene o andamento da disputa de pnaltis enviando mensagens SuaVez para o tcnico do time batedor e para o goleiro defensor a cada nova batida. Quando os personagens estiverem a postos, emita a mensagem CobranaAutorizada. Faa a contagem de gols e quando houver um vencedor, emita a mensagem VenceuOTimeX onde TimeX o nome do time vencedor. A disputa de pnaltis feita alternadamente, 5 cobranas para cada time. Se no houver um ganhador aps as 5 cobranas, so feitas novas cobranas alternadamente at que haja um vencedor. mensagem: Irregularidade ao: se a mensagem foi enviada por um Bandeirinha, ignore a cobrana recm-efetuada e ordene que ela seja realizada novamente enviando a mensagem RepitaCobrana ao tcnico apropriado. 6. Gandula Carto de Identicao Nome do Papel: Gandula Mensagens que entende: CobranaAutorizada Comportamento mensagem: CobranaAutorizada ao: preste ateno cobrana do pnalti. Aps a concluso da cobrana, pegue a bola e leve-a de volta marca de pnalti.

1.1. DISPUTA DE PNALTIS 7. Tcnico Carto de Identicao Nome do Papel: Tcnico Mensagens que entende: SuaVez, RepitaCobrana, VenceuOTimeX Atributos: Time: Comportamento

mensagem: SuaVez ao: escolha um dos seus jogadores para efetuar a cobrana e envie a mensagem SuaVez. No repita jogadores nas 5 cobranas iniciais. mensagem: RepitaCobrana ao: envie a mensagem SuaVez para o jogador que acabou de efetuar a cobrana. mensagem: VenceuOTimeX ao: se TimeX igual ao atributo Time no seu carto de identicao, comemore; caso contrrio, diga que o seu time foi prejudicado pela arbitragem e que futebol uma caixinha de surpresas. 8. Bandeirinha Carto de Identicao Nome do Papel: Bandeirinha Mensagens que entende: Cobrana Autorizada, VenceuOTimeX Comportamento mensagem: CobranaAutorizada ao: verique se o goleiro realmente no avana antes de o batedor chutar a bola. Caso ele avance, envie uma mensagem Irregularidade para o Juiz. mensagem: VenceuOTimeX ao: se TimeX no o nome do time da casa, distancie-se da torcida pois voc acaba de se tornar um alvo em potencial.

CAPTULO 1. TEATRO DE OBJETOS

Captulo 2

Histria da Computao
Quais novidades veremos neste captulo? a histria da computao; evoluo da arquitetura do computador; evoluo das linguagens de programao.

A Computao tem sido considerada uma cincia independente desde meados do sculo XX. No entanto, desde a antiguidade, a humanidade busca formas de automatizar os seus cmputos e de criar mquinas e mtodos para facilitar a realizao de clculos. Neste captulo, apresentamos inicialmente uma linha do tempo que indica alguns dos principais eventos ocorridos na histria da computao e na evoluo da arquitetura dos computadores automticos. Em seguida, apresentamos uma linha do tempo da evoluo das linguagens de programao.

2.1

Histria da Computao e Arquitetura do Computador

baco (Soroban em japons) (criado ~2000 anos atrs) Blaise Pascal, 1642 (pai da calculadora) o primeiro computador digital hoje, diramos apenas que era uma calculadora super simplicada capaz de somar entrada atravs de discos giratrios ajudou seu pai, coletor de impostos Leibniz computador capaz de somar e multiplicar (inventou em 1671 e construiu em 1694) 7

CAPTULO 2. HISTRIA DA COMPUTAO criou o mecanismo de engrenagens do "vai-um" usado at hoje Joseph Marie Jacquard (1752 - 1834) 1790: criou um sistema de tear semi-automtico onde os desenhos de ores, folhas e guras geomtricas eram codicados em cartes perfurados 1812: havia cerca de 11 mil teares de Jacquard na Frana a mquina despertou muitos protestos de artesos que temiam o desemprego que a mquina poderia causar a mquina era capaz de desenhar padres de alta complexidade como, por exemplo, um auto-retrato de Jacquard feito com 10 mil cartes perfurados Charles Babbage (professor de Matemtica em Cambridge, Inglaterra) 1812: notou que muito do que se fazia em Matemtica poderia ser automatizado iniciou projeto do "Difference Engine" (Mquina/Engenho/Engenhoca de Diferenas) 1822: terminou um prottipo da mquina e obteve nanciamento do governo para constru-la 1823: iniciou a construo (usaria motor a vapor, seria totalmente automtico, imprimiria o resultado e teria um programa xo) 1833: depois de 10 anos teve uma idia melhor e abandonou tudo Nova idia: mquina programvel, de propsito geral: "Analytical Engine" (Mquina Analtica) manipularia nmeros de 50 dgitos memria de 1000 dgitos estaes de leitura leriam cartes perfurados similares ao de tear de Jacquard (nesta poca, o auto-retrato de Jacquard pertencia a Babbage) mas ele no conseguiu constru-lo tecnologia mecnica da poca era insuciente pouca gente via a necessidade para tal mquina Ada Lovelace (me da programao) escreveu programas para o engenho analtico; inventou a palavra algoritmo em homenagem ao matemtico Al-Khawarizmi (820 d.C.) Algoritmo: seqncia de operaes ou comandos que, aplicada a um conjunto de dados, permite solucionar classes de problemas semelhantes. Exemplos: algoritmo da diviso, da raiz cbica, para resoluo de equaes do segundo grau, etc. a mquina foi nalmente construda pelo governo ingls nos anos 1990 (e funciona!) Herman Hollerith, 1890 criou cartes perfurados para uso no censo americano tecnologia levou criao da International Business Machines (IBM) at hoje dizemos que no nal do ms os empregados recebem o holerite como sinnimo de contracheque

2.1. HISTRIA DA COMPUTAO E ARQUITETURA DO COMPUTADOR Avanos nas calculadoras de mesa Em 1890, as mquinas permitiam: acumular resultados parciais armazenamento e reentrada automtica de resultados passados (memria) imprimir resultados em papel MARK 1, criada em 1937 por Howard Aiken, professor de Matemtica Aplicada de Harvard calculadora eletromecnica com motor eltrico pesava 5 toneladas, usava toneladas de gelo para refrigerao multiplicava dois nmeros de 23 dgitos em 3 segundos John Vincent Atanasoff, Universidade Estadual de Iowa construiu o que considerado o primeiro computador digital entre 1937 e 1942 calculadora com vlvulas a vcuo (240 vlvulas) resolvia equaes lineares, diferenciais e de balstica manipulava nmeros binrios Rumo programabilidade Alan Turing,

Trabalhou para o exrcito ingls ajudando a quebrar o cdigo criptogrco da mquina Enigma criada pelos alemes Realizou importantes contribuies prticas e tericas Cincia da Computao 1912: nasce em Londres 1935: Ganha bolsa para realizar pesquisas no Kings College, Cambridge 1936: Elabora Mquina de Turing, pesquisas em computabilidade 1936-38: Princeton University. Ph.D. Lgica, lgebra, Teoria dos Nmeros 1938-39: Cambridge. apresentado mquina Enigma dos alemes 1939-40: The Bombe, mquina para decodicao do Enigma criada em Bletchley Park 1939-42: quebra Enigma do U-boat, aliados vencem batalha do Atlntico 1943-45: Consultor-chefe anglo-americano para criptologia 1947-48: Programao, redes neurais e inteligncia articial 1948: Manchester University 1949: Pesquisas sobre usos do computador em clculos matemticos avanados 1950: Prope Teste de Turing para inteligncia de mquinas 1952: Preso por homossexualidade, perde privilgios militares 1953-54: Trabalho no nalizado em Biologia e Fsica; tem sua reputao e vida destrudas pelos militares ingleses

10

CAPTULO 2. HISTRIA DA COMPUTAO

Figura 2.1: Arquitetura do ENIAC

1954: Suicida-se em Wilmslow, Cheshire Livro interessante sobre sua vida e obra: Alan Turing: the Enigma de Andrew Hodges, 2000 Stio sobre a vida de Turing mantido pelo autor deste livro: http://www.turing.org.uk/turing ENIAC (Electronic Numerical Integrator and Computer), 1945 por alguns, considerado o primeiro computador eletrnico nmeros de 10 dgitos decimais 300 multiplicaes ou 5000 somas por segundo 17486 vlvulas, a queima de vlvulas era quase que diria 6000 comutadores manuais e centenas de cabos usados na programao programao era muito difcil Arquitetura do ENIAC (ver Figura 2.1) programa especicado manualmente em "hardware" com conexes semelhantes quelas que as velhas telefonistas utilizavam memria de dados separada do controle e separada do programa o controle formado por circuitos eletroeletrnicos John Von Neumann, matemtico, 1945 estudo abstrato de modelos de computao levou arquitetura do computador moderno o programa deve ser guardado no mesmo lugar que os dados: na memria Arquitetura de Von Neumann (ver Figura 2.2) hoje em dia, h vrios tipos de memria ROM, RAM, ash RAM, etc.) o controlador em memria, levou idia de sistema operacional que temos hoje Nunca diga nunca...

2.1. HISTRIA DA COMPUTAO E ARQUITETURA DO COMPUTADOR

11

Figura 2.2: Arquitetura de Von Neumann

Aiken declarou em 1947 que nunca haveria necessidade de mais de um ou dois computadores programveis e que os projetos neste sentido deveriam ser abandonados Bill Gates declarou na dcada de 1980 que a Microsoft nunca desenvolveria um sistema operacional de 32 bits Anos 50 1953: IBM vende 15 mquinas baseadas no modelo de Neumann transistores memria magntica ("magnetic core memory") Anos 60 circuitos impressos / circuitos integrados (chips) crescimento segundo lei de Moore, que diz que o nmero de transistores em circuitos integrados duplica a cada 18 meses. Esta lei continua valendo at hoje computao limitada a poucos computadores de grande porte Anos 70 indo contra o modelo centralizador da IBM, gerao sexo, drogas e rock-and-roll da California exige a democratizao da informtica revista esquerdista da Universidade da Califrnia em Berkeley Peoples Computer Company defende a criao de computadores pessoais e de cooperativas de informao Steve Jobs cria a Apple em garagem em ~1975 e investe lucros do Apple II em shows de Rock (82) nasce a Microsoft governo da Califrnia apia microinformtica

12 Anos 80 IBM lana PC (1981) Apple lana MacIntosh (1984)

CAPTULO 2. HISTRIA DA COMPUTAO

Xerox inventa e Apple comercializa interface baseada em janelas ("Windows") Microsoft cresce comercializando o sistema operacional simplista MS-DOS para IBM-PCs (o DOS era uma verso simplicada do CPM que, por sua vez, era uma verso simplicada do UNIX) algumas empresas comeam a esconder cdigo-fonte do software (antes era sempre aberto) comea o movimento do software livre e software aberto Anos 90 Microsoft pega carona na exploso de vendas de PCs, utiliza tcnicas de marketing agressivas (consideradas por alguns como moralmente questionveis) para controlar o mercado de software, estabelecendo quase um monoplio em certas reas popularizao da Internet e criao da Web intensica-se o movimento do software livre nasce o Linux e uma nova forma de desenvolvimento de software baseada em comunidades distribudas atravs da Internet no nal da dcada, o governo americano percebe o perigo que a Microsoft representa e inicia batalha judicial contra a empresa (em 2002, aps a vitria dos conservadores na eleio nos EUA, o governo termina um processo judicial que havia iniciado; as sanes empresa so mnimas) Sculo XXI computadores de mo, telefones celulares, iPod sistemas embutidos computao ubqua e pervasiva grande crescimento da empresa Google atravs de servios inovadores na Web

2.2

Evoluo das Linguagens de Programao

Paralelamente evoluo do hardware dos computadores eletrnicos, ocorreu tambm a evoluo do software e das linguagens de programao utilizadas para desenvolv-lo. Inicialmente, as linguagens estavam bem prximas do funcionamento dos circuitos do hardware; paulatinamente, as linguagens foram se aproximando da linguagem natural utilizada pelos humanos em seu dia-a-dia. A mquina de Babbage s poderia ser programada com a troca fsica de engrenagens 1945, no ENIAC, a programao era feita mudando chaves e trocando a posio de cabos

2.2. EVOLUO DAS LINGUAGENS DE PROGRAMAO

13

1949-50, primeira linguagem binria, a programao era feita mudando os comandos de zero a um, e vice-versa 1951, Grace Hooper cria o primeiro compilador, A0, programa que transforma comandos em 0s e 1s 1957, primeira linguagem de programao de alto nvel: FORTRAN (FORmula TRANslating) (John Backus da IBM) 1958, criao de um padro universal de linguagem: ALGOL 58 (ALGOritmic Language) (origem da maioria das linguagens modernas). Primeira linguagem estruturada 1958, John McCarthy do MIT cria o LISP (LISt Processing), inicialmente projetada para uso em inteligncia articial. Nela tudo se baseia em listas. Ainda usada hoje em dia 1959, FORTRAN era ecaz para manipulao de nmeros, mas no para entrada e sada: foi criada COBOL (COmmon Bussines Oriented Language) 1964, criao do BASIC (Beginners All-purpose Symbolic Instruction Code) 1965, criao de uma linguagem especca para simulao (SIMULA I) por Ole-Johan Dahl and Kristen Nygaard da Universidade de Oslo. considerada a base das linguagens orientadas a objetos 1966, criao da linguagem Logo para desenhos grcos (a linguagem da tartaruga) 1967, Simula 67, uma linguagem de uso geral incluindo todos os conceitos fundamentais de orientao a objetos 1968, criao da linguagem PASCAL por Niklaus Wirth. Principal interesse: linguagem para o ensino. Combinou as melhores caractersticas de Cobol, Fortran e Algol, foi uma linguagem bem utilizada 1970, PROLOG, linguagem para programao lgica 1972, criao da linguagem C (Denis Ritchie). Supriu as decincias da linguagem Pascal e teve sucesso quase imediato 1972-1980, linguagem Smalltalk, desenvolvida por Alan Kay, da Xerox, utilizando as melhores caractersticas de LISP, Simula 67, Logo e ambientes grcos como Sketchpad; Orientao a Objetos ganha fora 1983, criadas extenses de C incluindo suporte para OO: C++ e Objective-C 1987, linguagens baseadas em scripts, como Perl, desenvolvida por Larry Wall. Ferramentas de UNIX como sed e awk no eram sucientes 1994, Java lanada pela Sun como a linguagem para a Internet 2000, lanamento do C# pela Microsoft, combinando idias das linguagens Java e C++ 2005, lanamento da verso 1.5 de Java Neste livro, apresentamos, de forma muito sucinta, algumas das principais linguagens de programao. Para referncias mais completas visite www.princeton.edu/~ferguson/adw/programming_languages.shtml e en.wikipedia.org/wiki/Programming_language.

14

CAPTULO 2. HISTRIA DA COMPUTAO

Captulo 3

Conversor de Temperaturas
Quais novidades veremos neste captulo? primeiro programa em Java.

3.1

Analogia entre dramatizao da disputa de pnaltis e Programao Orientada a Objetos


Terminologia Teatral personagem (papel) ator envio de mensagem Terminologia de Programao Orientada a Objetos classe (tipo) objeto envio de mensagem, chamada de mtodo ou chamada de funo

Na dramatizao, podamos enviar uma mensagem (dizer alguma coisa) para um ator. Na programao orientada a objetos, podemos enviar uma mensagem para (ou chamar um mtodo de) um objeto. Os cartes de identicao denem os papis dos atores e os scripts especicam o comportamento dos atores no decorrer da pea. A linguagem Java permite que especiquemos a mesma coisa. Um carto de identicao tem 3 partes, essas mesmas 3 partes aparecem na denio de uma classe em Java. Por exemplo, o bandeirinha em Java seria mais ou menos assim:
class Bandeirinha { CobranaAutorizada { / / V e r i f i c a s e o g o l e i r o r e a l m e n t e no a v a n a a n t e s de o b a t e d o r . . . } VenceuOTime ( NomeDoTime ) { / / Se NomeDoTime no o nome do t i m e da casa , d i s t a n c i e s e da t o r c i d a . . . } }

15

16

CAPTULO 3. CONVERSOR DE TEMPERATURAS

3.2

Um exemplo real em Java: um conversor de Celsius para Fahrenheit

Sempre o primeiro passo antes de programar analisar o problema. 9 9 F 32 C = F 32 = C F = C + 32 9 5 5 5 Traduzindo esta frmula para Java temos F=9*C/5+32. A seguir iremos criar diversas classes para realizar a converso entre Celsius e Fahrenheit. 1. Primeira tentativa: programa em Java para converter 40 graus Celsius para Fahrenheit.
c l a s s Conversor { int celsiusParaFahrenheit () { r e t u r n 9 40 / 5 + 3 2 ; } }

para executar este conversor dentro do DrJava1 , podemos digitar o seguinte na janela do interpretador (chamada de interactions):
C o n v e r s o r c1 = new C o n v e r s o r ( ) ; c1 . c e l s i u s P a r a F a h r e n h e i t ( )

o DrJava imprimir o valor devolvido pelo mtodo celsiusParaFahrenheit do objeto c1. limitao: sempre converte a mesma temperatura. 2. Segunda tentativa: conversor genrico de temperaturas Celsius -> Fahrenheit. capaz de converter qualquer temperatura de Fahrenheit para Celsius.
c l a s s Conversor2 { int celsiusParaFahrenheit ( int c ) { return 9 c / 5 + 32; } }

para executar este conversor, podemos digitar o seguinte na janela do interpretador:


C o n v e r s o r 2 c2 = new C o n v e r s o r 2 ( ) ; c2 . c e l s i u s P a r a F a h r e n h e i t ( 1 0 0 )

o DrJava imprimir o valor devolvido pelo mtodo celsiusParaFahrenheit do objeto c2.


1 Para

mais informaes sobre o DrJava consulte o Apndice A.

3.2. UM EXEMPLO REAL EM JAVA: UM CONVERSOR DE CELSIUS PARA FAHRENHEIT

17

limitao: essa classe manipula apenas nmeros inteiros. Mas, em geral, temperaturas so nmeros reais, fracionrios, ento nmeros inteiros no so sucientes. Quando o computador opera com nmeros inteiros, os nmeros so truncados, ou seja, 30.3 se torna 30 e 30.9 tambm se torna 30. Devido a esta limitao, se tivssemos escrito a frmula como 9 C + 32, o clculo seria errado, 5 9 uma vez que 5 = 1 se considerarmos apenas a parte inteira da diviso. Assim, o programa calcularia apenas 1 C + 32. Quando precisamos trabalhar com nmeros reais, usamos nmeros de ponto utuante (oating point numbers). Esse nome se deriva do fato de que internamente os nmeros so representados de forma parecida a potncias de 10 onde, variando o expoente da potncia, movemos (utuamos) o ponto decimal para a esquerda ou para a direita. De oating point vem o tipo float da linguagem Java. Nmeros do tipo float so armazenados em 4 bytes e tem uma preciso de 23 bits (o que equivale a aproximadamente 7 casas decimais). No entanto, quase sempre so utilizados nmeros de ponto utuante com preciso dupla que so chamados de double. Em Java, um double ocupa 8 bytes e tem preciso de 52 bits, o que equivale a aproximadamente 16 casas decimais. Daqui para frente sempre que precisarmos de nmeros fracionrios, vamos utilizar o tipo double. Mas lembre-se de que as variveis do tipo double so apenas uma aproximao do nmero real, como podemos ver no exemplo abaixo: > double x = 1.0 1.0 > x = x / 59049 1.6935087808430286E-5 > x = x * 59049 0.9999999999999999 Aps dividir o nmero 1.0 pelo nmero 310 = 59049 e depois multiplic-lo por este mesmo nmero, obtivemos um valor diferente do inicial. Por este motivo, devemos ter muito cuidado com os erros de arredondamento presentes quando utilizamos nmeros de ponto utuante. 3. Terceira tentativa: conversor genrico usando double
c l a s s Conversor3 { double c e l s i u s P a r a F a h r e n h e i t ( double c ) { return 9.0 c / 5.0 + 3 2 . 0 ; } }

para executar este conversor, podemos digitar o seguinte na janela do interpretador:


C o n v e r s o r 3 c3 = new C o n v e r s o r 3 ( ) ; c3 . c e l s i u s P a r a F a h r e n h e i t ( 3 7 . 8 ) ;

limitao: s faz converso em um dos sentidos.

18

CAPTULO 3. CONVERSOR DE TEMPERATURAS 4. Quarta e ltima verso: converso de mo dupla


c l a s s Conversor4 { double c e l s i u s P a r a F a h r e n h e i t ( double c ) { return 9.0 c / 5.0 + 3 2 . 0 ; } double f a h r e n h e i t P a r a C e l s i u s ( double f ) { return 5.0 ( f 3 2 . 0) / 9 . 0 ; } }

para executar este conversor, podemos digitar o seguinte na janela do interpretador:


C o n v e r s o r 4 c4 = new C o n v e r s o r 4 ( ) ; c4 . c e l s i u s P a r a F a h r e n h e i t ( 3 7 . 8 ) ; c4 . F a h r e n h e i t P a r a C e l s i u s ( 2 0 . 3 ) ;

Note que, para que o seu programa que bem legvel e elegante, muito importante o alinhamento dos abre-chaves { com os fecha-chaves } correspondentes. Em programas mais complexos, esse correto alinhamento (indentao) ajuda muito a tornar o programa mais claro para seres humanos.

Exerccios
1. Crie uma classe Conversor5 que inclua tambm a escala Kelvin (K). Esta classe deve conter conversores entre as trs escalas de temperatura (Celsius, Fahrenheit e Kelvin), totalizando seis funes. A relao entre as trs escalas dada por: F 32 C K 273 = = 9 5 5 2. Iremos agora construir uma classe que calcula o valor de um nmero ao quadrado e ao cubo. Para tal, crie uma classe que contenha dois mtodos. O primeiro mtodo deve receber um nmero e devolver o seu quadrado e o segundo mtodo deve receber um nmero e devolver o seu valor ao cubo. Escolha nomes para a classe e mtodos que facilitem a compreenso de seu funcionamento. 3. Neste exerccio iremos simular um jogo de tnis. A partida de tnis composta por diversos papis: jogador, juiz de cadeira, juiz de linha, treinador, gandula, torcedor. Para cada um destes papis, descreva as mensagens que os atores de cada papel devem receber, e seu comportamento para cada uma delas. Utilize como modelo a descrio do papel Bandeirinha apresentada no incio deste captulo.

Captulo 4

Testes Automatizados
Quais novidades veremos neste captulo? comando if e else; comparaes == (igualdade) e != (diferena); denio de variveis inteiras e de ponto utuante; impresso de texto; comentrios.

Desde o incio, a computao sempre esteve sujeita erros. O termo bug, para denotar erro, tem uma origem muito anterior (vem de um inseto que causava problemas de leitura no fongrafo de Thomas Edison em 1889). Vrias outras histrias reais, ou nem tanto, tambm apareceram no incio da informtica. Infelizmente, muito difcil garantir que no existam erros em programas. Uma das formas de se garantir que certos erros no vo ocorrer testando algumas situaes. Apesar da clebre armao de Edsger Dijkstra 1 de que testes podem apenas mostrar a presena de erros e no a sua ausncia, eles podem ser os nossos grandes aliados no desenvolvimento de programas corretos. Intuitivamente, quanto mais testes zermos em um programa e quanto mais abrangentes eles forem, mais conantes podemos car com relao ao seu funcionamento. Por outro lado, podemos usar o prprio computador para nos ajudar, isto , podemos criar testes automatizados. Em vez de fazermos os testes na mo, faremos com que o computador seja capaz de vericar o funcionamento de uma seqncia de testes. Veremos neste captulo como desenvolver testes automatizados, passo a passo, para os conversores de temperatura vistos anteriormente. No incio da computao no havia uma preocupao muito grande com os testes, que eram feitos de forma manual pelos prprios programadores. Os grandes testadores eram os usurios nais. interessante notar que isto acontece com alguns produtos ainda hoje. Com o aparecimento da Engenharia de Software cou clara a necessidade de se efetuarem testes, tanto que em vrias empresas de desenvolvimento de software existe a gura do testador, responsvel por tentar encontrar erros em sistemas. Hoje existe uma tendncia para se
1 Um dos mais inuentes membros da gerao dos criadores da Cincia da Computao. A pgina http://www.cs.utexas.edu/ users/EWD contm cpias de vrios de seus manuscritos.

19

20

CAPTULO 4. TESTES AUTOMATIZADOS

considerar que testes automatizados so muito importantes, devendo ser escritos mesmo antes de se escrever o cdigo propriamente dito, tcnica esta chamada de testes a priori. Veremos como testar os diversos conversores de temperatura. Como testar o nosso primeiro programa em Java (Conversor).
C o n v e r s o r c1 = new C o n v e r s o r ( ) / / a r e s p o s t a e s p e r a d a o e q u i v a l e n t e a 40C em F i f ( c1 . c e l s i u s P a r a F a h r e n h e i t ( ) == 1 0 4 ) System . o u t . p r i n t l n ( " F u n c i o n a " ) ; else System . o u t . p r i n t l n ( " No f u n c i o n a " ) ;

Note que para fazer o teste utilizamos o comando condicional if else. O formato genrico deste comando o seguinte.
i f (CONDIO) COMANDO1; else COMANDO2;

Se a CONDIO verdadeira, o COMANDO-1 executado, caso contrrio, o COMANDO-2 executado. A classe Conversor2 possui um mtodo que aceita um parmetro, veja o teste abaixo:
C o n v e r s o r 2 c2 = new C o n v e r s o r 2 ( ) ; / / c r i a duas v a r i v e i s i n t e i r a s int entrada = 40; int r e s p o s t a = 104; / / a r e s p o s t a e s p e r a d a o e q u i v a l e n t e e n t r a d a C em F i f ( c2 . c e l s i u s P a r a F a h r e n h e i t ( e n t r a d a ) == r e s p o s t a ) System . o u t . p r i n t l n ( " F u n c i o n a " ) ; else System . o u t . p r i n t l n ( " No f u n c i o n a " ) ;

Note que, para realizar o teste acima, denimos duas variveis inteiras chamadas de entrada e resposta. A linha
int entrada = 40;

faz na verdade duas coisas. Primeiro, ela declara a criao de uma nova varivel (int entrada;) e, depois, atribui um valor inicial a esta varivel (entrada = 40;). Na linguagem Java, se o valor inicial de uma varivel no atribudo, o sistema atribui o valor 0 varivel automaticamente. Note que isso no necessariamente verdade em outras linguagens como, por exemplo, C e C++. Podemos tambm testar o Conversor2 para outros valores. Por exemplo, para as entradas (e respostas): 20 (68) e 100 (212).
e n t r a d a = 2 0 ; / / como a s v a r i v e i s j f o r a m d e c l a r a d a s acima , b a s t a usl a s r e s p o s t a = 68; i f ( c2 . c e l s i u s P a r a F a h r e n h e i t ( e n t r a d a ) == r e s p o s t a ) System . o u t . p r i n t l n ( " F u n c i o n a " ) ; else

21
System . o u t . p r i n t l n ( " No f u n c i o n a " ) ; entrada = 100; r e s p o s t a = 212; i f ( c2 . c e l s i u s P a r a F a h r e n h e i t ( e n t r a d a ) == r e s p o s t a ) System . o u t . p r i n t l n ( " F u n c i o n a " ) ; else System . o u t . p r i n t l n ( " No f u n c i o n a " ) ;

No programa acima o texto Funciona ser impresso na tela a cada sucesso, o que poder causar uma poluio visual caso tenhamos dezenas ou centenas de testes. O ideal para um testador que ele que silencioso caso os testes dem certo e chame a ateno caso ocorra algum erro. Podemos ento mudar o programa para:
C o n v e r s o r 2 c2 = new C o n v e r s o r 2 ( ) ; int entrada = 40; int r e s p o s t a = 104; i f ( c2 . c e l s i u s P a r a F a h r e n h e i t ( e n t r a d a ) ! = r e s p o s t a ) System . o u t . p r i n t l n ( " No f u n c i o n a p a r a 40 " ) ; entrada = 20; r e s p o s t a = 68; i f ( c2 . c e l s i u s P a r a F a h r e n h e i t ( e n t r a d a ) ! = r e s p o s t a ) System . o u t . p r i n t l n ( " No f u n c i o n a p a r a 20 " ) ; entrada = 100; r e s p o s t a = 212; i f ( c2 . c e l s i u s P a r a F a h r e n h e i t ( e n t r a d a ) ! = r e s p o s t a ) System . o u t . p r i n t l n ( " No f u n c i o n a p a r a 100 " ) ; System . o u t . p r i n t l n ( " Fim d o s t e s t e s " ) ;

Note que o comando if acima foi utilizado sem a parte do else, o que perfeitamente possvel. Adicionamos tambm uma linha nal para informar o trmino dos testes. Ela importante no caso em que todos os testes do certo para que o usurio saiba que a execuo dos testes foi encerrada. Uma forma de simplicar os comandos de impresso usar a prpria entrada como parmetro, o que pode ser feito da seguinte forma:
System . o u t . p r i n t l n ( " No f u n c i o n a p a r a " + e n t r a d a ) ;

Criaremos agora os testes para o Conversor4. Mas, agora, devem ser testados os seus dois mtodos. Introduziremos um testador automtico criando uma classe com apenas um mtodo que faz o que vimos.
class TestaConversor4 { int testaTudo () { C o n v e r s o r 4 c4 = new C o n v e r s o r 4 ( ) ; double c e l s i u s = 1 0 . 0 ; double f a h r e n h e i t = 5 0 . 0 ; i f ( c4 . c e l s i u s P a r a F a h r e n h e i t ( c e l s i u s ) ! = f a h r e n h e i t ) System . o u t . p r i n t l n ( "C> F no f u n c i o n a p a r a " + c e l s i u s ) ;

22

CAPTULO 4. TESTES AUTOMATIZADOS


i f ( c4 . f a h r P a r a C e l s i u s ( f a h r e n h e i t ) ! = c e l s i u s ) System . o u t . p r i n t l n ( " F> C no f u n c i o n a p a r a " + f a h r e n h e i t ) ; celsius = 20.0; fahrenheit = 68.0; i f ( c4 . c e l s i u s P a r a F a h r e n h e i t ( c e l s i u s ) ! = f a h r e n h e i t ) System . o u t . p r i n t l n ( "C> F no f u n c i o n a p a r a " + c e l s i u s ) ; i f ( c4 . f a h r P a r a C e l s i u s ( f a h r e n h e i t ) ! = c e l s i u s ) System . o u t . p r i n t l n ( " F> C no f u n c i o n a p a r a " + f a h r e n h e i t ) ; celsius = 101.0; fahrenheit = 213.8; i f ( c4 . c e l s i u s P a r a F a h r e n h e i t ( c e l s i u s ) ! = f a h r e n h e i t ) System . o u t . p r i n t l n ( "C> F no f u n c i o n a p a r a " + c e l s i u s ) ; i f ( c4 . f a h r P a r a C e l s i u s ( f a h r e n h e i t ) ! = c e l s i u s ) System . o u t . p r i n t l n ( " F> C no f u n c i o n a p a r a " + f a h r e n h e i t ) ; System . o u t . p r i n t l n ( " F i n a l d o s t e s t e s " ) ; return 0; }

Comentrios: Voc deve ter notado que, no meio de alguns exemplos de cdigo Java deste captulo, ns introduzimos uns comentrios em portugus. Comentrios deste tipo so possveis em praticamente todas as linguagens de programao e servem para ajudar os leitores do seu cdigo a compreender mais facilmente o que voc escreveu. Comentrios em Java podem ser inseridos de duas formas. O smbolo // faz com que tudo o que aparecer aps este smbolo at o nal da linha seja ignorado pelo compilador Java; este o formato que utilizamos neste captulo e que utilizaremos quase sempre neste livro. A segunda forma atravs dos smbolos /* (que indica o incio de um comentrio) e */ (que indica o nal de um comentrio). Neste caso, um comentrio pode ocupar vrias linhas. Esta tcnica tambm til para desprezarmos temporariamente um pedao do nosso programa. Por exemplo, se queremos testar se uma classe funciona mesmo se removermos um de seus mtodos, no necessrio apagar o cdigo do mtodo. Basta acrescentar um /* na linha anterior ao incio do mtodo, acrescentar um */ logo aps a ltima linha do mtodo e recompilar a classe. Posteriormente, se quisermos reinserir o mtodo, basta remover os smbolos de comentrios. Outro uso para este ltimo tipo de comentrios quando desejamos testar uma verso alternativa de um mtodo. Comentamos a verso antiga do mtodo, inserimos a verso nova e testamos a classe. Podemos a decidir qual verso utilizar e, ento, remover a que no mais ser usada. Agora, vamos treinar o que aprendemos com alguns exerccios. Em particular, os exerccios 3, de refatorao, e 4, que indica quais casos devem ser testados, so muito importantes.

Exerccios
1. Escreva uma classe TestaConversor3 para testar a classe Conversor3.

23 2. Importante: Refatore a classe TestaConversor4 de modo a eliminar as partes repetidas do cdigo. Dica: Crie um mtodo que realiza o teste das duas funes. 3. Importante: Podemos criar testes para objetos de uma classe que no sabemos como foi implementada. Para tal, basta conhecermos suas entradas e sadas. Escreva um teste automatizado para a seguinte classe:
c l a s s Contas { double c a l c u l a Q u a d r a d o ( double x ) ; double c a l c u l a C u b o ( double x ) ; }

Ao escrever o teste, pense em testar vrios casos com caractersticas diferentes. Em particular, no deixe de testar os casos limtrofes que , geralmente, onde a maioria dos erros tendem a se concentrar. Na classe Contas acima, os casos interessantes para teste seriam, por exemplo: x = 0; x um nmero positivo pequeno; x um nmero negativo pequeno; x um nmero positivo grande; x um nmero negativo grande. Alm disso, seria interessante que, em alguns dos casos acima, x fosse um nmero inteiro e em outros casos, um nmero fracionrio. 4. Programas conveis: Se conhecemos uma implementao e sabemos que a mesma funciona de maneira convel, ela pode servir de base para o teste de outras implementaes. Caso duas implementaes diferentes produzam resultados distintos para os mesmos dados de entrada, podemos dizer que pelo menos uma das duas est errada; Supondo que a classe Contas do exerccio anterior convel, escreva um teste automatizado que utiliza esta classe para testar a classe ContasNoConfiavel dada abaixo:
c l a s s ContasNoConfivel { double c a l c u l a Q u a d r a d o ( double x ) ; double c a l c u l a C u b o ( double x ) ; }

Resolues
Exerccio 2
class TesteConversor4Refatorado { i n t t e s t e P o n t u a l ( double c e l s i u s , double f a h r e n h e i t ) { C o n v e r s o r c4 = new C o n v e r s o r 4 ( ) ;

24

CAPTULO 4. TESTES AUTOMATIZADOS

i f ( c4 . c e l s i u s P a r a F a h r e n h e i t ( c e l s i u s ) ! = f a h r e n h e i t ) System . o u t . p r i n t l n ( "C> F no f u n c i o n a p a r a " + c e l s i u s ) ; i f ( c4 . f a h r P a r a C e l s i u s ( f a h r e n h e i t ) ! = c e l s i u s ) System . o u t . p r i n t l n ( " F> C no f u n c i o n a p a r a " + f a h r e n h e i t ) ; return 0; } int testaTudo () { double c e l s i u s = 1 0 . 0 ; double f a h r e n h e i t = 5 0 . 0 ; testePontual ( celsius , fahrenheit ); celsius = 20.0; fahrenheit = 68.0; testePontual ( celsius , fahrenheit ); celsius = 101.0; fahrenheit = 213.8; testePontual ( celsius , fahrenheit ); System . o u t . p r i n t l n ( " F i n a l d o s t e s t e s " ) ; return 0; } }

Exerccio 3
class TesteContas { int teste () { C o n t a s c o n t a s = new C o n t a s ( ) ; double v a l o r = 4 . 0 ; i f ( c o n t a s . c a l c u l a Q u a d r a d o ( v a l o r ) != 1 6 . 0 ) System . o u t . p r i n t l n ( " No f u n c i o n a p a r a c a l c u l a r o q u a d r a d o de 4 " ) ; i f ( c o n t a s . c a l c u l a C u b o ( v a l o r ) != 6 4 . 0 ) System . o u t . p r i n t l n ( " No f u n c i o n a p a r a c a l c u l a r 4 ao cubo " ) ; return 0; } }

Captulo 5

Mtodos com Vrios Parmetros


Quais novidades veremos neste captulo? Mtodos com vrios parmetros; Atributos; Mtodos que devolvem nada (void); Escolha de bons nomes.

No ltimo captulo, vimos um mtodo que recebe vrios parmetros. Apesar de no estarmos apresentando nenhuma novidade conceitual, vamos reforar a possibilidade da passagem de mais de um parmetro. Ao chamarmos um mtodo que recebe mltiplos parmetros, assim como no caso de mtodos de um parmetro, devemos passar valores do mesmo tipo que aqueles que o mtodo est esperando. Por exemplo, se um objeto (ator) tem um mtodo (entende uma mensagem) que tem como parmetro um nmero inteiro, no podemos enviar a este objeto um nmero double. Apesar de ser intuitivo, tambm vale ressaltar que a ordem dos parmetros importante, de modo que na chamada de um mtodo devemos respeitar a ordem que est na sua denio. Vamos comear com o clculo da rea de uma circunferncia, onde necessrio apenas um parmetro, o raio:
class Crculo1 { double c a l c u l a r e a ( double r a i o ) { return 3.14159 r a i o r a i o ; } }

25

26

CAPTULO 5. MTODOS COM VRIOS PARMETROS

Nota Lingstica: Em Java, o nome de variveis, classes e mtodos pode conter caracteres acentuados. Muitos programadores evitam o uso de acentuao mesmo ao usar nomes em portugus. Este costume advm de outras linguagens mais antigas, como C, que no permitem o uso de caracteres acentuados. Voc pode usar caracteres acentuados se quiser mas lembre-se que, se voc tiver uma varivel chamada rea, ela ser diferente de outra chamada area (sem acento); ou seja, se voc decidir usar acentos, dever us-los consistentemente sempre. Podemos sosticar o exemplo calculando tambm o permetro, com o seguinte mtodo:
double c a l c u l a P e r m e t r o ( double r a i o ) { return 3.14159 2.0 r a i o ; }

O seguinte trecho de cdigo calcula e imprime a rea e o permetro de uma circunferncia de raio 3.0:
C r c u l o 1 c = new C r c u l o 1 ( ) ; System . o u t . p r i n t l n ( c . c a l c u l a r e a ( 3 . 0 ) ) ; System . o u t . p r i n t l n ( c . c a l c u l a P e r m e t r o ( 3 . 0 ) ) ;

Vejamos agora uma classe Retngulo que dene mtodos para o clculo do permetro e da rea de um retngulo. Neste caso so necessrios dois parmetros.
c l a s s Retngulo1 { i n t c a l c u l a r e a ( i n t lado1 , i n t lado2 ) { return lado1 lado2 ; } i n t c a l c u l a P e r m e t r o ( i n t lado1 , i n t lado2 ) { return 2 ( lado1 + lado2 ) ; } }

As chamadas para os mtodos podem ser da seguinte forma:


R e t n g u l o 1 r = new R e t n g u l o 1 ( ) ; System . o u t . p r i n t l n ( r . c a l c u l a r e a ( 2 , 3 ) ) ; System . o u t . p r i n t l n ( r . c a l c u l a P e r m e t r o ( 2 , 3 ) ) ;

5.1

Atributos

Assim como no exemplo do teatrinho dos objetos onde os jogadores tinham como caracterstica o time e o nmero da camisa (atributos), tambm podemos ter algo semelhante para o caso dos retngulos. Podemos fazer com que os dados sobre os lados sejam caractersticas dos objetos. Isto feito da seguinte forma:

5.1. ATRIBUTOS

27

c l a s s Retngulo2 { int lado1 ; int lado2 ; int calcularea () { return lado1 lado2 ; } int calculaPermetro () { return 2 ( lado1 + lado2 ) ; } }

Na classe acima, lado1 e lado2 so atributos que faro parte de todas as instncias da classe Retngulo2. Um atributo, por ser denido fora dos mtodos, pode ser acessados a partir de qualquer mtodo da classe onde ele denido. Atributos so tambm chamados de propriedades ou variveis de instncia. No entanto, no exemplo acima, cou faltando algum mtodo para carregar os valores dos lados nas variveis lado1 e lado2. Poderamos escrever um mtodo para cada atributo ou ento, apenas um mtodo para denir o valor de ambos como no exemplo seguinte:
v o i d c a r r e g a L a d o s ( i n t l 1 , i n t l 2 ) / / e s t e mtodo no d e v o l v e nenhum v a l o r { lado1 = l1 ; lado2 = l2 ; }

Nota Lingstica: void em ingls signica vazio, nada ou nulidade. Assim, quando temos um mtodo que no devolve nenhum valor, como, por exemplo, o mtodo carregaLados acima, colocamos a palavra void antes da denio do mtodo para indicar que ele no devolver nada. Neste caso, no necessrio incluir o comando return no corpo do mtodo. Mesmo assim, podemos usar um comando de retorno vazio para provocar o m prematuro da execuo do mtodo, como em: return ; . O uso do return vazio nem sempre recomendado pois, em alguns casos, pode gerar cdigo pouco claro, mas uma opo permitida pela linguagem. O funcionamento de um objeto da classe Retngulo2 pode ser vericado com o cdigo abaixo:
R e t n g u l o 2 r = new R e t n g u l o 2 ( ) ; r . carregaLados (3 , 5); System . o u t . p r i n t l n ( r . c a l c u l a r e a ( ) ) ; System . o u t . p r i n t l n ( r . c a l c u l a P e r m e t r o ( ) ) ;

Para no perdermos o hbito, tambm veremos como testar esta classe. Neste caso, temos duas opes: criar diversos objetos do tipo Retngulo2, um para cada teste, ou carregar diversos lados no mesmo objeto. Abaixo, a cada chamada de TestePontual, um novo Retngulo2 criado:

28

CAPTULO 5. MTODOS COM VRIOS PARMETROS

class TestaRetngulo { void t e s t e P o n t u a l ( i n t l1 , i n t l 2 ) { R e t n g u l o 2 r = new R e t n g u l o 2 ( ) ; r . c a r r e g a L a d o s ( l1 , l 2 ) ; i f ( r . c a l c u l a r e a ( ) != l 1 l 2 ) System . o u t . p r i n t l n ( " No f u n c i o n a r e a p a r a l a d o s " + l1 + " e " + l2 ) ; i f ( r . c a l c u l a P e r m e t r o ( ) != 2 ( l 1 + l 2 ) ) System . o u t . p r i n t l n ( " No f u n c i o n a p e r m e t r o p a r a l a d o s " + l1 + " e " + l2 ) ; } void testaTudo ( ) { t e s t e P o n t u a l (10 , 20); testePontual (1 , 2); testePontual (3 , 3); } }

Da mesma forma que os lados foram atributos para a classe Retngulo2, podemos fazer o mesmo para a classe Crculo1.
class Crculo2 { double r a i o ; void c a r r e g a R a i o ( double r ) { raio = r ; } double c a l c u l a r e a ( ) { return 3.14159 r a i o r a i o ; } double c a l c u l o P e r m e t r o ( ) { return 3.14159 2.0 r a i o ; } }

Assim como vimos anteriormente podemos tambm utilizar objetos de uma classe sem conhecer a sua implementao. Por exemplo, suponha que temos acesso a uma classe Clculo que possui o seguinte mtodo:
int calculaPotncia ( int x , int n );

Para calcular a potncia poderamos ter o seguinte trecho de cdigo:


C l c u l o c = new C l c u l o ( ) ; System . o u t . p r i n t l n ( " 2 e l e v a d o a 5 i g u a l a : " + c . c a l c u l a P o t n c i a ( 2 , 5 ) ) ;

5.2. A IMPORTNCIA DA ESCOLHA DE BONS NOMES

29

5.2

A importncia da escolha de bons nomes

A caracterstica mais importante em um programa de computador a clareza do seu cdigo. Quanto mais fcil for para um programa ser entendido por um ser humano que o leia, melhor ser o cdigo. Portanto, fundamental que os nomes das variveis, classes e mtodos sejam escolhidos com muito cuidado e critrio. Programadores inexperientes (e alguns no to inexperientes assim mas descuidados) tendem a no dar importncia a este ponto que essencial para o desenvolvimento de software de boa qualidade. Os nomes das variveis devem indicar claramente o seu signicado, isto , devem explicar o que o contedo que elas guardam. Por exemplo, na classe Crculo1 descrita no incio deste captulo, a escolha do nome raio para a varivel perfeita porque ela no deixa a menor dvida sobre o que a varivel ir guardar. Se ao invs de raio, o programador tivesse escolhido x como nome da varivel, isto seria pssimo pois o nome x no traria informao nenhuma para o leitor do programa sobre o seu signicado. Se o programador tivesse dado o nome r para a varivel, a escolha no chegaria a ser pssima, pois o r traz alguma informao, mesmo que sutil. Mas, mesmo assim, no seria uma soluo to boa quanto nomear como raio, pois este no deixa a menor dvida. Portanto, importante no ter preguia de pensar em bons nomes e de escrever nomes um pouco mais longos. Por exemplo, o nome nmeroDeAlunos muito melhor do que nda e melhor do que numAlun. Quanto menor o esforo mental do leitor para compreender o programa, maior sero os ganhos a mdio e longo prazos. A economia de alguns segundos que obtemos com o uso de nomes abreviados pode facilmente se tornar em horas de dor de cabea no futuro. A escolha dos nomes de classes e mtodos tambm deve ser feita criteriosamente. Normalmente as classes representam tipos de objetos do mundo real ou do mundo virtual que estamos criando dentro do computador. Portanto, o mais comum usarmos substantivos como nome para classes (embora esta no seja uma regra obrigatria). Os nomes das classes tem que explicar muito bem qual o tipo de objeto que ela ir representar. Por exemplo, chamar uma classe de Aluno e depois usar objetos desta classe para guardar as notas de um aluno e calcular sua mdia, no uma boa escolha. Provavelmente, neste caso, NotasDeAluno seria um nome melhor. Os mtodos representam aes que so realizadas, normalmente manipulando os atributos da classe. Portanto, normalmente utiliza-se verbos no imperativo para nomear os mtodos (novamente, esta no uma regra obrigatria). Por exemplo, os mtodos calcularea, calculaPermetro, carregaLados e testaTudo atendem bem a este critrio. Portanto, antes de escrever sua prxima classe, mtodo ou varivel, no se esquea: nomes so importantes!

Exerccios
1. Neste exerccio, construiremos uma classe que calcula a mdia aritmtica de 4 notas e diz se o dono das notas foi aprovado, est de recuperao ou foi reprovado. Por exemplo, Entrada: 8.7, 7.2, 9.3, 7.4 5.2, 3.4, 6.5, 2.1 3.4, 5.1, 1.1, 2.0

30 Sada: Mdia: 8.15 -> aprovado. Mdia: 4.3 -> recuperao. Mdia: 2.9 -> reprovado.

CAPTULO 5. MTODOS COM VRIOS PARMETROS

Para isso, crie uma classe Aluno com mtodos que carreguem as 4 notas em variveis p1, p2, p3, p4 e um mtodo responsvel por calcular a mdia aritmtica das notas e dar o veredito. 2. Escreva uma classe Ol com um nico mtodo cumprimenta que, a cada chamada, cumprimenta o usurio de uma entre 3 maneiras diferentes. Dica: use um atributo para, dependendo de seu valor, escolher qual das maneiras ser usada; depois de imprimir a mensagem, altere o valor do atributo. 3. Construa a classe Inteiro que representa um nmero inteiro. Essa classe deve ter os seguintes atributos e mtodos: Classe Inteiro Atributos: int valor Valor do inteiro representado. Mtodos para interao com o usurio da classe: void carregaValor(int v) Muda o valor representado por este objeto. O novo valor deve ser v. int devolveValor() Devolve o valor representado por este objeto. int devolveValorAbsoluto() Devolve o valor absoluto do valor representado por este objeto. void imprime() Imprime algo que representa este objeto. Sugesto: imprima o seu valor. Exemplo de uso no DrJava: > Inteiro i = new Inteiro(); > i.carregaValor(14); > i.devolveValor() 14 > i.carregaValor(-473158); > i.devolveValor() -473158 > i.devolveValorAbsoluto() 473158 > i.imprime();

5.2. A IMPORTNCIA DA ESCOLHA DE BONS NOMES Valor: -473158. 4. Acrescente classe Inteiro algumas operaes matemticas, implementando os seguintes mtodos: Classe Inteiro Mais mtodos para interao com o usurio da classe: int soma(int v) Soma v ao valor deste objeto (valor + v). Este objeto passa a representar o novo valor, que tambm deve ser devolvido pelo mtodo. int subtrai(int v) Subtrai v do valor deste objeto (valor - v). Este objeto passa a representar o novo valor, que tambm deve ser devolvido pelo mtodo. int multiplicaPor(int v) Multiplica o valor deste objeto por v (valor * v). Este objeto passa a representar o novo valor, que tambm deve ser devolvido pelo mtodo. int dividePor(int divisor) Verica se divisor diferente de zero. Se no, imprime uma mensagem de erro e no faz nada (devolve o valor inalterado). Se for, divide o valor deste objeto por v (valor / divisor, diviso inteira). Este objeto passa a representar o novo valor, que tambm deve ser devolvido pelo mtodo. Exemplo de uso no DrJava: > Inteiro i = new Inteiro(); > i.carregaValor(15); > i.subtrai(20) -5 > i.devolveValor() -5

31

Se quiser, voc tambm pode fazer verses desses mtodos que no alteram o valor representado, apenas devolvem o valor da conta. 5. Crie uma classe TestaInteiro que verica o funcionamento correto da classe Inteiro em diversas situaes. Lembre-se de vericar casos como a diviso por diversos valores. Ao escrever os testes, voc notar que a classe Inteiro tem uma limitao importante no mtodo dividePor. 6. Crie uma classe Aluno2 para calcular a mdia aritmtica de 4 notas. Mas no lugar de um mtodo que recebe 4 parmetros, a classe deve conter 4 mtodos recebeNotaX, onde X = 1, 2, 3 ou 4, para receber as notas das provas, de modo que cada mtodo receba apenas uma nota. A classe deve conter ainda um mtodo imprimeMdia que imprime a mdia nal do aluno, dizendo se ele foi aprovado ou reprovado. Em seguida, escreva uma classe TestaAluno2 que verica se a classe Aluno2 calcula as mdias corretamente.

32 Exemplo de utilizao da classe: > Aluno2 aluno = new Aluno2(); > aluno.recebeNota1(5.0); > aluno.recebeNota2(7.0); > aluno.recebeNota3(9.0); > aluno.recebeNota4(7.0); > aluno.imprimeMedia(); Mdia: 7.0 -> aprovado.

CAPTULO 5. MTODOS COM VRIOS PARMETROS

Captulo 6

if else Encaixados
Quais novidades veremos neste captulo? novidade: if else encaixados; exerccio para reforar o que aprendemos at agora.

No Captulo 4, vimos pela primeira vez o conceito de desvio condicional atravs dos comandos if e else. Entretanto, vimos exemplos iniciais onde apenas um comando simples era executado, no caso, comandos de impresso. Na prtica, comandos if e else podem ser encaixados de forma a criar estruturas muito complexas. Para isto, veremos inicialmente como criar blocos de comandos atravs do seguinte exemplo:
i f (CONDIO) { / / i n c i o do b l o c o COMANDO1; COMANDO2; ... COMANDO ; n }

Neste trecho de cdigo, caso a CONDIO seja verdadeira, os comandos, de 1 a n, so executados seqencialmente. Veremos a seguir que comum que alguns destes comandos sejam tambm comandos de desvio condicional. Vamos iniciar programando uma classe para representar um tringulo retngulo. Ela contm um mtodo que, dados os comprimentos dos lados do tringulo, verica se o mesmo retngulo ou no.
class TrianguloRetngulo { void v e r i f i c a L a d o s ( i n t a , i n t b , i n t c ) { i f ( a b c ! = 0 ) / / nenhum l a d o pode s e r n u l o { i f ( a a == b b + c c ) System . o u t . p r i n t l n ( " T r i n g u l o r e t n g u l o . " ) ; i f ( b b == a a + c c ) System . o u t . p r i n t l n ( " T r i n g u l o r e t n g u l o . " ) ;

33

34
i f ( c c == a a + b b ) System . o u t . p r i n t l n ( " T r i n g u l o r e t n g u l o . " ) ; } } }

CAPTULO 6. IF ELSE ENCAIXADOS

O mtodo acima pode ser chamado da seguinte forma:


T r i a n g u l o R e t n g u l o r = new T r i a n g u l o R e t n g u l o ( ) ; r . verificaLados (1 , 1 , 1); r . verificaLados (3 , 4 , 5);

Limitaes: 1. mesmo que um if seja verdadeiro, ele executa os outros ifs. Em particular, se tivssemos um tringulo retngulo para o qual vrios desses ifs fossem verdadeiros, ele imprimiria esta mensagem vrias vezes (neste exemplo especco, isto no possvel); 2. este mtodo s imprime uma mensagem se os dados correspondem s medidas de um tringulo retngulo, se no um tringulo retngulo, ele no imprime nada. Atravs do uso do else podemos imprimir mensagens armativas e negativas:
class TrianguloRetngulo2 { void v e r i f i c a L a d o s ( i n t a , i n t b , i n t c ) { i f ( a b c ! = 0 ) / / nenhum l a d o pode s e r n u l o { i f ( a a == b b + c c ) System . o u t . p r i n t l n ( " T r i n g u l o r e t n g u l o . " ) ; e l s e i f ( b b == a a + c c ) System . o u t . p r i n t l n ( " T r i n g u l o r e t n g u l o . " ) ; e l s e i f ( c c == a a + b b ) System . o u t . p r i n t l n ( " T r i n g u l o r e t n g u l o . " ) ; else System . o u t . p r i n t l n ( " No t r i n g u l o r e t n g u l o . " ) ; } else System . o u t . p r i n t l n ( " No t r i n g u l o p o i s p o s s u i l a d o de c o m p r i m e n t o n u l o . " ) ; } }

Caso sejam necessrios outros mtodos, como um para o clculo de permetro, interessante colocar os lados como atributos da classe.
class TrianguloRetngulo3 { int a , b , c ; void c a r r e g a L a d o s ( i n t l1 , i n t l2 , i n t l 3 ) { a = l1 ; b = l2 ; c = l3 ;

35
} int calculaPermetro () { return a + b + c ; } void v e r i f i c a L a d o s ( ) { i f ( a b c ! = 0 ) / / nenhum l a d o pode s e r n u l o { i f ( a a == b b + c c ) System . o u t . p r i n t l n ( " T r i n g u l o r e t n g u l o . " ) ; e l s e i f ( b b == a a + c c ) System . o u t . p r i n t l n ( " T r i n g u l o r e t n g u l o . " ) ; e l s e i f ( c c == a a + b b ) System . o u t . p r i n t l n ( " T r i n g u l o r e t n g u l o . " ) ; else System . o u t . p r i n t l n ( " No t r i n g u l o r e t n g u l o . " ) ; } else System . o u t . p r i n t l n ( " No t r i n g u l o p o i s p o s s u i l a d o de c o m p r i m e n t o n u l o . " ) ; } }

Exerccios
1. Voc foi contratado por uma agncia de viagens para escrever uma classe em Java para calcular a converso de reais para dlar de acordo com a taxa de compra e a taxa de venda. Para isso, escreva uma classe ConversorMonetrio que inclua os seguintes mtodos: (a) defineTaxaCompra() e defineTaxaVenda(); (b) imprimeTaxas() que imprime o valor das 2 taxas de converso; (c) vendeDlar() que recebe uma quantia em dlares e devolve o valor correspondente em reais; (d) compraDlar() que recebe uma quantia em dlares e devolve o valor correspondente em reais. Em seguida, escreva uma classe TestaConversorMonetrio que dene diferentes taxas de compra e venda de dlares e, para cada taxa de converso, realiza operaes de compra e venda. 2. Escreva uma classe Baskara que possui 3 atributos do tipo double correspondentes aos coecientes a, b e c de uma equao do segundo grau. Escreva um mtodo para carregar valores nestes atributos e, em seguida, escreva os 4 mtodos seguintes: (a) delta() deve calcular o da frmula de Baskara; (b) nmeroDeRazesReais() deve devolver um inteiro indicando quantas razes reais a equao possui; (c) imprimeRazesReais() deve imprimir as razes reais;

36

CAPTULO 6. IF ELSE ENCAIXADOS (d) imprimeRazesImaginrias() deve imprimir as razes imaginrias. Para calcular a raiz quadrada, voc pode utilizar o mtodo java.lang.Math.sqrt(double x), que recebe um double como parmetro e devolve outro double. Voc pode supor que o primeiro coeciente, a, diferente de 0. 3. Crie uma classe contendo um mtodo que, dado um ponto determinado pelas suas coordenadas x e y, reais, imprime em qual quadrante este ponto est localizado. O primeiro quadrante corresponde aos pontos que possuem x e y positivos, o segundo quadrante a x positivo e y negativo e assim por diante. Para resolver este exerccio, ser necessrio utilizar os operadores < e >. Sua utilizao similar do operador == utilizado at agora. 4. [Desao!] So apresentadas a voc doze esferas de aparncia idntica. Sabe-se que apenas uma delas levemente diferente das demais em massa, mas no se sabe qual e nem se a massa maior ou menor. Sua misso identicar essa esfera diferente e tambm dizer se ela mais ou menos pesada. Para isso voc tem apenas uma balana de prato (que s permite determinar igualdades/desigualdades). Ah, sim, pequeno detalhe: o desao completar a misso em no mais que trs pesagens. Escreva um programa que resolve esse desao. O seu programa deve dar uma resposta correta sempre e tambm informar as trs ou menos pesagens que permitiram concluir a resposta. Como esse problema um tanto complicado, recomendamos que voc implemente o modelo descrito no quadro a seguir. Cada esfera deve ser representada por um inteiro entre 1 e 12. Para representarmos a esfera diferente, usaremos, alm do identicador inteiro, uma varivel booleana que receber o valor true se a esfera for mais pesada ou o valor false se a esfera for mais leve. Importante: note que, para que o problema tenha sentido, o mtodo resolveDesaoDasDozeEsferas no deve de modo algum acessar os atributos esferaDiferente e maisPesada para inferir a resposta. Quem d pistas para este mtodo sobre o valor desses atributos so os mtodos pesa#x#. Lembre-se de que voc tambm pode implementar mtodos adicionais, se achar necessrio ou mais elegante. Ou ainda, se voc j se sente seguro(a), voc pode implementar a(s) sua(s) prpria(s) classe(s). Exemplo de uso no DrJava: > DesafioDasEsferas dde = new DesafioDasEsferas(); > dde.defineEsferaDiferente(4, false); Incio do desafio: esfera 4 mais leve. > dde.resolveDesafioDasDozeEsferas(); Pesagem 1: 1 2 3 4 5 x 6 7 8 9 10. Resultado: (1) lado direito mais pesado. Pesagem 2: 1 2 x 3 4. Resultado: (-1) lado esquerdo mais pesado. Pesagem 3: 1 x 2. Resultado: (0) balana equilibrada. Resposta: esfera 3 mais leve. [Resposta errada!]

37 Note que a resposta est errada! (Alm disso, as pesagens no permitem dar a resposta certa.)

38 Classe DesafioDasEsferas Atributos:

CAPTULO 6. IF ELSE ENCAIXADOS

int esferaDiferente Identicador da esfera com peso diferente. boolean maisPesada Diz se a esfera diferente ou no mais pesada que as demais (isto , true para mais pesada e false para mais leve). int numPesagens Representa o nmero de pesagens realizadas. Mtodos para interao com o usurio: void defineEsferaDiferente(int esfera, boolean pesada) Determina qual a esfera diferente (parmetro esfera), e se ela mais pesada ou no (parmetro pesada). Alm disso, reinicia as pesagens, isto , o nmero de pesagens realizadas volta a ser zero. void resolveDesafioDasDozeEsferas() Resolve o Desao das Doze das Esferas. Este mtodo deve imprimir as 3 (ou menos) pesagens feitas, e no nal a resposta correta. Este mtodo deve se utilizar dos mtodos para uso interno descritos abaixo. Dica: na implementao deste mtodo voc tambm usar uma quantidade grande de ifs e elses encaixados. Mtodos para uso interno da classe: int int int int int int int int int pesa1x1(int pesa2x2(int pesa3x3(int pesa4x4(int d3, int d4) pesa5x5(int d2, int d3, pesa6x6(int d1, int d2, e1, e1, e1, e1, e1, int e1, int int int int int int d4, int d3, d1) e2, int d1, int d2) e2, int e3, int d1, int d2, int d3) e2, int e3, int e4, int d1, int d2, e2, int e2, int int e3, int e4, int e5, int d1, d5) int e3, int e4, int e5, int e6, d4, int d5, int d6)

Os mtodos acima (no formato pesa#x#) funcionam de forma semelhante. Eles representam as possveis pesagens e devolvem o resultado. Os parmetros representam as esferas que so pesadas, os comeados por e (ou seja, e1, e2, ...) representam esferas que vo para o prato esquerdo e os comeados por d (d1, d2, ...) so as do prato direito. Lembrando, cada esfera representada por um inteiro entre 1 e 12. Ento, por exemplo, para comparar as esferas 1, 7 e 3 com as esferas 4, 5 e 6, basta chamar pesa3x3(1,7,3,4,5,6). Os mtodos devem devolver -1 se a balana pender para o lado esquerdo, 0 se os pesos forem iguais ou 1 se a balana pender para o lado direito. Esses mtodos tambm devem incrementar o nmero de pesagens realizadas.

Captulo 7

Programas com Vrios Objetos


Quais novidades veremos neste captulo? Programas com vrios objetos.

At agora, todos os programas que vimos lidavam com apenas um objeto. No entanto, podemos ter programas que lidam com vrios objetos. Estes objetos podem pertencer todos mesma classe ou a classes diferentes. Exemplo: 1. Vrios objetos do mesmo tipo
F l o r r o s a = new F l o r ( ) ; F l o r m a r g a r i d a = new F l o r ( ) ; F l o r f l o r D e L a r a n j e i r a = new F l o r ( ) ; rosa . cor ( " vermelha " ) ; r o s a . aroma ( " m u i t o a g r a d v e l " ) ; m a r g a r i d a . aroma ( " s u t i l " ) ; f l o r D e L a r a n j e i r a . aroma ( " d e l i c i o s o " ) ;

2. Vrios objetos de tipos (classes) diferentes:


C a c h o r r o f l o q u i n h o = new C a c h o r r o ( ) ; Gato mingau = new Gato ( ) ; R a t o t o p o G i g g i o = new R a t o ( ) ; Vaca mimosa = new Vaca ( ) ; floquinho . lata ( ) ; mingau . mie ( ) ; to poGi ggio . comaQueijo ( ) ; mingau . p e r s i g a ( t o p o G i g g i o ) f l o q u i n h o . p e r s i g a ( mingau ) ; mimosa . p a s s e P o r C i m a ( f l o q u i n h o , mingau , t o p o G i g g i o ) ;

39

40

CAPTULO 7. PROGRAMAS COM VRIOS OBJETOS Vejamos agora um exemplo de utilizao de objetos de 3 tipos diferentes em conjunto. Neste exemplo, teremos 3 classes representando prismas, quadrados e tringulos retngulos e criaremos uma instncia de quadrado, uma de tringulo retngulo e duas de prismas. Note, no exemplo abaixo, que utilizamos um padro diferente para nomear os mtodos que servem para atribuir valores aos atributos. Segundo este padro, muito utilizado por programadores avanados em linguagens como C++ e Smalltalk, o nome do mtodo exatamente o nome do atributo correspondente. Por exemplo, o mtodo void altura(double a) utilizado para denir o valor do atributo altura e assim por diante. Ao escrever seus programas, voc livre para escolher entre qualquer um dos padres existentes, mas importante que voc seja coerente, ou seja, aps escolher o padro de nomeao, aplique-o consistentemente em todo o seu cdigo.
c l a s s Prisma { double a l t u r a ; double reaDaBase ; void a l t u r a ( double a ) { altura = a; } void reaDaBase ( double a ) { reaDaBase = a ; } d o u b l e volume ( ) { return reaDaBase a l t u r a ; } } c l a s s Quadrado { double l a d o ; void l a d o ( double l ) { lado = l ; } double r e a ( ) { return lado lado ; } } class TrianguloRetngulo { double c a t e t o 1 ; double c a t e t o 2 ;

41
/ / note a indentao supercompacta ! void c a t e t o 1 ( double c ) { c a t e t o 1 = c ; } void c a t e t o 2 ( double c ) { c a t e t o 2 = c ; } double r e a ( ) { return c a t e t o 1 c a t e t o 2 / 2 . 0 ; } }

Agora, utilizando o interpretador, podemos criar objetos destes vrios tipos e utiliz-los em conjunto:
Quadrado q = new Quadrado ( ) ; T r i a n g u l o R e t n g u l o t r = new T r i a n g u l o R e t n g u l o ( ) ; P r i s m a p r i s m a B a s e Q u a d r a d a = new P r i s m a ( ) ; P r i s m a p r i s m a B a s e T r i a n g u l a r = new P r i s m a ( ) ; q . lado ( 1 0 . 0 ) ; tr . cateto1 (20.0); tr . cateto2 (30.0); prismaBaseQuadrada . a l t u r a ( 3 . 0 ) ; prismaBaseTriangular . altura ( 1 . 0 ) ; prismaBaseQuadrada . reaDaBase ( q . r e a ( ) ) ; p r i s m a B a s e T r i a n g u l a r . reaDaBase ( t r . r e a ( ) ) ; i f ( p r i s m a B a s e Q u a d r a d a . volume ( ) > p r i s m a B a s e T r i a n g u l a r . volume ( ) ) System . o u t . p r i n t l n ( "O p r i s m a de b a s e q u a d r a d a tem m a i o r volume " ) ; e l s e i f ( p r i s m a B a s e T r i a n g u l a r . volume ( ) > p r i s m a B a s e Q u a d r a d a . volume ( ) ) System . o u t . p r i n t l n ( "O p r i s m a de b a s e t r i a n g u l a r tem m a i o r volume " ) ; else System . o u t . p r i n t l n ( " Ambos o s p r i s m a s tm o mesmo volume " ) ;

Nota sobre o interpretador do DrJava: para conseguir digitar todos os ifs encaixados no interpretador do DrJava sem que ele tente interpretar cada linha em separado, preciso utilizar Shift+Enter em vez de apenas Enter no nal de cada linha dos ifs encaixados. Apenas no nal da ltima linha (a que contm o println nal) que se deve digitar apenas Enter para que o DrJava ento interprete todas as linhas de uma vez.

Exerccios
1. Utilizando a classe Conversor5 denida no exerccio 1 do Captulo 3, escreva uma classe contendo trs mtodos, onde cada mtodo recebe uma temperatura x utilizando uma escala de temperaturas e imprime os valores de x nas demais escalas de temperatura. 2. Escreva uma classe Rendimentos que contenha os seguintes mtodos a m de contabilizar o total de rendimentos de uma certa pessoa em um certo ano:

42

CAPTULO 7. PROGRAMAS COM VRIOS OBJETOS rendimentosDePessoaFsica(double); rendimentosDePessoaJurdica(double); rendimentosDeAplicaesFinanceiras(double); rendimentosNoTributveis(double); double totalDeRendimentosTributveis(); Em seguida, escreva uma classe TabelaDeAlquotas que possui: um mtodo alquota() que recebe como parmetro o total de rendimentos tributveis de uma pessoa e devolve um nmero entre 0 e 1.0 correspondente alquota de imposto que a pessoa dever pagar e um mtodo valorADeduzir() que recebe como parmetro o total de rendimentos tributveis de uma pessoa e devolve o valor a deduzir no clculo do imposto. Para escrever esta classe, utilize a tabela do IR 2006 abaixo: Rendimentos Tributveis At R$ 13.968,00 De R$ 13.968,01 a R$ 27.912,00 acima de R$ 27.912,00 Alquota 0.15 0.275 Parcela a deduzir R$ 1.904,40 R$ 5.076,90

Agora escreva uma classe CalculadoraDeImposto que possui um nico mtodo que recebe como parmetro o valor dos rendimentos tributveis de uma pessoa e devolve o valor do imposto a ser pago. Finalmente, escreva um trecho de cdigo (para ser digitado no interpretador) que utiliza Rendimentos para denir os vrios rendimentos de uma pessoa e CalculadoraDeImposto para calcular o imposto a pagar. 3. Suponha que voc tenha as seguintes classes:
class A { d o u b l e a ( i n t meses , d o u b l e t a x a ) { r e t u r n Math . pow ( ( t a x a + 1 0 0 ) / 1 0 0 , meses ) 1 ; } } class B { f i n a l d o u b l e TAXA = 1 . 2 ; v o i d b ( d o u b l e v a l o r E m p r e s t a d o , i n t meses ) { A a = new A ( ) ; d o u b l e v a l o r D a D v i d a = v a l o r E m p r e s t a d o + ( a . a ( meses , TAXA) v a l o r E m p r e s t a d o ) ;

43
System . o u t . p r i n t l n ( " D v i d a de " + v a l o r D a D v i d a + " r e a l ( i s ) , " + " c a l c u l a d a com t a x a de " + TAXA + "% ao ms . " ) ; } }

(a) O que fazem os mtodos a (da classe A) e b (da classe B)? No precisa entrar em detalhes. Dica: para saber o que Math.pow faz consulte a pgina http://java.sun.com/j2se/1.5.0/docs/ api/java/lang/Math.html; (b) Os nomes a e b (dos mtodos) e A e B (das classes) so pssimos. Por qu? Que nomes voc daria? Sugira, tambm, outro nome para a varivel objeto (criada no interpretador); (c) Acrescente alguns comentrios no cdigo do mtodo b; (d) Seria mais fcil digitar o valor 1.2 quando necessrio, em vez de criar uma constante TAXA e utilizla. Ento, por que isso foi feito? Cite, pelo menos, dois motivos. A palavra chave final faz com que o valor da varivel TAXA, uma vez atribudo, no possa ser alterado.

44

CAPTULO 7. PROGRAMAS COM VRIOS OBJETOS

Captulo 8

Laos e Repeties
Quais novidades veremos neste captulo? A idia de laos em linguagens de programao; O lao while; O operador que calcula o resto da diviso inteira: %.

8.1

Laos em linguagens de programao

Vamos apresentar para vocs um novo conceito fundamental de programao: o lao. Mas o que pode ser isso? Um nome meio estranho, no? Nada melhor do que um exemplo para explicar. Vamos voltar ao nosso velho conversor de temperatura. Imagine que voc ganhou uma passagem para Nova Iorque e que os EUA no esto em guerra com ningum. Voc arruma a mala e se prepara para a viagem. Antes de viajar voc resolve conversar com um amigo que j morou nos EUA. Ele acaba lhe dando uma dica: guarde uma tabelinha de converso de temperaturas de Fahrenheit para Celsius. Ela ser muito til, por exemplo, para entender o noticirio e saber o que vestir no dia seguinte. Voc ento se lembra que j tem um conversor pronto. Basta ento us-lo para montar a tabela. Voc chama ento o DrJava e comea uma nova sesso interativa. Welcome to DrJava. > Conversor4 c = new Conversor4() > c.fahrenheitParaCelsius(0) -17.77777777777778 > c.fahrenheitParaCelsius(10) -12.222222222222221 > c.fahrenheitParaCelsius(20) -6.666666666666667 > c.fahrenheitParaCelsius(30) -1.1111111111111112 45

46 > c.fahrenheitParaCelsius(40) 4.444444444444445 > c.fahrenheitParaCelsius(50) 10.0 > c.fahrenheitParaCelsius(60) 15.555555555555555 > c.fahrenheitParaCelsius(70) 21.11111111111111 > c.fahrenheitParaCelsius(80) 26.666666666666668 > c.fahrenheitParaCelsius(90) 32.22222222222222 > c.fahrenheitParaCelsius(100) 37.77777777777778 > c.fahrenheitParaCelsius(110) 43.333333333333336 >

CAPTULO 8. LAOS E REPETIES

Pronto, agora s copiar as linhas acima para um editor de textos, retirar as chamadas ao mtodo fahrenheitParaCelsius (pois elas confundem) e imprimir a tabela. Ser que existe algo de especial nas diversas chamadas do mtodo fahrenheitParaCelsius acima? Todas elas so muito parecidas e fcil adivinhar a prxima se sabemos qual a passada. Ou seja, a lei de formao das diversas chamadas do mtodo simples e bem conhecida. No seria interessante se fosse possvel escrever um trecho de cdigo compacto que representasse essa idia? Para isso servem os laos: eles permitem a descrio de uma seqncia de operaes repetitivas.

8.2

O lao while

O nosso primeiro lao ser o while, a palavra inglesa para enquanto. Ele permite repetir uma seqncia de operaes enquanto uma condio se mantiver verdadeira. Mais uma vez, um exemplo a melhor explicao. Experimente digitar as seguintes linhas de cdigo no painel de interaes do DrJava (lembre-se que para digitarmos as 5 linhas do comando while abaixo, necessrio usarmos Shift+Enter em vez de apenas Enter no nal das 4 linhas iniciais do while): Welcome to DrJava. > int a = 1; > while (a <= 10) { System.out.println("O valor atual de a : " + a); a = a + 1; } o resultado ser o seguinte:

8.2. O LAO WHILE O O O O O O O O O O > valor valor valor valor valor valor valor valor valor valor atual atual atual atual atual atual atual atual atual atual de de de de de de de de de de a a a a a a a a a a : : : : : : : : : : 1 2 3 4 5 6 7 8 9 10

47

Vamos olhar com calma o cdigo acima. Primeiro criamos uma varivel inteira chamada a. O seu valor inicial foi denido como 1. A seguir vem a novidade: o lao while. Como dissemos antes, ele faz com que o cdigo que o segue (e est agrupado usando chaves) seja executado enquanto a condio a <= 10 for verdadeira. Inicialmente a vale 1, por isso este o primeiro valor impresso. Logo depois de imprimir o valor de a, o seu valor acrescido de 1, passando a valer 2. Neste momento o grupo de instrues que segue o while terminou. O que o computador faz voltar linha do while e vericar a condio novamente. Como a agora vale 2, ele ainda menor que 10. Logo as instrues so executadas novamente. Elas sero executadas enquanto a condio for verdadeira, lembra? Mais uma vez, o valor atual de a impresso e incrementado de 1, passando a valer 3. De novo o computador volta linha do while, verica a condio (que ainda verdadeira) e executa as instrues dentro das chaves. Esse processo continua at que o a passe a valer 11, depois do dcimo incremento. Neste instante, a condio torna-se falsa e na prxima vez que a condio do while vericada, o computador pula as instrues dentro das chaves do while. Ufa, isso! Ainda bem que o computador que tem todo o trabalho! Uma das principais qualidades do computador a sua capacidade de efetuar repeties. Ele faz isso de forma automatizada e sem se cansar. O lao uma das formas mais naturais de aproveitarmos essa caracterstica da mquina. Agora vamos ver como esse novo conhecimento pode nos ajudar a montar a nossa tabela de converso de forma mais simples e exvel. Se pensarmos bem, veremos que as operaes realizadas para calcular as temperaturas para tabela so semelhantes ao lao apresentado. S que no lugar de simplesmente imprimir os diferentes valores de uma varivel, para gerar a tabela chamamos o mtodo fahrenheitParaCelsius vrias vezes. Vamos agora adicionar um mtodo novo classe Conversor4, que ter a funo de imprimir tabelas de converso para diferentes faixas de temperatura. O cdigo nal seria:
c l a s s Conversor5 { / C o n v e r t e t e m p e r a t u r a de C e l s i u s p a r a F a h r e n h e i t . / double c e l s i u s P a r a F a h r e n h e i t ( double c e l s i u s ) { return c e l s i u s 9.0 / 5.0 + 32; } / C o n v e r t e t e m p e r a t u r a de F a h r e n h e i t p a r a C e l s i u s . / double f a h r e n h e i t P a r a C e l s i u s ( double f a h r )

48
{ return ( f a h r 3 2 . 0) 5.0 / 9 . 0 ; }

CAPTULO 8. LAOS E REPETIES

/ I m p r i m e uma t a b e l a de c o n v e r s o F a r a n h e i t => C e l s i u s . / void i m p r i m e T a b e l a F a h r e n h e i t P a r a C e l s i u s ( double i n i c i o , double fim ) { double f a h r = i n i c i o ; double c e l s i u s ; w h i l e ( f a h r <= f i m ) { celsius = fahrenheitParaCelsius ( fahr ); System . o u t . p r i n t l n ( f a h r + " F = " + c e l s i u s + "C" ) ; fahr = fahr + 10.0; } } }

Muito melhor, no?

8.3

Nmeros primos

Vejamos agora um novo exemplo. Todos devem se lembrar o que um nmero primo: um nmero natural que possui exatamente dois divisores naturais distintos, o 1 e o prprio nmero. Vamos tentar escrever uma classe capaz de reconhecer e, futuramente, gerar nmeros primos. Como podemos reconhecer nmeros primos? A prpria denio nos d um algoritmo. Dado um candidato a primo x, basta vericar se algum inteiro entre 2 e x - 1 divide x. Ento para ver se um nmero primo podemos usar um lao que verica se a diviso exata ocorreu. Porm, ainda falta um detalhe. Como podemos vericar se uma diviso entre nmeros inteiros exata. J sabemos que se dividirmos dois nmeros inteiros em Java a resposta inteira. E o resto da diviso? Felizmente, h um operador especial que devolve o resto da diviso, o operador %. Vejamos alguns exemplos: Welcome to DrJava. > 3 / 2 1 > 3 % 2 1 > 5 / 3 1 > 5 % 3 2 > int div = 7 / 5 > int resto = 7 % 5 > div 1

8.3. NMEROS PRIMOS > resto 2 > div*5 + resto 7 > Deu para pegar a idia, no?

49

Agora vamos escrever uma classe contendo um mtodo que verica se um inteiro primo ou no, imprimindo a resposta na tela. O nome que daremos nossa classe GeradorDePrimos. A razo para esse nome car clara no prximo captulo.
c l a s s GeradorDePrimos { / I m p r i m e na t e l a s e um nmero i n t e i r o p o s i t i v o p r i m o ou no . / void v e r i f i c a P r i m a l i d a d e ( i n t x ) { / / Todos o s nmeros i n t e i r o s p o s i t i v o s s o d i v i s v e i s p o r 1 . i n t nmeroDeDivisores = 1; / / O p r i m e i r o c a n d i d a t o a d i v i s o r no t r i v i a l o 2 . int candidatoADivisor = 2; / / T e s t a a d i v i s o p o r t o d o s o s nmeros m e n o r e s ou i g u a i s a x . w h i l e ( c a n d i d a t o A D i v i s o r <= x ) { i f ( x % c a n d i d a t o A D i v i s o r == 0 ) nmeroDeDivisores = nmeroDeDivisores + 1; candidatoADivisor = candidatoADivisor + 1; } / / Imprime a r e s p o s t a . i f ( n m e r o D e D i v i s o r e s == 2 ) System . o u t . p r i n t l n ( x + " p r i m o . " ) ; else System . o u t . p r i n t l n ( x + " no p r i m o . " ) ; } }

Ser que esta a forma mais eciente de implementar este mtodo? Ser que podemos alterar o cdigo para que ele fornea a resposta mais rapidamente? O que aconteceria se quisssemos vericar a primalidade de 387563973. Pense um pouco sobre isso e depois d uma olhada no exerccio 6 deste captulo.

Exerccios
1. Crie uma classe Fatorial com um mtodo calculaFatorial(int x) que calcula o fatorial de x se este for um nmero inteiro positivo e devolve -1 se x for negativo. Adicione o mtodo testaCalculaFatorial() que testa o mtodo calculaFatorial(int x) para diferentes valores de x.

50

CAPTULO 8. LAOS E REPETIES 2. Crie uma classe Mdia contendo um mtodo calculaMdia(int n) que devolve a mdia dos valores 1, 2, 3, ..., n, onde n o valor absoluto de um nmero fornecido ao mtodo. Adicione o mtodo testaCalculaMdia() que testa o mtodo calculaMdia(int n) para diferentes valores de n. 3. Adicione as seguintes funcionalidades classe Conversor5 vista neste captulo: (a) Crie o mtodo imprimeTabelaCelsiusParaFahrenheit, que converte no sentido oposto do mtodo imprimeTabelaFahrenheitParaCelsius. (b) Adicione um parmetro aos mtodos acima que permita a impresso de uma tabela com passos diferentes de 10.0. Ou seja, o passo entre a temperatura atual e a prxima ser dado por esse novo parmetro. 4. Escreva uma classe Fibonacci, com um mtodo imprimeNmerosDeFibonacci (int quantidade), que imprime os primeiros quantidade nmeros da seqncia de Fibonacci. A seqncia de Fibonacci denida da seguinte forma. F1 = 1; F2 = 1; Fn = Fn1 + Fn2 , para todo inteiro positivo n > 2. O mtodo deve ento imprimir F1 , F2 , F3 , . . . , Fquantidade . 5. Abaixo, apresentamos uma pequena variao do mtodo verificaPrimalidade. Ela no funciona corretamente em alguns casos. Voc deve procurar um exemplo no qual esta verso no funciona e explicar o defeito usando suas prprias palavras. Note que a falha sutil, o que serve como alerta: programar uma tarefa difcil, na qual pequenos erros podem gerar resultados desastrosos. Toda ateno pouca!
/ I m p r i m e na t e l a s e um nmero i n t e i r o p o s i t i v o p r i m o ou no . / void v e r i f i c a P r i m a l i d a d e ( i n t x ) { / / Todos o s nmeros i n t e i r o s p o s i t i v o s s o d i v i s v e i s p o r 1 . i n t nmeroDeDivisores = 1; / / O p r i m e i r o c a n d i d a t o a d i v i s o r no t r i v i a l o 2 . int candidatoADivisor = 2; / / T e s t a a d i v i s o p o r t o d o s o s nmeros m e n o r e s ou i g u a i s a x . w h i l e ( c a n d i d a t o A D i v i s o r <= x ) { candidatoADivisor = candidatoADivisor + 1; i f ( x % c a n d i d a t o A D i v i s o r == 0 ) nmeroDeDivisores = nmeroDeDivisores + 1; } / / Imprime a r e s p o s t a . i f ( n m e r o D e D i v i s o r e s == 2 )

8.3. NMEROS PRIMOS


System . o u t . p r i n t l n ( x + " p r i m o . " ) ; else System . o u t . p r i n t l n ( x + " no p r i m o . " ) ; }

51

6. O lao no nosso verificaPrimalidade executado mais vezes do que o necessrio. Na verdade poderamos parar assim que candidatoADivisor chegar a x/2 ou mesmo ao chegar raiz quadrada de x. Pense como mudar o programa levando em considerao estes novos limitantes. 7. Escreva uma classe Euclides, com um mtodo mdc que recebe dois nmeros inteiros a1 e a2, estritamente positivos, com a1 >= a2, e devolve o mximo divisor comum entre eles, utilizando o algoritmo de Euclides. Breve descrio do algoritmo de Euclides (para maiores detalhes, consulte seu professor de lgebra): - Dados a1 e a2, com a1 >= a2, quero o m.d.c.(a1, a2). - Calcule a3 = a1 % a2. - Se a3 = 0, m. A soluo a2. - Calcule a4 = a2 % a3. - Se a4 = 0, m. A soluo a3. - Calcule a5 = a3 % a4. - ... Nota importante: o operador binrio % calcula o resto da diviso de n por m, quando utilizado da seguinte maneira: n % m. Curiosidade: ele tambm funciona com nmeros negativos! Consulte seu professor de lgebra ;-)

52

CAPTULO 8. LAOS E REPETIES

Captulo 9

Expresses e Variveis Lgicas


Quais novidades veremos neste captulo? Condies como expresses lgicas; Variveis booleanas; Condies compostas e operadores lgicos: &&, || e !; Precedncia de operadores.

9.1

Condies como expresses

J vimos que em Java e outras linguagens de programao, as condies exercem um papel fundamental. So elas que permitem que diferentes aes sejam tomadas de acordo com o contexto. Isso feito atravs dos comandos if e while. Mas, o que so condies realmente? Vimos apenas que elas consistem geralmente em comparaes, usando os operadores ==, >=, <=, >, < e !=, entre variveis e/ou constantes. Uma caracterstica interessante em linguagens de programao que as condies so na verdades expresses que resultam em verdadeiro ou falso. Vamos ver isso no DrJava: Welcome to DrJava. > 2 > 3 false > 3 > 2 true > int a = 2 > a == 2 true > a >= 2 true 53

54 > a < a + 1 true >

CAPTULO 9. EXPRESSES E VARIVEIS LGICAS

Vejam que cada vez que digitamos uma condio o DrJava responde true (para verdadeiro) ou false (para falso). Para entender bem o que ocorre, melhor imaginar que em Java as condies so expresses que resultam em um dos dois valores lgicos: verdadeiro ou falso. Neste sentido, Java tambm permite o uso de variveis para guardar os resultados destas contas, como vemos abaixo. > boolean comp1 = 2 > 3 > comp1 false > int a = 3 > boolean comp2 = a < a + 1 > comp2 true > Com isso, acabamos de introduzir mais um tipo de varivel, somando-se aos tipos int e double j conhecidos: o tipo boolean, que usado em variveis que visam conter apenas os valores booleanos (verdadeiro ou falso). O nome uma homenagem ao matemtico ingls George Boole (1815-1864). Em portugus este tipo de varivel chamada de varivel booleana Agora que comeamos a ver as comparaes como expresses que calculam valores booleanos, tornase mais natural a introduo dos operadores lgicos. Ns todos j estamos bem acostumados a condies compostas. Algo como eu s vou praia se tiver sol e as ondas estiverem boas. Nesta sentena a conjuno e une as duas condies em uma nova condio composta que verdadeira somente se as duas condies que a formam forem verdadeiras. Em Java o e lgico representado pelo estranho smbolo &&. Ou seja, uma condio do tipo 1 <= a <= 10 seria escrita em Java como a >= 1 && a <= 10. Da mesma forma temos um smbolo para o ou lgico. Ele o smbolo ||. Isso mesmo, duas barras verticais. Por m, o smbolo ! antes de uma expresso lgica nega o seu valor. Por exemplo, a condio "a no igual a 0"poderia ser escrita em Java como !(a == 0)1 .

Tabelas da verdade contm todos os resultados que podem ser obtidos ao se aplicar uma operao lgica sobre variveis booleanas. Abaixo apresentamos as tabelas da verdade para os operadores &&, || e !. && (e) true false true true false false false false || (ou) true false true true true false true false ! (no) true false false true

1 Da

vem a explicao para o fato do sinal de diferente conter o ponto de exclamao.

9.1. CONDIES COMO EXPRESSES

55

Por m, podemos montar expresses compostas unindo, atravs dos operadores descritos acima, condies simples ou respostas de expresses lgicas anteriores que foram armazenadas em variveis booleanas. Mais uma vez um exemplo vale mais que mil palavras. Welcome to DrJava. > (2 > 3) || (2 > 1) true > boolean comp1 = 2 > 3 > comp1 false > comp1 && (5 > 0) false > !(comp1 && (5 > 0)) true > int a = 10 > (a > 5) && (!comp1) true > boolean comp2 = (a > 5) && comp1 > comp2 false > Tambm podemos misturar operadores aritmticos e comparadores, sempre que isso faa sentido. Por exemplo, > (a - 10) > 5 false > a - (10 > 5) koala.dynamicjava.interpreter.error.ExecutionError: Bad type in subtraction > Note que a ltima expresso resultou em um erro. Anal de contas, ela pede para somar, a uma varivel inteira, o resultado de uma expresso cujo valor booleano, misturando tipos. Isto no faria sentido em Java. Outra coisa que pode ser feita a criao de mtodos que devolvem um valor booleano. Assim a resposta dada por esses mtodos pode ser usada em qualquer lugar onde uma condio faa sentido, como um if ou um while. Por exemplo, se alterarmos o mtodo verificaPrimalidade, dado no captulo anterior, para devolver a resposta (se o nmero primo ou no), em vez de imprimir na tela, teramos o seguinte mtodo Primo:
/ V e r i f i c a s e um nmero i n t e i r o p o s i t i v o p r i m o ou no . / boolean Primo ( i n t x ) { i f ( x < 2) return f a l s e ; / / Todos o s nmeros i n t e i r o s p o s i t i v o s s o d i v i s v e i s p o r 1 .

56

CAPTULO 9. EXPRESSES E VARIVEIS LGICAS


i n t nmeroDeDivisores = 1; / / O p r i m e i r o c a n d i d a t o a d i v i s o r no t r i v i a l o 2 . int candidatoADivisor = 2; / / T e s t a a d i v i s o p o r t o d o s o s nmeros m e n o r e s ou i g u a i s a x . w h i l e ( c a n d i d a t o A D i v i s o r <= x ) { i f ( x % c a n d i d a t o A D i v i s o r == 0 ) nmeroDeDivisores = nmeroDeDivisores + 1; candidatoADivisor = candidatoADivisor + 1; } i f ( n m e r o D e D i v i s o r e s == 2 ) return true ; else return f a l s e ;

Note que, desta forma, podemos escrever algo do tipo:


i f ( ! Primo ( x ) ) / / f a a alguma c o i s a

A construo acima deixa muito claro o signicado da expresso, pois a lemos como se no primo x, o que bem prximo do que seria uma frase falada em portugus: se x no primo. Quanto mais prximo for o seu cdigo da linguagem falada, mais fcil ser para outras pessoas o compreenderem; e a clareza do cdigo um dos principais objetivos do bom programador.

9.2

Precedncia de operadores

Como acabamos de apresentar vrios operadores novos, devemos estabelecer a precedncia entre eles. Lembre-se que j conhecemos as regras de precedncia dos operadores aritmticos h muito tempo. J a precedncia dos operadores lgicos coisa nova. A tabela abaixo apresenta os operadores j vistos, listados da precedncia mais alta (aquilo que deve ser executado antes) mais baixa: operadores unrios operadores multiplicativos operadores aditivos operadores de comparao e lgico ou lgico atribuio -! */% +== != > < >= <= && || =

Entre operadores com mesma precedncia, as operaes so computadas da esquerda para a direita. Note, porm, que, nos exemplos acima, abusamos dos parnteses mesmo quando, de acordo com a tabela de precedncia, eles so desnecessrios. Sempre bom usar parnteses no caso de expresses lgicas (ou mistas), pois a maioria das pessoas no consegue decorar a tabela acima. Assim, mesmo que voc tenha uma tima memria, o seu cdigo torna-se mais legvel para a maioria dos mortais.

9.3. EXEMPLOS

57

9.3

Exemplos

Primeiro, vamos retomar o mtodo verificaLados da classe TianguloRetngulo3 vista no Captulo 6. Nele, testamos se no h lado de comprimento nulo. Entretanto, parece mais natural e correto forar todos os lados a terem comprimento estritamente positivo:
i f ( ( a > 0 ) && ( b > 0 ) && ( c > 0 ) ) { / / A q u i vo o s comandos p a r a v e r i f i c a r a c o n d i o p i t a g r i c a . }

Podemos tambm usar condies compostas para escrever uma verso mais rpida do mtodo Primo do captulo anterior.
/ V e r i f i c a s e um nmero i n t e i r o p o s i t i v o p r i m o ou no . / boolean Primo ( i n t x ) { i f ( x < 2) return f a l s e ; / / Todos o s nmeros i n t e i r o s p o s i t i v o s s o d i v i s v e i s p o r 1 . i n t nmeroDeDivisores = 1; / / O p r i m e i r o c a n d i d a t o a d i v i s o r no t r i v i a l o 2 . int candidatoADivisor = 2; / / T e s t a a d i v i s o p o r t o d o s o s nmeros m e n o r e s ou i g u a i s a x / 2 ou / / at encontrar o primeiro divisor . w h i l e ( ( c a n d i d a t o A D i v i s o r <= x / 2 ) && ( n m e r o D e D i v i s o r e s == 1 ) ) { i f ( x % c a n d i d a t o A D i v i s o r == 0 ) nmeroDeDivisores = nmeroDeDivisores + 1; candidatoADivisor = candidatoADivisor + 1; } i f ( n m e r o D e D i v i s o r e s == 1 ) return true ; else return f a l s e ; }

Melhor ainda podemos nalmente escrever a classe GeradorDePrimos de forma completa. O mtodo mais interessante o prximoPrimo que devolve o primeiro nmero primo maior do que o ltimo gerado. Este exemplo j bem sosticado, vocs tero que estud-lo com calma. Uma sugesto: tentem entender o que o programa faz, um mtodo por vez. O nico mtodo mais complicado o Primo, mas este ns j vimos.
c l a s s GeradorDePrimos { / / L i m i t e i n f e r i o r p a r a b u s c a de um novo p r i m o . int l i m i t e I n f e r i o r = 1; /

58

CAPTULO 9. EXPRESSES E VARIVEIS LGICAS


P e r m i t e mudar o l i m i t e p a r a cmputo do p r x i m o p r i m o . / void c a r r e g a L i m i t e I n f e r i o r ( i n t l i m i t e ) { limiteInferior = limite ; } / V e r i f i c a s e um nmero i n t e i r o p o s i t i v o p r i m o ou no . / boolean Primo ( i n t x ) { i f ( x < 2) return f a l s e ; / / Todos o s nmeros i n t e i r o s p o s i t i v o s s o d i v i s v e i s p o r 1 . i n t nmeroDeDivisores = 1; / / O p r i m e i r o c a n d i d a t o a d i v i s o r no t r i v i a l o 2 . int candidatoADivisor = 2; / / T e s t a a d i v i s o p o r t o d o s o s nmeros m e n o r e s ou i g u a i s a x / 2 ou / / at encontrar o primeiro divisor . w h i l e ( ( c a n d i d a t o A D i v i s o r <= x / 2 ) && ( n m e r o D e D i v i s o r e s == 1 ) ) { i f ( x % c a n d i d a t o A D i v i s o r == 0 ) nmeroDeDivisores = nmeroDeDivisores + 1; candidatoADivisor = candidatoADivisor + 1; } i f ( n m e r o D e D i v i s o r e s == 1 ) return true ; else return f a l s e ; } / A cada chamada , e n c o n t r a um novo p r i m o m a i o r que l i m i t e I n f e r i o r . / i n t prximoPrimo ( ) { / / Busca o p r i m e i r o p r i m o d e p o i s do l i m i t e . l i m i t e I n f e r i o r = l i m i t e I n f e r i o r + 1; while ( ! Primo ( l i m i t e I n f e r i o r ) ) l i m i t e I n f e r i o r = l i m i t e I n f e r i o r + 1; return l i m i t e I n f e r i o r ; }

Note o uso do atributo limiteInferior no exemplo acima. Ele guarda uma informao importante: o valor do ltimo nmero primo encontrado. importante que ele seja um atributo dos objetos do tipo GeradorDePrimos e no uma varivel local do mtodo prximoPrimo() para que o seu valor sobreviva s sucessivas chamadas ao mtodo prximoPrimo(). Se ele fosse uma varivel local, a cada nova execuo do

9.3. EXEMPLOS

59

mtodo, seu valor seria zerado. No deixem de brincar um pouco com objetos da classe GeradorDePrimos para entender melhor como ela funciona! Agora um desao para vocs: usando o mtodo prximoPrimo, escrevam um novo mtodo void imprimePrimos (int quantidade) que imprime uma dada quantidade de nmeros primos a partir do limiteInferior. Experimentem executar o mtodo no DrJava passando 50 como parmetro.

Exerccios
1. Escreva uma classe TrianguloRetngulo com um mtodo denominado defineLados(double x1, double x2, double x3) que recebe trs valores e verica se eles correspondem aos lados de um tringulo retngulo. Em caso armativo, o mtodo devolve true, caso contrrio ele devolve false. Note que o programa deve vericar quais dos trs valores corresponde hipotenusa. Construa duas verses do mtodo, uma contendo trs ifs e outra contendo apenas um if! Em seguida, crie um novo mtodo que verica se ambos os mtodos retornam o mesmo resultado para diferentes combinaes de x1, x2 e x3. 2. Escreva uma classe Brincadeiras que possua 3 atributos inteiros. Escreva um mtodo para carregar valores nestes atributos e, em seguida, escreva os seguintes mtodos: (a) troca2Primeiros() que troca os valores dos dois primeiros atributos. Por exemplo, se antes da chamada do mtodo o valor dos atributos <1, 2, 3>, depois da chamada, eles devero valer <2, 1, 3>. (b) imprime() que imprime o valor dos 3 atributos. (c) imprimeEmOrdemCrescente() que imprime o valor dos 3 atributos em ordem crescente. 3. A linguagem Java oferece operadores que, se usados corretamente, ajudam na apresentao e digitao do cdigo, tornando-o mais enxuto. Veremos neste exerccio dois deles: os operadores de incremento e de decremento. Verique o funcionamento desses operadores usando os mtodos da classe abaixo.
class Experincia { void verIncremento ( i n t n ) { int x = n ; System . o u t . p r i n t l n ( " Nmero i n i c i a l x > " + x ) ; System . o u t . p r i n t l n ( " x++ > " + x + + ) ; System . o u t . p r i n t l n ( " Novo v a l o r de x > " + x ) ; x = n; System . o u t . p r i n t l n ( " Nmero i n i c i a l x > " + x ) ; System . o u t . p r i n t l n ( " ++x > " + ++x ) ; System . o u t . p r i n t l n ( " Novo v a l o r de x > " + x ) ; } void verDecremento ( i n t n ) { int x = n ; System . o u t . p r i n t l n ( " Nmero i n i c i a l x > " + x ) ; System . o u t . p r i n t l n ( " x > " + x ); System . o u t . p r i n t l n ( " Novo v a l o r de x > " + x ) ;

60

CAPTULO 9. EXPRESSES E VARIVEIS LGICAS

x = n; System . o u t . p r i n t l n ( " Nmero i n i c i a l x > " + x ) ; System . o u t . p r i n t l n ( "x > " + x ) ; System . o u t . p r i n t l n ( " Novo v a l o r de x > " + x ) ; } }

Entenda bem o cdigo e observe os resultados. Em seguida, tire suas concluses e compare-as com as concluses de seus colegas. Alm dos operadores de incremento e decremento, tambm existem os seguintes operadores resumidos: +=, -=, *= e /=. Eles so teis quando queremos efetuar uma operao em uma varivel e guardar o resultado na mesma. Isto , a = a * 2; completamente equivalente a a *= 2;.

Captulo 10

Mergulhando no while
Quais novidades veremos neste captulo? Reforo em while; O comando do...while.

10.1

Um pouco mais sobre primos

Vamos iniciar este captulo com dois exerccios. Primeiro, que tal modicarmos o mtodo de gerao de primos para que ele use o fato de que os nicos candidatos a primos maiores do que 2 so mpares? Uma complicao interessante que o limiteInferior para o prximo primo pode ser modicado pelo usurio a qualquer momento chamando carregaLimiteInferior. Isso deve ser contemplado na soluo. Aqui vai a resposta:
/ A cada chamada , c a l c u l a um novo p r i m o s e g u i n d o ordem c r e s c e n t e . / i n t prximoPrimo ( ) { / / Move o l i m i t e i n f e r i o r na d i r e o do p r x i m o p r i m o . / / Temos que c o n s i d e r a r que o l i m i t e i n f e r i o r pode s e r p a r / / p o r q u e e l e pode s e r m o d i f i c a d o a q u a l q u e r momento com uma / / chamada a c a r r e g a L i m i t e I n f e r i o r . i f ( l i m i t e I n f e r i o r == 1 ) l i m i t e I n f e r i o r = 2; e l s e i f ( l i m i t e I n f e r i o r % 2 == 0 ) l i m i t e I n f e r i o r = l i m i t e I n f e r i o r + 1; else l i m i t e I n f e r i o r = l i m i t e I n f e r i o r + 2; / / Encontra o prximo primo while ( ! Primo ( l i m i t e I n f e r i o r ) ) l i m i t e I n f e r i o r = l i m i t e I n f e r i o r + 2;

61

62

CAPTULO 10. MERGULHANDO NO WHILE

return l i m i t e I n f e r i o r ; }

Nosso prximo desao criar uma nova classe ManipuladorDeInteiros. Ela deve conter o mtodo fatoraInteiro que deve imprimir a decomposio em primos de um inteiro positivo maior ou igual a 2. Uma dica importante usar o GeradorDePrimos Antes de ler soluo colocada abaixo, tente com anco fazer o exerccio sozinho.
class ManipuladorDeInteiros { / F a t o r a em p r i m o s um i n t e i r o > 1 . / void f a t o r a I n t e i r o ( i n t x ) { System . o u t . p r i n t ( x + " = " ) ; / / Usa um g e r a d o r de p r i m o s p a r a e n c o n t r a r o s p r i m o s m e n o r e s ou i g u a i s a x . G e r a d o r D e P r i m o s g e r a d o r = new G e r a d o r D e P r i m o s ( ) ; i n t primo = g e r a d o r . prximoPrimo ( ) ; / / C o n t i n u a f a t o r a n d o o nmero a t que x s e t o r n e 1 . while ( x > 1) { i f ( x % p r i m o == 0 ) { System . o u t . p r i n t ( " " + p r i m o ) ; x = x / primo ; } else primo = g e r a d o r . prximoPrimo ( ) ; } / / I m p r i m e um f i m de l i n h a no f i n a l . System . o u t . p r i n t l n ( ) ; } }

Um exemplo de uso do nosso ManipuladorDeInteiros: Welcome to DrJava. > ManipuladorDeInteiros m = new ManipuladorDeInteiros() > m.fatoraInteiro(5) 5 = 5 > m.fatoraInteiro(10) 10 = 2 5 > m.fatoraInteiro(18) 18 = 2 3 3 > m.fatoraInteiro(123456) 123456 = 2 2 2 2 2 2 3 643 > m.fatoraInteiro(12345678)

10.2. UMA BIBLIOTECA DE FUNES MATEMTICAS. 12345678 = 2 3 3 47 14593 > m.fatoraInteiro(167890) 167890 = 2 5 103 163 >

63

Obs: Note que na soluo usamos uma rotina de impresso nova: System.out.print. Ela muito parecida com System.out.println com a diferena de que no muda a linha ao terminar de imprimir.

10.2

Uma biblioteca de funes matemticas.

Terminamos com um exerccio clssico. Vamos mostrar como construir uma pequena biblioteca de funes matemticas avanadas. Com ser que o computador consegue calcular senos, cossenos, logaritmos? O segredo para implementar essas funes em Java um bom conhecimento de clculo e laos. Usando clculo, sabemos que essas funes matemticas complicadas possuem expanses de Taylor. Estas expanses transformam uma funo numa srie de polinmios1 , que podem ser facilmente calculados usando laos. Vejamos a expanso de algumas dessas funes: sen(x) =
x 1!

x + x . . . + (1) x 3! 5! (2k+1)! + . . .
2 4 6 k (2k)

k (2k+1)

cos(x) = 1 x + x x + . . . + (1) x 2! 4! 6! (2k)!


2 3 4

+... +...

ln(1 + x) = x x2 + x3 x4 + . . . + (1) k Isso funciona bem sempre que |x| < 1.

(k1) xk

O segredo para usar essas frmulas no computador continuar somando at que o mdulo do prximo termo seja muito pequeno e por isso possa ser desprezado. Antes de apresentarmos aqui a soluo que consideramos ideal, faa com cuidado e ateno os exerccios 1 (implementao das funes double pot(double x, int y) e double fat(double x)) e 2 (implementao da funo double sen(double x) usando as funes do exerccio 1. Agora, aps termos feito os exerccios 1 e 2, iremos criar uma nova classe, que chamaremos Matemtica, com mtodos para calcular funes como as apresentadas acima. Abaixo vemos a classe com uma funo que calcula sen(x) implementada. Compare esta forma de implementar com as formas usadas no exerccio. Qual mais rpida? Qual mais fcil de entender?
c l a s s Matemtica { / / C o n t r o l a o s i g n i f i c a d o de " p e q u e n o " . d o u b l e e p s i l o n = 1 . 0 e 8; double sen ( double x ) { int k = 1; double termo = x ; double seno = termo ;
1 Mais

informaes sobre sries de Taylor podem ser encontradas em livros de Clculo.

64

CAPTULO 10. MERGULHANDO NO WHILE


while ( termo termo > e p s i l o n e p s i l o n ) { / / muito mais f c i l c o n s t r u i r o prximo termo usando o a n t e r i o r . k = k + 2; t e r m o = t e r m o x x / ( k 1 ) / k ; seno = seno + termo ; } return seno ; }

Um exemplo de uso: Welcome to DrJava. > m = new Matemtica(); > m.sen(0.3) 0.2955202066613839 > m.sen(0.5) 0.4794255386164159 > m.sen(3.141596/2.0) 0.9999999999925767 >

10.3 do...while
Para complementar os laos possveis em Java, vejamos uma pequena variao do while. Nele a condio testada sempre antes de execuo do corpo de comandos que compe o lao. J o lao do...while tem a condio testada apenas no nal. Conseqentemente, no caso do do...while, existe a garantia que o contedo no interior do lao ser executado pelo menos uma vez, enquanto no while este pode nunca ser executado. Na prtica, a existncia destes dois tipos de laos uma mera convenincia sinttica, j que um pode ser facilmente substitudo pelo outro. Vejamos um exemplo de utilizao do do...while:
int f a t o r i a l ( int x) { int resultado = 1; do { resultado = resultado x; x = x 1; } while ( x > 1) return r e s u l t a d o ; }

10.3. DO...WHILE

65

Exerccios
1. Implemente na classe Matemtica as funes double pot(double x, int y) que calcula xy e double fat(double x) que calcula x! 2 . 2. Implemente na classe Matemtica a funo double sen(double x) utilizando-se das funes double pot(double x, int y) e int fat(int x) do tem anterior. 3. Implemente na classe Matemtica funes para calcular cos(x) e ln(1 + x). Note que para implementar o ln(1 + x) deve-se criar uma funo double ln(double x) e no interior da funo denir uma varivel local x2 = 1 - x de modo que se possa calcular ln(1 + x2). 4. Escreva uma classe TestaMatemtica que utiliza os mtodos matemticos java.lang.Math.sen(), java.lang.Math.cos(), java.lang.Math.pow() e java.lang.Math.log(), disponveis na biblioteca Java, para testar os respectivos mtodos implementado por voc nos exerccios anteriores. Os mtodos de TestaMatemtica devem receber um parmetro double epsilon que determina a diferena mxima aceitvel entre o valor devolvido pela sua implementao com relao ao da implementao da biblioteca Java. Qualquer dvida sobre a utilizao destes mtodos, consulte a documentao online do Java3 . 5. O enunciado deste exerccio bem mais complexo que a soluo, por isso no tenha medo! Imagine um quadrado em um plano e uma reta paralela a um dos lados do quadrado: a projeo do quadrado sobre a reta tem exatamente o mesmo comprimento que o lado do quadrado. Imagine agora que este quadrado seja girado sobre o plano; a projeo do quadrado sobre a reta tem um novo tamanho. Crie uma classe Projetor que possua um mtodo gira que aceite como parmetro o nmero de graus que o quadrado deve girar em relao sua posio anterior e imprima na tela o tamanho da projeo do quadrado sobre a reta. Note que se o usurio executar o mtodo duas vezes, com os parmetros 22 e 35, sua classe deve responder qual o tamanho da projeo para inclinaes do quadrado de 22 e 57 graus. Escreva 3 solues para este exerccio: uma que voc considere elegante e clara, uma com um nico mtodo e uma com o mximo nmero possvel de mtodos. Utilize os mtodos sen() e cos() desenvolvidos neste captulo. Utilize agora os mtodos java.lang.Math.cos() e java.lang.Math.sin() disponveis na biblioteca Java, que calculam, respectivamente, o coseno e o seno do ngulo passado como parmetro em radianos (graus * PI/180 = radianos). Compare os resultados com os obtidos com nossas implementaes de sen() e cos().

2 Apesar do clculo de fatorial s usar inteiros, com o tipo int pode se calcular at 16!, e com o tipo long at 20!. Com o tipo double possvel calcular fatoriais maiores, mas com menos dgitos signicativos. 3 http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Math.html.

66

CAPTULO 10. MERGULHANDO NO WHILE

Captulo 11

Caracteres e Cadeias de Caracteres


Quais novidades veremos neste captulo? Introduo do tipo char; Uma classe da biblioteca padro: String.

11.1

Um tipo para representar caracteres

At o momento j vimos diferentes tipos de variveis, como os inteiros (int) e os reais (double). Alm disto, tambm vimos as variveis booleanas, que podem ter apenas dois valores, verdadeiro ou falso (boolean). Parece intuitivo que as linguagens de programao tambm ofeream variveis para a manipulao de caracteres. No caso de Java temos o tipo char. Vejamos um exemplo de uso:
class Caractere1 { v o i d v e r i f i c a R e s p o s t a ( char ch ) { i f ( ( ch == s ) | | ( ch == S ) ) System . o u t . p r i n t l n ( "A r e s p o s t a f o i sim " ) ; e l s e i f ( ( ch == n ) | | ( ch == N ) ) System . o u t . p r i n t l n ( "A r e s p o s t a f o i no " ) ; else System . o u t . p r i n t l n ( " R e s p o s t a i n v l i d a " ) ; } }

No exemplo acima podemos ver que para se representar um caractere usamos aspas simples (). Tambm podemos ver que os caracteres minsculos so diferentes do mesmo caractere maisculo. Um outro exemplo um pouco mais elaborado pode ser visto abaixo:
class Caracteres {

67

68

CAPTULO 11. CARACTERES E CADEIAS DE CARACTERES


v o i d i m p r i m e C a r a c t e r e s ( char ch , i n t n ) { int i = 0; while ( i < n ) { System . o u t . p r i n t ( ch ) ; i = i + 1; } }

Neste exemplo, so impressos diversos caracteres do mesmo tipo. Observe abaixo como podemos adicionar um novo mtodo para desenhar letras grandes:
class Caracteres { v o i d i m p r i m e C a r a c t e r e s ( char ch , i n t n ) { int i = 0; while ( i < n ) { System . o u t . p r i n t ( ch ) ; i = i + 1; } } void novaLinha ( ) { System . o u t . p r i n t l n ( ) ; } v o i d i m p r i m e C a r a c t e r e s N L ( char ch , i n t n ) { i m p r i m e C a r a c t e r e s ( ch , n ) ; novaLinha ( ) ; } void desenhaE ( ) { imprimeCaracteresNL ( , 2 0 ) ; i m p r i m e C a r a c t e r e s N L ( E , 1 5 ) ; i m p r i m e C a r a c t e r e s N L ( E , 1 4 ) ; i m p r i m e C a r a c t e r e s N L ( E , 3 ) ; i m p r i m e C a r a c t e r e s N L ( E , 3 ) ; i m p r i m e C a r a c t e r e s N L ( E , 1 3 ) ; i m p r i m e C a r a c t e r e s N L ( E , 1 3 ) ; i m p r i m e C a r a c t e r e s N L ( E , 3 ) ; i m p r i m e C a r a c t e r e s N L ( E , 3 ) ; i m p r i m e C a r a c t e r e s N L ( E , 1 4 ) ; i m p r i m e C a r a c t e r e s N L ( E , 1 5 ) ; imprimeCaracteresNL ( , 2 0 ) ; } }

11.2. CADEIAS DE CARACTERES (STRINGS) A sada do programa : ******************** EEEEEEEEEEEEEEE EEEEEEEEEEEEEE EEE EEE EEEEEEEEEEEEE EEEEEEEEEEEEE EEE EEE EEEEEEEEEEEEEE EEEEEEEEEEEEEEE *********************

69

Para desenharmos letras onde necessrio intercalar espaos e letras em uma nica linha, a implementao ca um pouco mais longa. Os diferentes mtodos que imprimem caracteres pulando ou sem pular linha sero usados. Por exemplo, para a letra U, a primeira linha deve ser impressa como:
i m p r i m e C a r a c t e r e s ( U , 3 ) ; imprimeCaracteres ( , 9); / / e s p a o tambm um c a r a c t e r e i m p r i m e C a r a c t e r e s N L ( U" , 3 ) ;

11.2

Cadeias de caracteres (Strings)

Uma forma de escrevermos palavras no computador seria usando grupos de caracteres, entretanto isto depende de um conceito mais avanado que ainda no vimos. A nossa outra opo usar uma classe pronta, que j vem com a linguagem Java, a classe String. Nos nossos primeiros exemplos, j havamos feito algumas operaes com strings, por exemplo:
System . o u t . p r i n t l n ( "O t r i n g u l o r e t n g u l o " ) ; System . o u t . p r i n t l n ( "A r a i z de " + 4 + " i g u a l a " + 2 + " . " ) ;

Agora ns veremos com mais detalhes esta classe String . Podemos ver que o operador + tem um signicado natural o de concatenao. Logo, as seguintes operaes so vlidas:
S t r i n g a = " abc " ; String b = " cdf " ; String c ; c = a + b; System . o u t . p r i n t l n ( c ) ;

Podemos tambm concatenar nmeros a uma String:


S t r i n g a = "O r e s u l t a d o " ; int i = 10; String c ;

70

CAPTULO 11. CARACTERES E CADEIAS DE CARACTERES

c = a + i; System . o u t . p r i n t l n ( c ) ;

Alm disto, existem alguns mtodos pr-denidos na classe String. Entre eles podemos citar: char charAt(int index) - devolve o caractere na posio index. Os ndices em uma String vo de zero ao seu tamanho menos um. Exemplo:
S t r i n g s = " mesa " ; System . o u t . p r i n t l n ( s . c h a r A t ( 0 ) ) ; System . o u t . p r i n t l n ( s . c h a r A t ( 3 ) ) ; / / Imprime / / Imprime m a

boolean endsWith(String suffix) - verica se a String acaba com o suxo dado. Usado, entre outras coisas, para vericar as extenses dos arquivos. Por exemplo, vericar se o nome de um arquivo termina com ".java". int indexOf(char ch) - devolve o ndice da primeira ocorrncia de ch na String ou -1 caso o caractere no ocorra na String. Exemplo:
S t r i n g s 1 = " EP1 . j a v a " ; System . o u t . p r i n t l n ( s 1 . i n d e x O f ( . ) ) ; System . o u t . p r i n t l n ( s 1 . i n d e x O f ( x ) ) ; / / imprime 3 / / i m p r i m e 1

int length() - devolve o tamanho da String. Exemplo:


S t r i n g s 1 = " mesa " ; System . o u t . p r i n t l n ( s 1 . l e n g t h ( ) ) ; / / imprime 4

String toUpperCase() - devolve a String convertida para letras maisculas. Exemplo:


S t r i n g s 1 = " mesa " ; System . o u t . p r i n t l n ( s 1 . t o U p p e r C a s e ( ) ) ; / / i m p r i m e MESA

int compareTo(String outra) - compara duas Strings. Devolve um nmero positivo se a outra for menor, 0 se forem iguais, e um negativo caso contrrio. Exemplo:
S t r i n g s 1 = " mesa " ; S t r i n g s2 = " c a d e i r a " ; System . o u t . p r i n t l n ( s 1 . compareTo ( s 2 ) ) ;

/ / i m p r i m e 10 que > 0

Exerccios
1. Escreva uma classe Linha que possua um mtodo imprimeLinha que, ao ser chamado, imprime uma linha de caracteres X na diagonal, na tela de interaes do DrJava. Use laos while. DICA: voc vai precisar do mtodo System.out.print(), que imprime seu argumento na tela mas no passa para a linha seguinte; imprima linhas com nmero crescente de espaos no comeo e o caractere X no nal.

11.2. CADEIAS DE CARACTERES (STRINGS)

71

2. Escreva uma classe contendo um mtodo que devolve o nmero de ocorrncias da vogal a em uma frase contida em uma String. Crie um teste para vericar o funcionamento desta classe. 3. Implemente uma classe com um mtodo que determina a freqncia relativa de vogais em uma String. Considere que as letras maisculas e minsculas no esto acentuadas. Crie um teste para vericar o funcionamento desta classe.

72

CAPTULO 11. CARACTERES E CADEIAS DE CARACTERES

Captulo 12

A Memria e as Variveis
Quais novidades veremos neste captulo? Organizao da Memria do Computador; O que so variveis.

12.1

A Memria do Computador

Nos computadores modernos, a memria armazena tanto os programas que esto sendo executados quanto os dados por eles manipulados. Grosso modo, podemos dividir a memria em principal e secundria. Memria principal aquela normalmente armazenada em chips conectados placa me do computador; o acesso aos seus dados muito rpido mas, em geral, seus dados so perdidos quando o computador desligado. J a memria secundria armazenada em discos rgidos ou exveis, CDs, DVDs, etc. O acesso aos seus dados mais lento mas eles so armazenados de forma persistente, ou seja, no necessitam de energia eltrica para serem mantidos. Os dados gravados em um CD, por exemplo, mantm-se inalterados por vrios anos at que a degradao do material comece a causar perda de informaes. Quando ativamos um ambiente de desenvolvimento de software como o DrJava ou o Eclipse em nosso computador, o programa do ambiente que estava gravado no disco, lido e copiado para a memria principal do computador. A partir de ento, as informaes que digitamos no ambiente so armazenadas na memria do computador como dados. Quando selecionamos a opo Salvar, os dados da memria principal so copiados para o disco. Podemos visualizar abstratamente a memria do computador como sendo uma rua muito longa com milhes de casas. O endereo de cada casa dado pelo nmero da rua no qual ela se encontra e cada casa armazena um certo contedo. Nos computadores modernos, em cada endereo de memria armazenado um byte formado por 8 bits. O computador utiliza internamente nmeros binrios e com 8 bits consegue armazenar nmero de 0 a 255 (ou de 00000000 at 11111111 em binrio). Combinando duas casas (bytes) adjacentes, o computador consegue armazenar nmeros de 16 bits, ou de 0 a 32767. Um int em Java ocupa 4 bytes e usa uma codicao que capaz de representar nmeros de -2.147.483.648 at 2.147.483.647. Utilizando mais bytes adjacentes e 73

74

CAPTULO 12. A MEMRIA E AS VARIVEIS

outras formas de codicao, possvel armazenar na memria qualquer tipo de informao que podemos imaginar: nmeros positivos e negativos inteiros e fracionrios, letras, textos, imagens, sons, vdeo, etc. Quando dizemos que um computador tem 1GB de memria (1 Giga Byte), queremos dizer que sua memria composta por 230 = 1.073.741.824 bytes. Podemos ento imagin-la como sendo uma rua com pouco mais de 1 bilho de casas (comprida n?), cada uma composta por um byte. Nestes bytes, o computador armazena os programas sendo executados, o cdigo-fonte dos programas Java que digitamos no DrJava, os bytecodes correspondentes s classes Java depois que ns as compilamos, o contedo das variveis que fazem parte de nossos objetos, etc.

12.2

O que so as Variveis?

Variveis so nomes associados a dados em um programa de computador. No caso de Java, isso inclui os atributos de objetos e de classes, parmetros de mtodos e variveis locais. Quando um programa executado, cada varivel associada, em tempo de execuo, a um determinado endereo da memria. Se denimos uma varivel i do tipo int, ela pode ser associada, por exemplo, ao endereo de memria 3.745.908. A partir da, quando atribumos um valor a esta varivel, este valor armazenado nos quatro bytes (porque um int Java ocupa 4 bytes) a partir do endereo 3.745.908 da memria. Em Java, uma varivel associada a um tipo primitivo (int, float, double, boolean e char) tem um comportamento levemente diferente de variveis associadas a objetos complexos como Strings, arrays ou objetos pertencentes a classes denidas pelo programador. Os dados de tipo primitivo so todos muito simples, ocupando pouco espao de memria. Neste caso, fcil guardar nas posies de memria correspondentes a estas variveis o seu valor. Logo, se a e b so variveis de mesmo tipo primitivo, a operao a = b copia em a o valor que est em b, ou seja, copia o contedo dos bytes da memria correspondentes varivel b para os bytes da memria correspondentes varivel a. Dizemos que as variveis a e b armazenam diretamente o seu contedo. Isso explica por que a mudana em um parmetro de tipo primitivo dentro de um mtodo no se reete fora dele. O parmetro alterado dentro do mtodo no tem nenhuma ligao com a varivel que estava em seu lugar no momento da chamada do mtodo (alm, claro, da cpia inicial do seu valor quando o mtodo chamado). J para objetos complexos, como cadeias de caracteres, arrays e qualquer objeto de uma classe denida pelo programador, a situao bem diferente. Estes objetos podem ser muito complicados, ocupando muito espao de memria. Neste caso, o Java no guarda nas variveis uma cpia do objeto, mas sim o endereo de memria no qual este objeto est armazenado. Por este motivo, fala-se que em Java as variveis associadas a objetos complexos so referncias para estes objetos. No momento em que um objeto precisa ser usado, o interpretador Java o localiza a partir de uma referncia para ele armazenada em uma varivel que, por sua vez, est tambm armazenada em um endereo de memria. Esta pequena diferena gera algumas surpresas. Considere que temos uma classe chamada Fruta com um atributo preo e mtodos carregaPreo e imprimePreo. O que ocorre quando executamos o seguinte cdigo?
F r u t a a = new F r u t a ( ) ; a . carregaPreo (10); Fruta b = a ; b . carregaPreo (100); a . imprimePreo ( ) ;

12.2. O QUE SO AS VARIVEIS?

75

Observamos que o preo da fruta a mudou. Isto ocorre porque, aps a terceira linha do trecho acima, a e b passam a ser referncias para o mesmo objeto na memria; como dois apelidos para mesma pessoa. Qualquer coisa que ocorre com o objeto usando um de seus apelidos se reete para a viso do outro apelido. Esse raciocnio explica porque alteraes em objetos complexos dentro de um mtodo se propagam para fora. O parmetro associado a esse objeto tambm um apelido. A diferena entre tipos primitivos e objetos tambm ca evidente quando lidamos com comparaes. Quando se comparam dois tipos primitivos com o operador ==, os valores dos mesmos so vericados. O mesmo no acontece com objetos, o que se comparam so as referncias. Veja o exemplo abaixo: > int a = 5 > int b = 2 > a == b true > String s1 > String s2 > s2 = s2 + > s1 == s2 false

+ 3

= "Bom dia" = "Bom" " " + "dia"

Vemos no exemplo acima que o operador == tem um signicado diferente com relao a objetos. A comparao de igualdade verica se as duas referncias se referem ao mesmo objeto. Na ltima linha do exemplo acima, tanto s1 quanto s2 se referem ao texto "Bom dia" mas as variveis s1 e s2 so referncias a posies diferentes da memria, se referem a dois objetos distintos; portanto, s1 == s2 false.

Exerccios
1. O comparador == no pode ser usado para comparar o contedo de objetos. Neste caso, usa-se o mtodo equals, presente em todos os objetos. Este mtodo recebe como entrada uma outra String e retorna true se as Strings so iguais e false caso contrrio. Faa uma classe com um mtodo que verica se duas Strings tm o mesmo contedo. 2. Vimos neste captulo que a mudanas no valor de um parmetro de tipo primitivo dentro de um mtodo no se reete fora dele. Mas no caso de objetos, alteraes em seu contedo dentro de um mtodo so reetidas fora deste. Suponha que voc deseje criar um mtodo que modica os valores de um par de inteiros de modo que estas modicaes se reitam fora do mtodos. Um bom exemplo um mtodo que recebe como entrada as coordenadas de ponto cartesiano e desloca este ponto em (+1,+1). Pense numa possvel soluo para este problema. Em seguida, implemente sua soluo e verique se ela funciona. 3. Verique o seguinte trecho de cdigo: > String s1 = "Bom dia." > String s2 = s1 > s1 = "Boa noite."

76

CAPTULO 12. A MEMRIA E AS VARIVEIS Qual o valor da varivel s2 aps a execuo deste trecho de cdigo? Pense cuidadosamente na resposta e em seguinte verique-a utilizando o DrJava. Tente explicar o comportamento vericado.

Captulo 13

Manipulando Nmeros Utilizando Diferentes Bases


Quais novidades veremos neste captulo? Como extrair os dgitos de um nmero; Como converter nmeros de uma base para outra.

Neste captulo, aprenderemos como extrair e processar os dgitos de um nmero inteiro e como realizar a converso de um nmero entre diferentes bases. Mas antes, faremos uma introduo aos principais sistemas de numerao utilizados para representar nmeros inteiros.

13.1

Sistemas de numerao

Nmeros inteiros podem ser representados utilizando diferentes sistemas de numerao. Por exemplo, no dia-a-dia, representamos os nmeros utilizando o sistema decimal, isto , utilizamos 10 algarismos para representar os nmeros, dados por {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0}. Um nmero formado pela concatenao destes algarismos, onde a posio dos algarismos determina um valor pelo qual aquele algarismo deve ser multiplicado. Para o sistema decimal, tambm chamado de base 10, este valor de 10 pos , onde pos a posio do algarismo, contada a partir da direita, que possui pos igual a 0 (zero). Por exemplo, o nmero 1256 tem o seu valor dado por: 1 103 + 2 102 + 5 101 + 6 100 = 1000 + 200 + 50 + 6 = 1256 J os computadores representam os dados internamente utilizando o sistema binrio, cujos nmeros so representados pelos algarismo {0, 1}. O motivo para a utilizao de uma base binria se deve ao fato dos computadores trabalharem utilizando apenas dois nveis de voltagem, por exemplo, +5V e 0V . Voltando ao exemplo anterior, o nmero 1256 seria representado na base binria por 100111010002 , pois: 100111010002 = 21 0 + 27 + 26 + 25 + 23 = 1024 + 128 + 64 + 32 + 8 = 1256 77

78

CAPTULO 13. MANIPULANDO NMEROS UTILIZANDO DIFERENTES BASES

Apesar da representao binria ser aquela utilizada internamente pelo computador, esta de difcil leitura para os seres humanos, devido s longas seqncias de algarismos 0 e 1. Para aliviar este problema, duas outras bases so bastantes utilizadas na computao, a base octal e a hexadecimal. A base octal corresponde concatenao de 3 bits, que combinados do origem a 8 diferentes valores, representados pelos algarismos de 0 a 7. J a base hexadecimal corresponde concatenao de 4 bits, gerando 16 combinao diferentes. Como possumos apenas 10 algarismo numricos, utilizamos as letras do alfabeto {A, B,C, D, E, F}. O nmero 1256 nestas bases seria ento dado por: 23508 = 2 83 + 3 82 + 5 81 = 2 512 + 3 64 + 5 8 = 1256 4E816 = 4 162 + 14 161 + 8 160 = 4 256 + 14 16 + 8 = 1256 Reparem que a representao hexadecimal mais compacta que a decimal, o que esperado, dado que utilizamos mais algarismos para representar os nmeros. Veremos agora como realizar a converso de nmeros inteiros entre diferentes sistemas de numerao.

13.2

Converso entre sistemas de numerao

Analise agora, com cuidado, a implementao da classe Converso que converte nmeros binrios para decimais e vice-versa. Este exemplo tambm demonstra como realizar a extrao dos dgitos de um nmero inteiro. No muito fcil entender o funcionamento de seus mtodos; sugerimos fortemente, ento, que voc tente rastrear1 a execuo dos dois mtodos.
c l a s s Converso { int binrioParaDecimal ( int n) { i n t dec = 0 ; int pot2 = 1; while ( n != 0){ / p r o c e s s a um d g i t o b i n r i o / d e c = d e c + n % 10 p o t 2 ; n = n / 10; pot2 = pot2 2; } return dec ; } int decimalParaBinrio ( int n) { int dig ; int bin = 0; int pot = 1;

a execuo de um programa signica construir uma tabela contendo colunas correspondentes s variveis do programa e simular a sua execuo indicando os valores que as variveis recebem ao longo do tempo. Se o programa imprimir texto (usando System.out.println) esse texto tem que ser indicado como sada e se os mtodos devolvem algum valor (com o comando return) este valor tem que ser destacado.

1 Rastrear

13.2. CONVERSO ENTRE SISTEMAS DE NUMERAO


while ( n > 0) { / e x t r a i p r x i m o d g i t o b i n r i o menos s i g n i f i c a t i v o ( m a i s d i r e i t a ) / dig = n % 2; / remove e s s e d g i t o do n / n = n / 2; / a d i c i o n a o d g i t o como o m a i s s i g n i f i c a t i v o a t o momento / bin = bin + dig pot ; pot = pot 10; } return bin ; } }

79

Exerccios
1. Crie uma classes Contador com um mtodo que recebe um nmero natural n e devolve seu nmero de dgitos. Em seguida, escreva uma classe TestaContador que testa o mtodo para diferentes valores de n. No se esquea de testar o caso do nmero ser igual a zero! 2. Dado um nmero, vericar se o mesmo possui dois dgitos consecutivos iguais. Para resolver este problema podemos usar um tcnica denominada indicador de passagem, para isto, inicialmente vamos supor que o nmero no contm dgitos iguais. Vericaremos cada par de dgitos consecutivos, caso algum deles seja igual, saberemos que ele contm dgitos consecutivos iguais. Em outras palavras, vamos inicializar uma varivel booleana com falso e testar a condio para todos os dgitos consecutivos; se forem iguais mudamos a condio. Ao nal, a resposta vai corresponder ao estado nal desta condio. 3. Dado um nmero natural n, vericar se n palndromo. Um nmero palndromo um nmero que lido de trs para frente o mesmo quando lido normalmente, por exemplo: 78087 1221 11111 3456 no palindromo!!! Duas maneiras de se resolver estes problemas so apresentadas abaixo. Escreva as solues para cada uma delas. A forma mais fcil construir o nmero inverso e compar-lo com o original. A outra soluo consiste em supor inicialmente que o nmero palndromo e em seguida vericar se a condio de igualdade vlida para os extremos. Se o nmero for negativo, considere apenas o seu valor absoluto (isso apenas uma conveno nossa para este exerccio). Por exemplo, -2002 deve ser considerado palndromo. Curiosidade: nmeros palndromos tambm so conhecidos por capicuas.

80

CAPTULO 13. MANIPULANDO NMEROS UTILIZANDO DIFERENTES BASES 4. Uma propriedade de nmeros naturais a seguinte: um nmero sempre maior do que o produto dos seus dgitos. Faa uma classe com dois mtodos: int calculaProd(int n), que calcula o produto dos dgitos de um nmero natural n e boolean verificaProp(int n), que verica se a propriedade vlida para um nmero n dado. 5. Crie mtodos para converter uma String contendo um nmero em algarismos romanos em um inteiro e vice-versa. Crie testes para estes mtodos. 6. Crie uma classe contendo um mtodo que recebe um inteiro e o imprime representado em notao cientca. Por exemplo, > Inteiro i = new Inteiro(); > i.carregaValor(1356); > i.imprimeEmNotacaoCientifica(); 1,356e3 > i.carregaValor(-102); > i.imprimeEmNotacaoCientifica(); -1,02e2 > i.carregaValor(7); > i.imprimeEmNotacaoCientifica(); 7,0e0 > i.carregaValor(900200); > i.imprimeEmNotacaoCientifica(); 9,002e5 7. Implemente a operao de diviso de dois nmeros inteiros utilizando apenas laos e os operadores + e -.

Captulo 14

Arrays (vetores)
Quais novidades veremos neste captulo? arrays (vetores); programas independentes em Java (mtodo main).

Muitas vezes, precisamos que um objeto guarde um grande nmero de informaes. Por exemplo, se precisamos calcular a temperatura mdia em um dado ms poderamos ter uma classe similar seguinte:
c l a s s TemperaturasDoMs { double t1 , t2 , t3 , t4 , t5 , t6 , t7 , t8 , t9 , t10 , t11 , t12 t13 , t14 , t15 , t16 , t17 , t18 , t19 , t20 , t21 , t22 , t23 , t24 , t25 , t26 , t27 , t28 , t29 , t30 , t31 ; / / etc . }

onde cada varivel guarda a temperatura mdia de um dia do ms. Isso claramente indesejvel. Imagine ainda se quisssemos uma classe para guardar as temperaturas mdias de todos os dias do ano. Precisaramos de 365 variveis? Felizmente no! A linguagem Java possui o conceito de array que uma estrutura de dados que permite guardar uma seqncia de valores (nmeros, caracteres ou objetos quaisquer) de uma forma nica e organizada. Utilizando um array, a classe anterior caria assim:
c l a s s TemperaturasDoMs { d o u b l e [ ] t e m p e r a t u r a s = new d o u b l e [ 3 1 ] ; / / etc . }

Note que, no exemplo acima, a linha que dene o array temperaturas faz duas operaes simultaneamente. Esta linha poderia ser separada em dois passos: double[] temperaturas; dene um novo array chamado temperaturas que ir conter valores do tipo double. Por enquanto, o array est vazio. 81

82

CAPTULO 14. ARRAYS (VETORES) temperaturas = new double[31]; especica que o array guardar exatamente 31 valores do tipo double. Neste instante, o ambiente Java reserva a memria necessria para guardar estes 31 valores. Nota Lingstica: a traduo padro de array para o portugus vetor. No entanto, a linguagem Java contm um tipo de objeto chamado Vector que semelhante a arrays, mas no igual. Para evitar confuses entre arrays e Vectors, preferimos no traduzir a palavra array para vetor neste livro.

Vejamos agora um exemplo simples de utilizao de arrays.


class BrincadeirasComArrays { S t r i n g [ ] diasDaSemana = new S t r i n g [ 7 ] ; i n t [ ] q u a d r a d o s = new i n t [ 1 0 ] ; void defineDiasDaSemana ( ) { diasDaSemana [ 0 ] = " domingo " ; diasDaSemana [ 1 ] = " s e g u n d a f e i r a " ; diasDaSemana [ 2 ] = " t e r a f e i r a " ; diasDaSemana [ 3 ] = " q u a r t a f e i r a " ; diasDaSemana [ 4 ] = " q u i n t a f e i r a " ; diasDaSemana [ 5 ] = " s e x t a f e i r a " ; diasDaSemana [ 6 ] = " s b a d o " ; } void calculaQuadrados ( ) { int i = 0; while ( i < 10) { quadrados [ i ] = i i ; i ++; } } void listaDiasDaSemana ( ) { int i = 0; while ( i < 7) { System . o u t . p r i n t l n ( diasDaSemana [ i ] ) ; i ++; } } void l i s t a Q u a d r a d o s ( ) { int i = 0; while ( i < 10) {

14.1. CRIAO DE PROGRAMAS JAVA


System . o u t . p r i n t l n ( i + " ao q u a d r a d o " + q u a d r a d o s [ i ] ) ; i ++; } } }

83

O atributo length
Arrays so na verdade um tipo especial de objeto em Java. Qualquer array j vem com um atributo prdenido, chamado length, que contm o comprimento do array. Desta forma, o mtodo calculaQuadrados acima poderia ser reescrito para
void calculaQuadrados ( ) { int i = 0; while ( i < quadrados . l e n g t h ) { quadrados [ i ] = i i ; i ++; } }

O valor do atributo length denido automaticamente pelo ambiente Java, o programador no pode alterlo. Assim, quadrados.length = 2 uma operao ilegal.

Inicializao de arrays
Existe tambm a opo de inicializar um array no momento em que ela declarada. Assim, podemos inicializar arrays de inteiros e de Strings conforme o exemplo a seguir:
i n t [ ] primos = {2 , 3 , 5 , 7 , 11 , 13 , 17 , 19 , 23}; S t r i n g [ ] p l a n e t a s = { " M e r c r i o " , " Vnus " , " T e r r a " , " M a r t e " , " J p i t e r " , " S a t u r n o " , " Urano " , " Netuno " , " P l u t o " } ;

14.1

Criao de programas Java

At este captulo, todos os exemplos de cdigos que vimos, a rigor, no eram "programas", eles eram apenas classes Java que podiam ser usadas dentro do interpretador do DrJava. Mas, e se quisssemos criar um programa para ser utilizado por algum que no possui o DrJava em sua mquina? Neste caso, precisamos criar um programa a ser executado ou na linha de comando do sistema operacional ou dando um "clique duplo"com o mouse em cima do cone do programa. Para fazer isso, basta que a classe principal do programa possua um mtodo main como no exemplo a seguir.
class BrincadeirasComArrays { / / a q u i vo o s d e m a i s m t o d o s e a t r i b u t o s da c l a s s e p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g )

84
{

CAPTULO 14. ARRAYS (VETORES)

B r i n c a d e i r a s C o m A r r a y s b = new B r i n c a d e i r a s C o m A r r a y s ( ) ; b . defineDiasDaSemana ( ) ; b . calculaQuadrados ( ) ; b . listaDiasDaSemana ( ) ; b . listaQuadrados ( ) ; b . imprimeArray ( arg ) ; } void imprimeArray ( S t r i n g [ ] a r r a y ) { int i = 0; while ( i < a r r a y . l e n g t h ) { System . o u t . p r i n t l n ( a r r a y [ i ] ) ; i ++; } } }

Para executar o seu programa aps compilar a classe, basta abrir um shell (um interpretador de comandos do sistema operacional; no unix pode ser, por exemplo, o bash; no windows pode ser, por exemplo, o command) e digitar java BrincadeirasComArrays um dois trs onde, java o nome do interpretador Java, BrincadeirasComArrays o nome da classe que ser carregada e cujo mtodo main ser executado e um dois trs so apenas um exemplo de 3 argumentos que estamos passando, poderia ser qualquer outra coisa. Neste exemplo, o programa BrincadeirasComArrays geraria a seguinte sada: domingo segunda-feira tera-feira quarta-feira quinta-feira sexta-feira sbado 0 ao quadrado 1 ao quadrado 2 ao quadrado 3 ao quadrado 4 ao quadrado 5 ao quadrado 6 ao quadrado 7 ao quadrado 8 ao quadrado 9 ao quadrado

0 1 4 9 16 25 36 49 64 81

14.1. CRIAO DE PROGRAMAS JAVA um dois trs

85

portanto, para que uma classe possa ser executada a partir da linha de comando do sistema, necessrio que ele possua um mtodo com a seguinte assinatura:
p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g )

o nome do parmetro no precisa ser exatamente arg, qualquer nome funciona; mas o seu tipo tem que ser obrigatoriamente um array de Strings. A partir do DrJava possvel executar o mtodo main pressionando a tecla F2.

Exerccios
Testes: at este captulo, em diversos exerccios pedimos explicitamente para voc criar testes para classes e mtodos escritos. Fizemos isto para enfatizar a necessidade de escrever testes, um processo que deve ser realizado de modo automtico. A partir deste captulo no iremos mais solicitar em cada exerccio que voc escreva testes. Voc dever, a partir de agora, fazer isso naturalmente.

1. Escreva uma classe Simples contendo um mtodo que recebe um array de inteiros como parmetro e que inicializa todos os elementos do array com um valor, tambm dado como parmetro. O mtodo deve devolver o tamanho do array. A assinatura do mtodo deve ser a seguinte:
int inicializaArray ( int [] a , int v );

Escreva agora um mtodo que recebe um array de inteiros como parmetro e imprime o seu contedo:
void imprimeArray ( i n t [ ] a ) ;

Crie agora um mtodo que, dado um inteiro, verica se ele est presente no array.
boolean estNoArray ( i n t [ ] a , i n t v ) ;

Finalmente, escreva um programa que cria um array, cria um objeto Simples e chama os seus trs mtodos. 2. Crie um mtodo double[] freqnciaRelativa(int[] v, int n) que recebe um vetor contendo nmeros inteiros no intervalo [0, n] e devolve um vetor contendo a freqncia relativa de cada um destes nmeros. 3. Crie um mtodo que, dados dois vetores a e b, verica se o vetor de menor tamanho uma subseqncia do vetor de tamanho maior. Ex: O vetor [9, 5] uma subseqncia de [3, 9, 5, 4, -1].

86

CAPTULO 14. ARRAYS (VETORES) 4. Crie uma classe contendo um mtodo que, dado um vetor v de inteiros, imprime o segmento de soma mxima. Ex: No vetor [ -1, 5, -4, 7, 2, -3] o segmento de soma mxima [ 5, -4, 7, 2]

Captulo 15

for, leitura do teclado e converso de Strings


Quais novidades veremos neste captulo? for (mais um comando de repetio); Leitura de dados do teclado; Converso de Strings para nmeros.

15.1

O comando for

Voc deve ter notado que, quando implementamos laos com o comando while, muito comum que sigamos um padro bem denido. Considere os dois exemplos a seguir que vimos no captulo anterior:
void listaDiasDaSemana ( ) { int i = 0; while ( i < 7) { System . o u t . p r i n t l n ( diasDaSemana [ i ] ) ; i ++; } } void calculaQuadrados ( ) { int i = 0; while ( i < quadrados . l e n g t h ) { quadrados [ i ] = i i ; i ++; }

87

88
}

CAPTULO 15. FOR, LEITURA DO TECLADO E CONVERSO DE STRINGS

Em ambos os casos, a estrutura do lao a seguinte:


i n t i = 0 ; / / d e f i n e onde o l a o s e i n i c i a / / d e f i n e o c r i t r i o p a r a c o n t i n u a r m o s d e n t r o do l a o while ( i < quadrados . l e n g t h ) { quadrados [ i ] = i i ; / / a operao propriamente d i t a i ++; / / comando de a t u a l i z a o p a r a p a s s a r m o s p a r a a p r x i m a i t e r a o }

Ou seja, um formato genrico para laos com while seria o seguinte:


inicializao ; while ( condio para c o n t i n u a r ) { comando ; atualizao ; }

Aps muito observar este padro, projetistas de linguagens de programao decidiram criar um novo comando para implementao de laos onde todas estas partes relacionadas com o lao fossem organizadas de uma forma melhor. Assim, surgiu o comando for que, nas linguagens C, C++ e Java, adquirem o seguinte formato:
for ( i n i c i a l i z a o ; condio para continuar ; a t u a l i z a o ) { comando ; }

onde as chaves so apenas necessrias se comando for composto. Com o for, podemos implementar exatamente o mesmo que com o while mas, no caso do for, todas as operaes relacionadas com o lao cam na mesma linha, o que facilita a visualizao e o entendimento de quem olha para o cdigo.

15.2

Leitura do teclado

No captulo anterior, aprendemos como escrever um programa em Java que pode ser executado a partir da linha de comando, sem a necessidade de utilizar um ambiente como o DrJava para execut-lo. Aprendemos tambm a receber dados como parmetro atravs da linha de comando utilizando o parmetro args do mtodo main. No entanto, existem casos em que gostaramos de ler valores digitados pelo usurio atravs do teclado durante a execuo do programa. At a verso 1.4, Java oferecia algumas formas de se fazer isso mas nenhuma delas era muito simples. A partir da verso 1.5 foi introduzida a classe Scanner que possui vrios mtodos para a leitura do teclado. Observe a classe seguinte:
import j a v a . u t i l . ; c l a s s UsoScanner {

15.2. LEITURA DO TECLADO


p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { S c a n n e r s c = new S c a n n e r ( System . i n ) ; int x = sc . n e x t I n t ( ) ; System . o u t . p r i n t l n ( " O i n t e i r o l i d o f o i " + x ) ; double d = sc . nextDouble ( ) ; System . o u t . p r i n t l n ( " O d o u b l e l i d o f o i " + d ) ; S t r i n g s = sc . next ( ) ; System . o u t . p r i n t l n ( " A s t r i n g l i d a f o i " + s ) ; } }

89

Nela podemos ver que, para a leitura de dados a partir do teclado, primeiro precisamos instanciar um objeto do tipo Scanner, para em seguida podermos usar mtodos como nextInt para a leitura de um nmero do tipo int. Caso o dado lido no seja do tipo esperado, uma exceo1 lanada.

Verses anteriores a JDK 1.5


At a verso 1.4 no havia forma simples de se efetuar a leitura a partir do teclado. Para facilitar a vida de iniciantes em programao Java com verses mais antigas do JDK, podemos utilizar uma classe que esconde as partes mais complicadas da leitura atravs do teclado. Neste livro utilizaremos a classe SavitchIn escrita pelo Prof. Walter Savitch da Universidade da California em San Diego. A classe SavitchIn pode ser encontrada no stio do Prof. Savitch 2 . Aps compilar o SavitchIn.java para produzir o SavitchIn.class, basta copi-lo para o mesmo diretrio onde os seus arquivos .class sero guardados para que voc possa utilizar os mtodos da classe SavitchIn. Uma descrio detalhada de todos os mtodos da SavitchIn est disponvel na Web3 . Mas vamos nos concentrar apenas nos seguintes mtodos:
public class SavitchIn { public s t a t i c String readLine ( ) ; p u b l i c s t a t i c i n t r e a d L i n e I n t ( ) ; / / s u p e que h a p e n a s um i n t e i r o na l i n h a p u b l i c s t a t i c d o u b l e r e a d L i n e D o u b l e ( ) ; / / a p e n a s um d o u b l e na l i n h a / I n t h e f o l l o w i n g method I f t h e i n p u t word i s " t r u e " o r " t " , t h e n t r u e i s r e t u r n e d . I f t h e i n p u t word i s " f a l s e " o r " f " , t h e n f a l s e i s r e t u r n e d . U p p e r c a s e and l o w e r c a s e l e t t e r s a r e c o n s i d e r e d e q u a l . I f t h e u s e r e n t e r s a n y t h i n g e l s e ( e . g . , m u l t i p l e words o r d i f f e r e n t words ) , t h e n t h e u s e r i s a s k e d t o r e e n t e r t h e i n p u t . / public s t a t i c boolean readLineBoolean ( ) ; } (Exceptions) so representadas por um tipo especial de objeto e utilizadas em Java para o tratamento de erros. Este recurso no exclusivo de Java, sendo utilizado tambm em outras linguagens, como o C++. Mais informaes sobre o uso de excees em Java podem ser encontradas no site http://java.sun.com/docs/books/tutorial/essential/exceptions/index.html. 2 http://www.cs.ucsd.edu/users/savitch/java/SavitchIn.txt 3 http://www.sinc.sunysb.edu/Stu/fmquresh/SavitchIn.html
1 Excees

90

CAPTULO 15. FOR, LEITURA DO TECLADO E CONVERSO DE STRINGS

A palavra static na declarao de cada mtodo indica que este mtodo pode ser utilizado mesmo que no existam instncias da classe. Para utiliz-lo basta fazer algo como no exemplo seguinte:
f o r ( i = 1 ; i <= 1 0 ; i ++) { i n t num = S a v i t c h I n . r e a d L i n e I n t ( ) ; System . o u t . p r i n t l n ( i + " o nmero d i g i t a d o : " + num ) ; }

Nota: Por uma limitao do DrJava, a classe SavitchIn ainda no funciona na janela Interactions. Segundo os desenvolvedores do DrJava, esta limitao ser solucionada no futuro. Portanto, por enquanto, voc deve utilizar a SavitchIn em programas a serem executados na linha de comando.

15.3

Converso de String para nmeros

Voc deve ter notado que o mtodo main recebe sempre Strings como parmetro. Mas e se quisermos receber valores numricos? Neste caso temos que converter o String que recebemos em um nmero. Isso pode ser feito atravs da classe Integer ou da classe Double que contm mtodos para efetuar estas converses:
S t r i n g m e u S t r i n g I n t e i r o = " 10 " ; int meuInteiro = Integer . parseInt ( meuStringInteiro ) ; S t r i n g meuStringReal = " 3.14159265 " ; d o u b l e meuReal = Double . p a r s e D o u b l e ( m e u S t r i n g R e a l ) ;

Exerccios
1. Usando o comando for, escreva um mtodo que recebe um array de doubles como parmetro e imprime o seu contedo. 2. Usando o comando for, escreva um mtodo somaArrays que recebe 3 arrays de mesmo comprimento como parmetro e que calcula a soma dos dois primeiros e a armazena no terceiro. A soma deve ser implementada como soma vetorial, ou seja, soma-se a primeira posio de um vetor com a primeira posio do segundo, armazenando-se o resultado na primeira posio do terceiro e assim por diante. Nota: o terceiro array que passado como parmetro chamado de parmetro de sada. Quando o mtodo se inicia, ele j contm um array que passado por quem chamou o mtodo somaArrays, mas o seu contedo inicial no relevante. Isso funciona em Java apenas quando passamos uma referncia de objeto como parmetro, como vimos no Captulo 12. 3. Escreva um mtodo que recebe um array de doubles como parmetro e imprime a mdia dos valores nele contidos. 4. Escreva dois mtodos (min e max) que recebem um array de inteiros como parmetro e devolvem, respectivamente, um inteiro correspondente ao menor e ao maior elemento do array. 5. Escreva uma classe ProdutoEscalar contendo os seguintes mtodos:

15.3. CONVERSO DE STRING PARA NMEROS

91

(a) mtodo que recebe um array "vazio"como parmetro e que l valores double do teclado para serem inseridos no array. (b) mtodo que recebe 2 arrays de double como parmetro e devolve o valor do produto escalar (soma dos produtos das posies de mesmo ndice dos dois arrays). (c) mtodo main que, usando os mtodos anteriores, l do teclado o comprimento dos vetores, l do teclado o contedo de dois vetores com o tamanho comprimento, calcula o produto escalar e imprime o resultado.

92

CAPTULO 15. FOR, LEITURA DO TECLADO E CONVERSO DE STRINGS

Captulo 16

Laos Encaixados e Matrizes


Quais novidades veremos neste captulo? repeties encaixadas; matrizes (arrays multidimensionais).

16.1

Laos encaixados

Em algumas situaes, pode ser necessrio implementar um lao dentro de outro lao. Chamamos esta construo de laos encaixados, laos aninhados ou repeties encaixadas. Eis um exemplo bem simples:
int i , j ; f o r ( i = 0 ; i < 5 ; i ++) f o r ( j = 0 ; j < 3 ; j ++) System . o u t . p r i n t l n ( " i = " + i + " , j = " + j ) ;

A idia que, para cada iterao do for mais externo, o interpretador Java executa o for mais interno com todas as suas iteraes. No exemplo acima, o println , portanto, executado 5*3 = 15 vezes. Agora um exemplo mais complexo: um programa usado para calcular a mdia de vrias turmas na prova P1 de uma disciplina:
c l a s s MediasNaP1 { p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g ) { i n t nmeroDeAlunos , nmeroDeTurmas , turma , a l u n o ; d o u b l e n o t a , soma ; S c a n n e r s c = new S c a n n e r ( System . i n ) ; System . o u t . p r i n t ( " Voc q u e r c a l c u l a r a s m d i a s de q u a n t a s t u r m a s ? " ) ; nmeroDeTurmas = s c . n e x t I n t ( ) ; f o r ( t u r m a = 1 ; t u r m a <= nmeroDeTurmas ; t u r m a ++) {

93

94

CAPTULO 16. LAOS ENCAIXADOS E MATRIZES


soma = 0 ; nota = 0; System . o u t . p r i n t l n ( " D i g i t e a s n o t a s na P1 da t u r m a " + t u r m a ) ; System . o u t . p r i n t l n ( " F i n a l i z e a s e q n c i a de n o t a s d i g i t a n d o 1. " ) ; f o r ( nmeroDeAlunos = 0 ; n o t a >= 0 ; nmeroDeAlunos ++) { nota = sc . nextDouble ( ) ; i f ( n o t a >= 0 ) soma += n o t a ; } System . o u t . p r i n t l n ( "A mdia da t u r m a " + soma / ( nmeroDeAlunos 1 ) ) ; } }

16.2

Matrizes (arrays multidimensionais)

Uma matriz de 1 dimenso, tambm chamada de vetor, implementada em Java usando um array unidimensional, como vimos no Captulo 14. Matrizes de 2 ou mais dimenses tambm podem ser representadas em Java atravs de arrays multidimensionais. Veja um exemplo:
/ / d e f i n e uma m a t r i z b i d i m e n s i o n a l int [ ] [ ] matriz ; / / a l o c a e s p a o p a r a uma m a t r i z de 5 l i n h a s e 7 c o l u n a s m a t r i z = new i n t [ 5 ] [ 7 ] ; matriz [0][ 0] = 3; matriz [1][1] = matriz [3][4] + matriz [ 1 ] [ 2 ] ;

muito comum utilizarmos repeties encaixadas quando precisamos percorrer os elementos de matrizes de duas dimenses ou mais:
int i , j ; i n t [ ] [ ] t a b u a d a = new i n t [ 1 1 ] [ 1 1 ] ; f o r ( i = 0 ; i <= 1 0 ; i ++) f o r ( j = 0 ; j <= 1 0 ; j ++) tabuada [ i ] [ j ] = i j ;

este trecho de cdigo cria uma matriz de duas dimenses contendo a tabuada de 0 a 10. Note que a primeira linha e a primeira coluna no precisariam ser inicializadas com uma multiplicao, poderamos atribuir o valor 0 diretamente a elas. Nota interessante: para Java, na verdade uma matriz bidimensional um array de arrays. Ou seja, tabuada um array onde cada posio do tipo array de inteiros. Dito isto, pense como podemos fazer para descobrir quantas linhas e quantas colunas possui uma matriz bidimensional. A resposta a seguinte:
void imprimeDimenses ( i n t [ ] [ ] m a t r i z ) { System . o u t . p r i n t l n ( "A m a t r i z p o s s u i " + matriz . length + " linhas e " +

16.3. EXEMPLO: LIFE, O JOGO DA VIDA


matriz [ 0 ] . length } + " colunas . " ) ;

95

16.3

Exemplo: LIFE, o jogo da vida

O LIFE um jogo simples de simulao de processos biolgicos criado pelo matemtico John Conway. O ambiente onde se passa a simulao uma grade quadriculada onde so colocadas clulas vivas; cada quadrado da grade pode conter ou no uma clula viva. A partir de um estado inicial (que pode ser gerado aleatoriamente, por exemplo), o estado seguinte da grade determinado atravs de 3 regras bem simples: Uma clula viva com menos de 2 vizinhos morre. Uma clula viva com mais de 3 vizinhos morre. Uma clula viva aparece quando tem 3 vizinhos vivos exatamente. O processo de simulao iterativo, ou seja, as regras so aplicadas ao estado inicial que produz um segundo estado. A este segundo estado so aplicadas as regras novamente e assim sucessivamente, criando novas geraes de clulas ao longo do tempo. Veja um exemplo de implementao do LIFE abaixo. Estude atentamente cada trecho do programa e depois o execute no DrJava.
class Life { i n t MAX = 1 0 ; / / Tamanho da m a t r i z i n t [ ] [ ] m a t r i z = new i n t [MAX] [MAX] ; void i n i c i a l i z a ( ) { int i , j ; f o r ( i = 1 ; i < MAX 1 ; i ++) f o r ( j = 1 ; j < MAX 1 ; j ++) m a t r i z [ i ] [ j ] = ( i n t ) ( Math . random ( ) 1 . 5 ) ; / / o Math . random g e r a um nmero em [ 0 , 1 ] , m u l t i p l i c a n d o / / p o r 2 / 3 c o n s e g u i r e m o s 2 / 3 d a s c a s a s com z e r o s e 1 / 3 com 1 s / / o ( i n t ) t r a n s f o r m a o d o u b l e o b t i d o em i n t e i r o / / Os m a i s o b s e r v a d o r e s podem p e r c e b e r que a s b o r d a s da m a t r i z no / / f o r a m i n i c i a l i z a d a s . F i z e m o s i s s o p a r a d e i x l a s z e r a d a s ( o J a v a / / f a z i s t o a u t o m a t i c a m e n t e quando da a l o c a o da m a t r i z ( new i n t ) . } void imprimeTabuleiro ( ) { int i , j ; f o r ( i = 0 ; i < MAX; i ++) { f o r ( j = 0 ; j < MAX; j ++) i f ( m a t r i z [ i ] [ j ] == 1 )

96
System . o u t . p r i n t ( " " ) ; else System . o u t . p r i n t ( " . " ) ; System . o u t . p r i n t l n ( ) ; } System . o u t . p r i n t l n ( ) ; }

CAPTULO 16. LAOS ENCAIXADOS E MATRIZES

int vizinhos ( int i , int j ) { r e t u r n m a t r i z [ i 1][ j 1] + m a t r i z [ i 1][ j ] + m a t r i z [ i 1][ j + 1 ] + m a t r i z [ i ] [ j 1] + m a t r i z [ i ] [ j + 1] + m a t r i z [ i + 1 ] [ j 1] + m a t r i z [ i + 1 ] [ j ] + m a t r i z [ i + 1 ] [ j + 1 ] ; } int [ ] [ ] iterao () { i n t [ ] [ ] aux = new i n t [MAX] [MAX] ; int i , j ; f o r ( i = 1 ; i < MAX 1 ; i ++) f o r ( j = 1 ; j < MAX 1 ; j ++) { i f ( m a t r i z [ i ] [ j ] == 1 ) / / se est viva { i f ( ( vizinhos ( i , j ) < 2) | | ( vizinhos ( i , j ) > 3)) aux [ i ] [ j ] = 0 ; / / morre else aux [ i ] [ j ] = 1 ; / / continua viva } else / / s e no e s t v i v a { i f ( v i z i n h o s ( i , j ) == 3 ) aux [ i ] [ j ] = 1 ; / / aparece vida else aux [ i ] [ j ] = 0 ; / / c o n t i n u a como e s t a v a } } r e t u r n aux ; / / d e v o l v e a m a t r i z com a nova i t e r a o } void simulaVida ( i n t quant ) { int i ; / / f a r e m o s a s i m u l a o de q u a n t o s c i c l o s f o r ( i = 0 ; i < q u a n t ; i ++) { imprimeTabuleiro ( ) ; m a t r i z = i t e r a o ( ) ; / / a m a t r i z da i t e r a o a n t e r i o r r e c o l h i d a / / p e l o c o l e t o r de l i x o . } } }

16.3. EXEMPLO: LIFE, O JOGO DA VIDA Observe abaixo, cinco iteraes do Life, da esquerda para a direita. .......... ...*.****. ....*...*. ....**.... .**.***.*. .*....*... ..*...*... ..*.*..... .....**.*. .......... .......... ....*****. ...*....*. ......**.. .****.**.. .*.*..*... .***.*.... ...*..**.. .....*.... .......... .......... ....*****. ....*...*. ....***.*. .*.**..... ......**.. .*.*.*.*.. ...*.**... ......*... .......... .......... ....*****. ...*....*. .......*.. ...**..... ...*.***.. ..*..*.*.. ..*..*.*.. .....**... .......... .......... ....*****. ....**..*. ...**..... ...***.*.. ..**.*.*.. ..**.*.**. ....**.*.. .....**... ..........

97

Exerccios
1. Escreva um mtodo para preencher uma matriz com nmeros inteiros lidos do teclado. O mtodo recebe a matriz como parmetro. 2. Escreva uma classe com os seguintes mtodos: Um mtodo que recebe 3 matrizes do tipo double como parmetro, calcula a soma das duas primeiras e guarda o resultado na terceira. Um mtodo que recebe 3 matrizes do tipo double como parmetro, calcula o produto das duas primeiras e guarda o resultado na terceira. Para os dois mtodos anteriores, escreva uma segunda verso que recebe apenas 2 matrizes como parmetro e devolve o resultado atravs do comando return. 3. Adicionar classe do exerccio anterior um mtodo que recebe duas matrizes quadradas do tipo double e devolve um boolean indicando se uma inversa da outra. Lembrando da impreciso das contas com ponto utuante considere que um nmero igual a zero se ele pertencer a [108 , 108 ]. De forma anloga considere que um nmero igual a 1 se ele pertencer a [1 108 , 1 + 108 ]. 4. Dizemos que uma matriz Anxn um quadrado latino de ordem n se em cada linha e em cada coluna aparecem todos os inteiros 1,2,3,...,n (ou seja, cada linha e coluna permutao dos inteiros 1,2,...,n). Escreva uma classe com os seguintes mtodos: (a) imprimeMatriz(), que imprime uma matriz; (b) estNoArray() que recebe como parmetros um inteiro j e um array a de inteiros e verica se j ocorre no array; (c) temTodos() que, usando o mtodo acima, recebe como parmetros um array a com n inteiros e verica se em a ocorrem todos os inteiros de 1 a n e (d) Latino() que, utilizando o mtodo acima, verica se uma dada matriz inteira Anxn um quadrado latino de ordem n.

98

CAPTULO 16. LAOS ENCAIXADOS E MATRIZES Veja um exemplo de uso de um objeto da classe nas seguintes iteraes. Aproveitamos o exemplo abaixo para mostrar como podemos denir matrizes constantes (usando chaves). Welcome to DrJava. > QuadradoLatino a = new QuadradoLatino(); > int [][] matriz1 = {{1}}; > a.imprimeMatriz(matriz1) 1 > a.Latino(matriz1) true > int [][] matriz2 = {{1,2,3}, {2,3,1}, {3,1,2}}; > a.imprimeMatriz(matriz2) 1 2 3 2 3 1 3 1 2 > a.Latino(matriz2) true > int [][] matriz3 = {{1,2}, {1,2}}; > a.imprimeMatriz(matriz3) 1 2 1 2 > a.Latino(matriz3) false 5. Dizemos que uma matriz Anxn um quadrado mgico de ordem n se o valor da soma dos elementos em cada linha e em cada coluna o mesmo. Escreva uma classe que inclua mtodos para vericar se uma dada matriz (recebida como parmetro em um de seus mtodos) um quadrado mgico ou no. 6. Faa uma classe com dois mtodos estticos: int pertence(int el, int v[], int tam) que verica se um inteiro el ocorre em um array v[] com tam elementos. Se ele ocorre, o mtodo devolve a posio da primeira ocorrncia, caso contrrio devolve -1. void freqncia(int v[]) que imprime a freqncia absoluta dos elementos em v. Dica: para calcular a freqncia absoluta so necessrios dois vetores, um com os elementos distintos e outro com o nmero de ocorrncias. Percorra o array v vericando, para cada posio, se o nmero armazenado j apareceu. 7. Um jogo de palavras cruzadas pode ser representado por uma matriz Amxn onde cada posio da matriz corresponde a um quadrado do jogo, sendo que 0 indica um quadrado branco e -1 indica um quadrado preto. Indicar na matriz as posies que so incio de palavras horizontais e/ou verticais nos quadrados correspondentes (substituindo os zeros), considerando que uma palavra deve ter pelo menos duas letras. Para isso, numere consecutivamente tais posies. Exemplo: Dada a matriz:

16.3. EXEMPLO: LIFE, O JOGO DA VIDA 0 0 0 -1 0 -1 0 0 0 0 0 0 -1 0 -1 -1 0 -1 0 0 -1 -1 0 0 0 -1 -1 9 0 0 0 0 0 -1 0 3 7 0 -1 0 -1 0 -1 0 -1 -1 0 -1 12 -1 0 0 0 0 -1 4 0 0 0 -1

99

A sada dever ser: 1 -1 2 -1 5 6 0 0 8 0 -1 -1 -1 10 0 11 13 0 -1 14

8. (Difcil) Escreva uma classe com um mtodo que leia um inteiro n e as posies de n rainhas em um tabuleiro de xadrez e determina se duas rainhas se atacam.

100

CAPTULO 16. LAOS ENCAIXADOS E MATRIZES

Captulo 17

Busca e Ordenao
Quais novidades veremos neste captulo? Busca em array; Ordenao de arrays.

17.1

Busca

Como j vimos, arrays podem guardar muita informao embaixo de uma nica varivel. Uma das operaes mais comuns que podemos fazer em um array buscar um elemento nele. Isso pode ser til para saber se um elemento j est l para recuperar outras informaes dos objetos armazenados. Pense, por exemplo, na busca de um CD pelo ttulo. Sabendo onde o CD est, podemos recuperar outras informaes, como as faixas que o compem, sua durao, etc. Mas como podemos buscar algo? Vamos primeiro aprender a forma mais simples de busca: a busca seqencial. Neste caso, varre-se o array do incio ao m at encontrarmos o elemento desejado. Isso pode ser feito usando um simples lao while. Considere que biblioteca um array de objetos da classe Livro. O array est cheio de livros vlidos, ou seja, tem elementos de 0 a biblioteca.length - 1. Considere ainda que esses objetos disponibilizam um mtodo pegaNome que devolve o nome do livro. Veja abaixo um exemplo de cdigo para buscar um livro de nome Amor em tempos de clera.
int i = 0; w h i l e ( ( i < b i b l i o t e c a . l e n g t h ) && ( b i b l i o t e c a [ i ] . pegaNome ( ) . e q u a l s ( " Amor em t e m p o s de c l e r a " ) == f a l s e ) ) i = i + 1;

Ao nal, temos duas possibilidades: i < bibliotecas.length: Neste caso o livro est na posio i do array. De posse desse ndice podemos manipular o livro encontrado como quisermos. i == bibliotecas.length: J, aqui, o livro no foi encontrado pois passamos do nal do array. 101

102

CAPTULO 17. BUSCA E ORDENAO

Por m, devemos destacar que h uma certa sutileza no cdigo acima. Note que no segundo caso no poderamos acessar o array na posio i. Isso no ocorre devido ordem das condies do while. Como a primeira condio falsa, o computador no precisa testar a segunda para saber que a expresso falsa, j que a condio um e-lgico.

17.2

Pondo ordem na casa

Uma das tarefas mais comuns em programas ordenar coisas. Muitas vezes mais fcil trabalhar com os elementos de um array ordenados. Um bom exemplo a busca. Caso o array esteja ordenado pela chave de busca, como veremos no prximo captulo, possvel fazer algo bem mais eciente do que a busca seqencial descrita acima. Mas como podemos ordenar os elementos de um array? Para fazer isso vamos nos lembrar de algo que universitrios fazem muito: jogar baralho. Quando temos vrias cartas na mo, muitas vezes acabamos por orden-las. Pensem e discutam um pouco como vocs fazem isso. Existe alguma lgica por trs da maneira que voc move as cartas para l e para c? Ser que voc poderia descrever um algoritmo para ordenar as cartas? Agora vamos fazer a brincadeira car um pouco mais complicada. Seja qual for o algoritmo que voc descreveu acima, tente pensar como adapt-lo para incorporar duas restries. Primeiro, considere que voc no pode olhar todas as cartas de uma vez, isto , no mximo duas cartas podem car visveis ao mesmo tempo. Vale, porm, anotar a posio onde uma carta do seu interesse est. Segundo, considere que voc no pode simplesmente mover as cartas de um lugar para outro, mas somente pode trocar duas cartas de posio. bem provvel que a soluo imaginada poderia ser descrita em Java por um dos algoritmos abaixo. Neles deseja-se ordenar os elementos no array de inteiros nmeros. Cada algoritmo escrito como um mtodo. 1. Seleo direta. Neste algoritmo, a cada passo buscamos o menor elemento no array e o levamos para o incio. No passo seguinte buscamos o segundo menor elemento e assim por diante.
v o i d s e l e o D i r e t a ( i n t [ ] nmeros ) { i n t i , j , ndiceDoMnimo , temp ; i n t f i m = nmeros . l e n g t h ; f o r ( i = 0 ; i < f i m 1 ; i ++) { / / I n i c i a l m e n t e o menor e l e m e n t o j v i s t o o p r i m e i r o e l e m e n t o . n di c eD o M n i m o = i ; f o r ( j = i + 1 ; j < f i m ; j ++) { i f ( nmeros [ j ] < nmeros [ i n d ic e Do M ni m o ] ) nd i c eD o M n i m o = j ; } / / C o l o c a o menor e l e m e n t o no i n c i o do s u b v e t o r a t u a l . Para i s s o , t r o c a / / de l u g a r o s e l e m e n t o s n o s n d i c e s i e n d i c e D o M n i m o . temp = nmeros [ i ] ; nmeros [ i ] = nmeros [ n d ic e Do M ni m o ] ; nmeros [ n di c e Do M ni m o ] = temp ; } }

17.2. PONDO ORDEM NA CASA

103

2. Insero direta. A cada passo aumenta a parte ordenada do array de uma posio, inserindo um novo elemento na posio correta.
v o i d i n s e r o D i r e t a ( i n t [ ] nmeros ) { int i , j , nmeroAInserir ; i n t f i m = nmeros . l e n g t h ; / / Cada p a s s o c o n s i d e r a que o a r r a y e s q u e r d a de i e s t o r d e n a d o . f o r ( i = 1 ; i < f i m ; i ++) { / / T e n t a i n s e r i r m a i s um nmero na p o r o i n i c i a l do a r r a y que / / j e s t o r d e n a d a empurrando p a r a d i r e i t a t o d o s o s e l e m e n t o s / / m a i o r e s do que n m e r o A I n s e r i r . n m e r o A I n s e r i r = nmeros [ i ] ; j = i; w h i l e ( ( j > 0 ) && ( nmeros [ j 1] > n m e r o A I n s e r i r ) ) { nmeros [ j ] = nmeros [ j 1 ] ; j ; } nmeros [ j ] = n m e r o A I n s e r i r ; } }

3. Mtodo da bolha. Esse mtodo testa se a seqncia est ordenada e troca o par de elementos que gerou o problema. Pense no array como um tubo de ensaio vertical onde os elementos mais leves sobem superfcie como bolhas.
v o i d b o l h a ( i n t [ ] nmeros ) { i n t i , j , temp ; i n t f i m = nmeros . l e n g t h ; f o r ( i = f i m 1 ; i > 0 ; i ) / / V a r r e o a r r a y d e s d e o i n c i o p r o c u r a n d o e r r o s de o r d e n a o . / / Como a cada passagem o m a i o r e l e m e n t o s o b e a t s u a / / p o s i o c o r r e t a , no h n e c e s s i d a d e de i r a t o f i n a l . f o r ( j = 1 ; j <= i ; j ++) / / Se a ordem e s t e r r a d a p a r a o p a r j 1 e j i f ( nmeros [ j 1] > nmeros [ j ] ) { / / T r o c a o s d o i s de l u g a r temp = nmeros [ j 1 ] ; nmeros [ j 1] = nmeros [ j ] ; nmeros [ j ] = temp ; } }

Obs.: Sempre que pedimos para o System.out.print ou System.out.println imprimirem um array ou outro objeto qualquer de uma classe denida por ns, ele imprime apenas um nmero estranho (que representa o lugar onde o objeto est armazenado na memria). Deste modo interessante escrever um mtodo

104

CAPTULO 17. BUSCA E ORDENAO

imprimeArray para que o computador mostre todos os elementos vlidos de seu array. Esse mtodo fcil, basta percorrer o array e pedir a cada passo que o computador imprima o elemento atual (ou a parte dele que nos interessa ver).

Exerccio
1. Os algoritmos de ordenao neste captulo foram desenvolvidos utilizando nmeros. Se quisermos ordenar uma seqncia de nomes, por exemplo, {Renault, McLaren, Ferrari, Toyota, Williams, Honda, Red Bull, BMW Sauber}, preciso modicar estes mtodos. Escreva uma verso do mtodo da bolha que ordena um array de String. 2. Vamos descobrir como os algoritmos acima descritos se comportam medida que aumentamos o tamanho do array a ser ordenado? Para cada um dos algoritmos acima execute o algoritmo utilizando como entrada arrays de diferentes tamanhos. O tempo gasto para realizar a ordenao cresce linearmente com o tamanho do array? 3. Algoritmos de ordenao so freqentemente utilizados junto com outros algoritmos para torn-los mais ecientes. Escreva uma classe que contenha um mtodo atribuiArray que recebe um array de inteiros e o armazena como um atributo da classe. Escreva ento um mtodo int nRepeties(int x) que devolve o nmero de vezes que x aparece neste array Escreva uma outra classe similar anterior cujo mtodo atribuiArray ordena os elementos do array antes de armazen-lo como atributo da classe. Fornea a cada uma das classes vetores de diferentes tamanhos contendo nmeros aleatrios. Para cada caso, chame o mtodo int nRepeties(int x) utilizando diferentes valores de x. Podemos argumentar que a primeira classe mais eciente no caso em que so realizadas poucas consultas a nRepeties e a segunda classe mais eciente quando so realizadas muitas consultas. Justique esta argumentao.

Captulo 18

Busca Binria e Fuso


Quais novidades veremos neste captulo? Busca binria; Complexidade Computacional; Fuso de duas seqncias ordenadas.

18.1

Busca binria

Neste captulo, veremos alguns dos usos da ordenao. Um exemplo especialmente interessante a busca binria. Suponha que estamos escrevendo um programa que vai guardar um grande nmero de informaes. Estes dados mudam pouco no tempo mas so sempre consultados. Um exemplo tpico a lista telefnica, cujo contedo muda muito pouco, mas que consultada vrias vezes por dia no stio da operadora. Neste caso, vale a pena pagar o preo de guardar os dados ordenados pela chave de busca (no caso da lista, o nome do assinante). Isso torna a busca, que a operao mais freqente, muito mais rpida. Vejamos como isso pode ser feito. A idia da busca binria bem simples. Grosso modo, como a seqncia est ordenada, sabemos que o tem que est localizado bem no meio da seqncia, a divide em duas partes: os tens menores que o tem do meio caro esquerda dele enquanto que os tens maiores que ele caro sua direita. Se, em cada iterao, simplesmente compararmos o valor buscado ao valor contido no tem do meio da seqncia, podemos jogar metade do trabalho fora. H trs possibilidades: 1. O objeto buscado tem a mesma chave do objeto do meio: ento j encontramos o que queramos e nosso trabalho acabou; 2. O objeto buscado vem antes do objeto do meio: podemos ento concentrar a busca na poro inicial da seqncia e esquecer a segunda metade; 3. O objeto buscado ca depois do objeto intermedirio: a busca deve continuar apenas na segunda metade. 105

106

CAPTULO 18. BUSCA BINRIA E FUSO

Ou seja, podemos, usando o elemento intermedirio, eliminar metade do trabalho a cada passo do nosso algoritmo. Isso faz com que a busca que muito mais rpida! Vejamos como ca a implementao da busca binria para um array de inteiros. O mtodo abaixo retorna a posio do valor buscado caso este esteja presente no array e -1 caso contrrio. Este cdigo pode ser facilmente adaptado para doubles, cadeias de caracteres ou qualquer outro tipo de objeto.
int buscaBinria ( int valor , int [ ] vetor ) { i n t esq = 0 , dir = vetor . length 1 , meio ; w h i l e ( e s q <= d i r ) { meio = ( e s q + d i r ) / 2 ; i f ( v a l o r > v e t o r [ meio ] ) e s q = meio + 1 ; e l s e i f ( v a l o r < v e t o r [ meio ] ) d i r = meio 1 ; else r e t u r n meio ; } r e t u r n 1; }

18.2

Complexidade Computacional

Vamos agora pensar um pouco sobre quanto tempo o algoritmo de busca binria necessita para ser executado, ou em outras palavras, queremos descobrir qual o seu custo computacional ou qual a sua complexidade computacional. Note que o algoritmo seqencial de busca que vimos no captulo anterior precisa percorrer todos os elementos de um vetor, de um em um, at localizar o elemento que estamos procurando. Em particular, se o elemento buscado no se encontra no vetor, seria necessrio compar-lo a todos os elementos do vetor para descobrir que ele no se encontra l. Podemos ento dizer que o algoritmo de busca seqencial utiliza da ordem de n comparaes para localizar o tem procurado, onde n o nmero de elementos do vetor. Suponha que queiramos realizar a busca numa lista telefnica de uma megalpole como So Paulo que possua, por exemplo, 18 milhes de telefones e suponha que nosso software demore, em mdia, 10s (10 milionsimos de segundo) para comparar dois nomes. Neste caso, seriam necessrios 180s ou 3 minutos para descobrir que um determinado nome no consta na lista. Nos dias de hoje, uma espera dessas , obviamente, considerada inaceitvel. Se levarmos em conta que o vetor j se encontra previamente ordenado, possvel melhorar um pouco o algoritmo da busca seqencial fazendo com que a busca termine assim que encontrarmos um elemento maior do que o elemento procurado. Mas, note que se estamos procurando por um valor prximo aos valores dos ltimos elementos do vetor, o tempo total da busca continua to alto quanto antes. Dizemos que a complexidade de pior caso do algoritmo ainda da ordem de n, onde n o nmero de elementos do vetor. Por outro lado, a busca binria utiliza a informao de que o vetor se encontra pr-ordenado de uma maneira muito perspicaz. Qual a complexidade de pior caso da busca binria? Em outras palavras, qual o maior nmero

18.3. FUSO

107

possvel de iteraes do while do mtodo buscaBinria? A resposta simples: note que a cada iterao do while, a parte que resta do vetor dividida ao meio. Ento a pergunta que devemos fazer : quantas vezes eu consigo dividir ao meio um vetor de n elementos at que o vetor resultante contenha apenas um elemento? Pense um pouco... Aqueles com os conhecimento matemticos em dia vo se lembrar... A resposta log2 n, ou seja, o logaritmo de n na base 2. Portanto, a complexidade de pior caso do algoritmo de busca binria da ordem de log2 n. Voltemos ao exemplo da lista telefnica de nossa megalpole. Se nosso software demora, em mdia, 10s para comparar dois nomes, ento utilizando o algoritmo da busca binria, demoraramos log2 18.000.000 10 10 1.000.000 = 24, 1 1.000.000 = 0.000241s, ou 0,24 milissegundos, o que bem melhor do que 3 minutos, no? Portanto, quando nos deparamos com grandes volumes de dados ou problemas computacionalmente difceis, a escolha do algoritmo que utilizamos pode ter um grande impacto na ecincia do programa que estamos criando. A rea de Anlise de Complexidade de Algoritmos estuda exatamente estas questes.

18.3

Fuso

Um outro algoritmo interessante ligado a seqncias ordenadas a fuso de duas delas. Ou seja, a unio (preservando repeties) de duas seqncias ordenadas em uma nica seqncia maior ainda em ordem. Esta operao conhecida como fuso. Vejamos como podemos implement-la:
/ / Combinao de d o i s v e t o r e s o r d e n a d o s em um novo v e t o r o r d e n a d o . / / N o t e que e s t e mtodo d e v o l v e um v e t o r . int [] fuso ( int [] a , int b [ ] ) { i n t posa = 0 , posb = 0 , posc = 0; i n t [ ] c = new i n t [ a . l e n g t h + b . l e n g t h ] ; / / E n q u a n t o nenhuma d a s d u a s s e q n c i a s e s t v a z i a . . . w h i l e ( p o s a < a . l e n g t h && p o s b < b . l e n g t h ) { / / Pega o menor e l e m e n t o a t u a l e n t r e a e b . i f ( b [ p o s b ] <= a [ p o s a ] ) { c [ posc ] = b [ posb ] ; p o s b ++; } else { c [ posc ] = a [ posa ] ; p o s a ++; } p o s c ++; } / / C o m p l e t a com a s e q n c i a que a i n d a no acabou . while ( posa < a . l e n g t h ) { c [ posc ] = a [ posa ] ; p o s c ++; p o s a ++;

108
} while ( posb < b . l e n g t h ) { c [ posc ] = b [ posb ] ; p o s b ++; p o s c ++; } return c ; }

CAPTULO 18. BUSCA BINRIA E FUSO

Exerccios
1. Implemente o algoritmo de busca ternria, que funciona de forma similar ao de busca binria mas que divide o vetor em trs partes iguais a cada iterao. 2. Construa um programa que o auxilie a determinar qual algoritmo mais eciente: a busca binria ou a busca ternria. 3. Escreva novamente o algoritmo de fuso de seqncias de forma a no preservar repeties de elementos. Ou seja, se um elemento aparece em ambas seqncias de entrada, a seqncia resultante conter apenas uma cpia dele. 4. Analise a complexidade do algoritmo de fuso para o caso em que ambos os vetores de entrada tm tamanho n. Em outras palavras, qual a ordem do nmero de comparaes e atribuies utilizadas pelo algoritmo no pior caso. 5. Analise a complexidade do algoritmo de ordenao por seleo direta que vimos no captulo passado. Quantas comparaes e quantas trocas de elementos o algoritmo realiza? Dica: a frmula da PA (progresso aritmtica) pode ajudar.

Captulo 19

Construtores e Especicadores de Acesso


Quais novidades veremos neste captulo? Construtores; Especicadores de acesso; final e static.

19.1

Construtores

Desde o incio deste livro, trabalhamos com diferentes tipos de objetos. Mas, antes de comear a usar um objeto de uma classe ClasseX, devemos cri-lo. Isto foi feito at agora atravs de chamadas do tipo: ClasseX x = new ClasseX(); na qual a varivel x passa a se referir a um novo objeto da classe ClasseX. Na linguagem Java, quando no especicamos como um objeto deve ser criado, a prpria linguagem nos fornece um construtor padro. Vejamos com mais detalhes um exemplo abaixo:
c l a s s Ex1 { int a ; double d ; String s ; boolean b ; void imprime ( ) { System . o u t . p r i n t l n System . o u t . p r i n t l n System . o u t . p r i n t l n System . o u t . p r i n t l n }

( "o ( "o ( "a ( "o

i n t e i r o vale " + a ) ; real vale " + d ) ; String vale " + s ) ; boolean vale " + b ) ;

p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {

109

110
Ex1 e = new Ex1 ( ) ; e . imprime ( ) ; } }

CAPTULO 19. CONSTRUTORES E ESPECIFICADORES DE ACESSO

No exemplo acima podemos ver que os nmeros foram inicializados automaticamente com zero, a String com null e o boolean com false. A inicializao com a referncia nula, null, o padro para as referncias a objetos em geral. Mas, e se por alguma razo queremos que as variveis da classe tenham algum valor pr-denido ou, melhor ainda, que seja denido durante a "construo"do objeto? Neste caso podemos denir explicitamente um construtor. Veja o exemplo abaixo:
c l a s s Ex2 { int a ; double d ; String s ; boolean b ; Ex2 ( i n t i 1 , d o u b l e d1 , S t r i n g s1 , b o o l e a n b1 ) { a = i1 ; d = d1 ; s = s1 ; b = b1 ; } void imprime ( ) { System . o u t . p r i n t l n ( " o i n t e i r o v a l e " + a ) ; System . o u t . p r i n t l n ( " o r e a l v a l e " + d ) ; System . o u t . p r i n t l n ( " a S t r i n g v a l e " + s ) ; System . o u t . p r i n t l n ( " o b o o l e a n v a l e " + b ) ; } p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { / / Ex2 e = new Ex2 ( ) ; ERRO no podemos m a i s u s a r o c o n s t r u t o r p a d r o Ex2 o b j 1 = new Ex2 ( 2 , 3 . 1 4 , " Oi " , t r u e ) ; Ex2 o b j 2 = new Ex2 ( 1 , 1 . 0 , " Tudo 1 " , t r u e ) ; obj1 . imprime ( ) ; System . o u t . p r i n t l n ( ) ; obj2 . imprime ( ) ; } }

A primeira observao importante que no podemos mais usar o construtor padro. Se a prpria classe nos fornece um construtor, de se esperar que devamos respeitar algumas regras na hora de construir o objeto, logo o construtor padro no est mais disponvel. Podemos tambm pensar em um exemplo um pouco mais sosticado, criando uma classe que representa contas em um banco. Como atributos bvios podemos pensar em ter o nome do titular e o saldo de cada conta. natural que no possamos criar contas sem titular, logo no construtor sempre ser necessrio fornecer um

19.1. CONSTRUTORES nome (String).


c l a s s Conta { String t i t u l a r ; double s a l d o ; Conta ( S t r i n g s , double v a l ) { titular = s; saldo = val ; } void imprime ( ) { System . o u t . p r i n t l n ( "O c l i e n t e : " + t i t u l a r + " tem s a l d o " + s a l d o ) ; } p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { C o n t a c1 = new C o n t a ( " J o s " , 1 0 0 ) ; C o n t a c2 = new C o n t a ( " M a r i a " , 1 0 0 0 ) ; c1 . i m p r i m e ( ) ; System . o u t . p r i n t l n ( ) ; c2 . i m p r i m e ( ) ; } }

111

Mesmo no exemplo bem simples acima podemos notar que uma operao usual a criao de contas com saldo zero. Logo, parece natural que tenhamos um construtor que receba apenas o nome, e no o saldo (cando subentendido neste caso que no houve depsito inicial).
Conta ( S t r i n g s ) { titular = s; saldo = 0; }

Pode-se observar tambm que podemos reescrever o construtor acima usando funcionalidades do primeiro construtor.
Conta ( S t r i n g s ) { this ( s , 0.0); }

Para isso usamos uma palavra reservada da linguagem Java, a palavra this, que nada mais do que uma referncia ao prprio objeto. Isto , quando o construtor Conta("Joo") chamado, ele repassa o trabalho ao outro construtor usando saldo 0. Tambm interessante notar a diferena entre os dois construtores: como eles tm o mesmo nome (nome da classe), a nica diferena entre eles est nos parmetros recebidos. O compilador Java escolhe o construtor

112

CAPTULO 19. CONSTRUTORES E ESPECIFICADORES DE ACESSO

correto conforme a assinatura (parmetros e sua ordem). Esta mesma tcnica tambm pode ser usada se precisarmos de dois mtodos com o mesmo nome, mas que recebam parmetros diferentes. Isto chamado de polimorsmo de nome. Tambm interessante ressaltar um outro uso da palavra chave this. Vamos supor que adicionamos um novo parmetro para as contas, o RG. Logo, teremos um atributo a mais: String RG. Se por acaso quisermos criar um novo construtor que receba um parmetro tambm chamado de RG, isto se torna possvel.
C o n t a ( S t r i n g s , d o u b l e v a l , S t r i n g RG) { titular = s; saldo = val ; t h i s . RG = RG; }

No caso, o this refora que estamos falando de um dos atributos do objeto. At o momento no havamos usado o this pois tomamos o cuidado de escolher os nomes de parmetros e variveis locais diferentes dos nomes dos atributos.

19.2

Especicadores de acesso

Continuando com o exemplo anterior, poderamos adicionar mtodos seguros para efetuar depsitos e saques.
void saque ( double v a l ) { i f ( v a l <= s a l d o ) { System . o u t . p r i n t l n ( " Saque e f e t u a d o com s u c e s s o " ) ; saldo = saldo val ; } else System . o u t . p r i n t l n ( " S a l d o INSUFICIENTE " ) ; imprime ( ) ; } void d e p o s i t o ( double v a l ) { saldo = saldo + val ; imprime ( ) ; }

No cdigo acima, no caso de saque, veramos mensagens avisando sobre o sucesso ou falha na operao. Existem outras formas mais bonitas de mostrar as falhas atravs de excees (Exceptions), mas estas fogem ao escopo deste livro. Entretanto, um usurio poderia autorizar saques quaisquer, da seguinte forma:
C o n t a c2 = new C o n t a ( " M a r i a " , 1 0 0 0 ) ; c2 . i m p r i m e ( ) ; c2 . s a l d o = c2 . s a l d o 1 0 0 0 0 0 ; c2 . i m p r i m e ( ) ;

Pois, neste caso, o usurio do objeto do tipo Conta estaria interagindo diretamente com atributos do objeto, mexendo nas suas partes internas. Para evitar isto podemos usar protees explcitas, indicando que s mtodos

19.2. ESPECIFICADORES DE ACESSO

113

do prprio objeto possam alterar os seus atributos. Isto feito com a palavra chave private, como neste exemplo:
c l a s s Conta { private String t i t u l a r ; p r i v a t e double s a l d o ; p r i v a t e S t r i n g RG; ... }

Neste caso, no existe mais o acesso direto aos atributos de objetos da classe Conta. O oposto de private public que d acesso irrestrito. Os especicadores de acesso tambm podem ser usados com os mtodos. Quando nenhum especicador utilizado, a linguagem Java usa o acesso amigvel (friendly) que s permite a visibilidade dentro do mesmo pacote (por enquanto pode se pensar em pacote como sendo equivalente a um diretrio). Um outro qualicador interessante o static que indica quais atributos devem ser considerados como da classe e no especcos a cada objeto. Veja o seguinte exemplo:
class TesteStatic { s t a t i c int quantidade = 0; TesteStatic () { System . o u t . p r i n t l n ( " C r i a n d o um o b j e t o do t i p o T e s t e S t a t i c " ) ; q u a n t i d a d e ++; System . o u t . p r i n t l n ( " At a g o r a f o r a m c r i a d o s : " + q u a n t i d a d e + " objetos TesteStatic " ); } }

A cada objeto TesteStatic criado veremos quantos objetos deste tipo j foram criados anteriormente. Observem que no uma prtica usual colocar impresses no construtor, mas de forma a apresentar um exemplo simples optamos por tomar esta liberdade. Alm disto, mtodos static tambm so mtodos de classe, isto , podem ser chamados, mesmo que no existam objetos da classe criados. Um exemplo j visto so as funes da classe Math como, por exemplo, Math.sin(double x). O mtodo main tambm esttico pois ao iniciarmos a execuo de um programa no existe objeto criado. Finalmente, um ltimo qualicador interessante o final que serve para denir variveis que no podem mais ter o seu valor modicado, como, por exemplo, final double PI = 3.1415926538;

Exerccio
1. Reescreva a classe CalculadoraDeImposto descrita no exerccio 2 do Captulo 7, contendo um mtodo que no recebe nenhum parmetro e devolve o imposto a ser pago. A classe CalculadoraDeImposto deve possuir em seus atributos as classes Rendimentos e TabeladeAlquotas e receber como parmetros em seu construtor todos os valores necessrios para inicializar objetos destas classes. Compare a abordagem do exerccio do Captulo 7 com a deste exerccio.

114

CAPTULO 19. CONSTRUTORES E ESPECIFICADORES DE ACESSO

2. Suponha que voc possua um programa de edio de imagens que manipula objetos geomtricos. Voc deseja denir uma classe Quadrado contendo como atributos um inteiro cor e um String tamanho, denidos pelo usurio no momento de sua criao, mas que no podem ser posteriormente modicados. Como voc escreveria esta classe? 3. Modique a classe Quadrado do Exerccio 2 de modo que a cor e o tamanho do objeto possam ser alterados aps sua atribuio inicial. Alm disso, a classe deve garantir que sejam atribudos, para o campo tamanho, apenas valores positivos e, para o campo cor, apenas as cores amarelo, azul, verde ou vermelho. 4. (difcil): Como fazer para criar uma classe na qual s seja possvel construir um nico objeto. Este tipo de objeto chamado de Singleton. Dica: Limitar o acesso ao construtor.

Captulo 20

Interfaces
Quais novidades veremos neste captulo? Interfaces.

Interface: local onde dois sistemas independentes se encontram, atuam ou se comunicam. Webster.

20.1

O conceito de interfaces

Um dos conceitos principais de orientao a objetos o encapsulamento, atravs do qual, tanto os atributos quanto a implementao dos mtodos de uma certa classe no so visveis ao usurio da classe. Conhecendo-se apenas a interface de uma classe, isto , os mtodos disponveis e suas respectivas assinaturas, podemos utilizar objetos desta classe sem conhecer detalhes de como ela implementada internamente. Alm disto, existem casos, onde existe a necessidade de se ter uma classe mas no queremos implement-la. Neste caso, pode-se terceirizar a implementao, fornecendo como especicao a interface desejada.

20.2

Um primeiro exemplo

Vejamos um exemplo prtico: voc tem a misso de criar um zoolgico virtual com vrios tipos de animais. Voc gostaria de enviar as seguintes mensagens a cada animal: nasa(); passeiePelaTela(); durma(); Mas, apesar de ser especialista em computao, voc conhece muito pouco a respeito de animais, logo voc ter que pedir a outros programadores, que conhecem bem os animais, as seguintes classes: Ornitorrinco, Morcego e Zebra. Neste caso, voc passar a seguinte especicao: 115

116

CAPTULO 20. INTERFACES

i n t e r f a c e Animal { void nasa ( ) ; void p a s s e i e P e l a T e l a ( ) ; v o i d durma ( ) ; double peso ( ) ; }

O programador que for implementar o morcego ter que dizer explicitamente que vai usar a interface Animal, o que feito atravs da palavra chave implements. Como o objetivo apresentar como funcionam as interfaces, o cdigo dos animais ser apenas composto de comandos de impresso de mensagens.
p u b l i c c l a s s Morcego implements Animal { public void nasa ( ) { System . o u t . p r i n t l n ( " Nasce um l i n d o morcego " ) ; } public void p a s s e i e P e l a T e l a ( ) { System . o u t . p r i n t l n ( " Voa de um l a d o p a r a o o u t r o " ) ; } p u b l i c v o i d durma ( ) { System . o u t . p r i n t l n ( " Dorme de p o n t a c a b e a " ) ; } p u b l i c double peso ( ) { r e t u r n 4 . 5 ; / / morcego : ) } }

A palavra chave implements obriga o programador a escrever o cdigo correspondente a todos os mtodos com suas respectivas assinaturas. Alm disto, todos os mtodos da interface devem ser obrigatoriamente pblicos. Vejamos as implementaes das outras classes:
p u b l i c c l a s s O r n i t o r r i n c o implements Animal { double peso ; O r n i t o r r i n c o ( double p ) { peso = p ; } p u b l i c double peso ( ) { return peso ; } public void nasa ( ) { System . o u t . p r i n t l n ( " Quebra o ovo p a r a s a i r " ) ; }

20.2. UM PRIMEIRO EXEMPLO


public void p a s s e i e P e l a T e l a ( ) { System . o u t . p r i n t l n ( " Anda e n a d a de um l a d o p a r a o o u t r o " ) ; } p u b l i c v o i d durma ( ) { System . o u t . p r i n t l n ( " Dorme d e n t r o de t n e i s , d u r a n t e o d i a " ) ; } } p u b l i c c l a s s Z e b r a implements Animal { int l i s t r a s ; double peso ; p u b l i c Zebra ( i n t l , double p ) { l i s t r a s = l ; / / c r i a uma z e b r a com l l i s t r a s peso = p / / e peso p } public void nasa ( ) { System . o u t . p r i n t l n ( " Nasce m a i s uma z e b r a " ) ; } public void p a s s e i e P e l a T e l a ( ) { System . o u t . p r i n t l n ( " G a l o p a p e l o campo " ) ; } p u b l i c v o i d durma ( ) { System . o u t . p r i n t l n ( " Dorme em p " ) ; } p u b l i c double peso ( ) { return peso ; } / / nada i m p e d e que s e j a m i m p l e m e n t a d o s m t o d o s a d i c i o n a i s public void c o n t a L i s t r a s ( ) { System . o u t . p r i n t l n ( " E s t a z e b r a tem " + l + " l i s t r a s " ); } }

117

Em tempo: Existe uma regra em Java com relao ao nmero de classes pblicas que podem existir em um arquivo .java. Em cada arquivo deve existir no mximo uma classe pblica, sendo que, caso exista uma, o nome do arquivo deve ser igual ao nome da classe pblica. Logo, no exemplo acima, as classes Ornitorrinco, Morcego e Zebra devem estar em arquivos separados, com os respectivos nomes: Ornitorrinco.java, Morcego.java e Zebra.java.

118

CAPTULO 20. INTERFACES

Mas, o uso da interface um pouco mais amplo, pois podemos considerar que cada um dos animais alm de ser um objeto da prpria classe tambm um objeto do tipo Animal. interessante ressaltar que no podemos criar novos objetos a partir da interface Animal. Vejamos mais um exemplo:
class ZoolgicoVirtual { s t a t i c p u b l i c v o i d c i c l o D e V i d a ( Animal a n i m a l ) { animal . nasa ( ) ; animal . p a s s e i e P e l a T e l a ( ) ; a n i m a l . durma ( ) ; } s t a t i c public void f a z F u n c i o n a r ( ) { Zebra z1 = new Z e b r a ( 1 0 2 , 9 9 ) ; / / c r i a duas z e b r a s Animal z2 = new Z e b r a ( 1 0 1 , 1 0 7 ) ; / / s e n d o uma do t i p o A n i m a l Morcego m1 = new Morcego ( ) ; O r n i t o r r i n c o o1 = new O r n i t o r r i n c o ( 2 5 ) ; c i c l o D e V i d a ( z1 ) ; c i c l o D e V i d a ( z2 ) ; c i c l o D e V i d a ( m1 ) ; c i c l o D e V i d a ( o1 ) ; } }

Veja o exemplo do painel de iteraes abaixo: > ZoolgicoVirtual.fazFuncionar() Nasce mais uma zebra Galopa pelo campo Dorme de p Nasce mais uma zebra Galopa pelo campo Dorme de p Nasce um lindo morcego Voa de um lado para o outro Dorme de ponta cabea Quebra o ovo para sair Anda e nada de um lado para o outro Dentro de tneis, durante o dia > Observe que apesar de z2 ter sido denido como uma nova Zebra, a referncia para um objeto do tipo Animal, de modo que chamadas do tipo z2.contaListras() no so vlidas, mas chamadas z1.contaListras() o so. Na verdade, seria interessante refatorarmos o mtodo fazFuncionar() da seguinte forma.
s t a t i c public void f a z F u n c i o n a r ( )

20.3. IMPLEMENTANDO MAIS DE UMA INTERFACE POR VEZ


{ Animal [ ] bicharada bicharada bicharada bicharada b i c h a r a d a = new Animal [ 4 ] ; [ 0 ] = new Z e b r a ( 1 0 2 , 9 9 ) ; [ 1 ] = new Z e b r a ( 1 0 1 , 1 0 7 ) ; [ 2 ] = new Morcego ( ) ; [ 3 ] = new O r n i t o r r i n c o ( 2 5 ) ;

119

f o r ( i n t i = 0 ; i < b i c h a r a d a . l e n g t h ; i ++) cicloDeVida ( bicharada [ i ] ) ; }

Ficou bem melhor, no? D para melhorar um pouco mais ainda:


s t a t i c public void f a z F u n c i o n a r ( ) { Animal [ ] b i c h a r a d a = { new Z e b r a ( 1 0 2 , 9 9 ) , new Z e b r a ( 1 0 1 , 1 0 7 ) , new Morcego ( ) , new O r n i t o r r i n c o ( 2 5 ) } f o r ( i n t i = 0 ; i < b i c h a r a d a . l e n g t h ; i ++) cicloDeVida ( bicharada [ i ] ) ; }

20.3

Implementando mais de uma interface por vez

Vimos acima que podemos ver objetos como sendo do mesmo tipo, desde que eles implementem a mesma interface. Isto tambm vlido no caso de objetos implementarem vrias interfaces (pensando no mundo real isto acontece muito mais freqentemente). Vejam as duas interfaces seguintes:
i n t e r f a c e Voador { v o i d voa ( ) ; void a t e r r i s s a ( ) ; } interface TransportadorDePessoas { void entramPessoas ( ) ; void saemPessoas ( ) ; }

Agora vamos pensar em trs classes: Ave, nibus e Avio. As classes Ave e nibus podem implementar a primeira e segunda interface, respectivamente.
c l a s s Ave implements Voador { p u b l i c v o i d voa ( ) { System . o u t . p r i n t l n ( " B a t e a s a s a s bem f o r t e " ) ; } public void a t e r r i s s a ( ) {

120

CAPTULO 20. INTERFACES


System . o u t . p r i n t l n ( " B a t e a s a s a s m a i s f r a c o e pe o s p s no c h o " ) ; }

} c l a s s n i b u s implements T r a n s p o r t a d o r D e P e s s o a s { public void entramPessoas ( ) { System . o u t . p r i n t l n ( " Abre a s p o r t a s e e n t r a m a s p e s s o a s " ) ; } public void saemPessoas ( ) { System . o u t . p r i n t l n ( " Abre a s p o r t a s e saem a s p e s s o a s " ) ; } }

Finalmente, podemos ver o Avio que implementa as duas interfaces:


c l a s s Avio implements Voador , T r a n s p o r t a d o r D e P e s s o a s { p u b l i c v o i d voa ( ) { System . o u t . p r i n t l n ( " L i g a a s t u r b i n a s ; r e c o l h e o t r e m de p o u s o " ) ; } public void a t e r r i s s a ( ) { System . o u t . p r i n t l n ( " A b a i x a o t r e m de p o u s o e d e s c e " ) ; } public void entramPessoas ( ) { System . o u t . p r i n t l n ( " P r o c e d i m e n t o de embarque " ) ; } public void saemPessoas ( ) { System . o u t . p r i n t l n ( " P r o c e d i m e n t o de d e s e m b a r q u e " ) ; } }

Observe o trecho abaixo:


public class TesteDeInterface { s t a t i c public void faz ( ) { T r a n s p o r t a d o r D e P e s s o a s t = new n i b u s ( ) ; Voador v = new Ave ( ) ; Avio a = new Avio ( ) ; t . entramPessoas ( ) ; t . saemPessoas ( ) ; v . voa ( ) ; / / bate asas v. aterrissa (); / / Com o n i b u s e Ave no podemos chamar a o u t r a i n t e r f a c e . a . entramPessoas ( ) ; a . voa ( ) ;

20.4. UM EXEMPLO MAIS SOFISTICADO


a. aterrissa (); a . saemPessoas ( ) ; v = a; v . voa ( ) ; / / liga turbinas } }

121

Uma boa prtica seguida por bons programadores OO Programe para as interfaces, no para as implementaes. Em outras palavras, toda vez que voc escrever cdigo que utiliza outras classes, no pense em como essas outras classes so implementadas internamente, pense apenas na sua interface. Nunca baseie o seu cdigo em alguma idiossincrasia interna da classe, use apenas conceitos que so claros a partir das interfaces das classes que voc usa.

20.4

Um exemplo mais sosticado

Vamos supor que temos uma classe Fruta com os seguintes atributos: peso, preo e nome. Os trs atributos j devem ser carregados no construtor.
class Fruta { double peso ; double preo ; S t r i n g nome ; F r u t a ( S t r i n g n , double v , double p ) { nome = n ; preo = v ; peso = p ; } void imprime ( ) { System . o u t . p r i n t l n ( nome + " p e s a " + p e s o + " gramas e c u s t a " + preo + " r e a i s " ) ; } }

Queremos criar um vetor de Frutas e orden-lo primeiro por preo e posteriormente por peso. Como fazer isto? Observando os procedimentos de ordenao j vistos fcil ver que a nica mudana o critrio de comparao. Veja uma implementao usando o algoritmo de insero direta visto no Captulo 17.
public c l a s s Quitanda { F r u t a [ ] f r u t a s = new F r u t a [ 5 ] ; public Quitanda ( ) { f r u t a s [ 0 ] = new f r u t a s [ 1 ] = new f r u t a s [ 2 ] = new f r u t a s [ 3 ] = new

Fruta ( " Laranja " , 0.5 , 100); F r u t a ( " Ma " , 0 . 8 , 1 2 0 ) ; F r u t a ( "Mamo" , 1 . 2 , 1 1 0 ) ; Fruta ( " Cereja " , 5.0 , 20);

122
f r u t a s [ 4 ] = new F r u t a ( " J a c a " , 0 . 4 , 5 0 0 ) ; } p u b l i c void imprime ( ) { f o r ( i n t i = 0 ; i < f r u t a s . l e n g t h ; i ++) f r u t a s [ i ] . imprime ( ) ; } public void ordenaPorPreo ( ) { int i , j ; Fruta a I n s e r i r ; f o r ( i = 1 ; i < f r u t a s . l e n g t h ; i ++) { aInserir = frutas [ i ]; j = i; w h i l e ( ( j > 0 ) && ( f r u t a s [ j 1 ] . p r e o > a I n s e r i r . p r e o ) ) { f r u t a s [ j ] = f r u t a s [ j 1]; j ; } frutas [ j ] = aInserir ; } } public void ordenaPorPeso ( ) { int i , j ; Fruta a I n s e r i r ; f o r ( i = 1 ; i < f r u t a s . l e n g t h ; i ++) { aInserir = frutas [ i ]; j = i; w h i l e ( ( j > 0 ) && ( f r u t a s [ j 1 ] . p e s o > a I n s e r i r . p e s o ) ) { f r u t a s [ j ] = f r u t a s [ j 1]; j ; } frutas [ j ] = aInserir ; } } p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { Q u i t a n d a x e p a = new Q u i t a n d a ( ) ; System . o u t . p r i n t l n ( " D e s o r d e n a d o " ) ; xepa . imprime ( ) ; System . o u t . p r i n t l n ( "Em ordem de p r e o " ) ; xepa . o r d e n a P o r P r e o ( ) ; xepa . imprime ( ) ;

CAPTULO 20. INTERFACES

20.4. UM EXEMPLO MAIS SOFISTICADO


System . o u t . p r i n t l n ( "Em ordem de p e s o " ) ; xepa . ordenaPorPeso ( ) ; xepa . imprime ( ) ; } }

123

No programa acima, ca claro que tivemos que duplicar o cdigo de ordenao, o que bem desagradvel. Mas, e se existissem outros critrios para ordenao, teramos que criar um novo mtodo repetindo o cdigo de ordenao para cada um dos critrios? Isso seria, com certeza, muito ruim. Como regra geral, devemos sempre evitar cdigo repetido. Quando identicamos um trecho de cdigo que aparece repetido em vrios lugares, como no caso acima, devemos tentar refatorar (reorganizar) o cdigo para evitar a repetio. Neste caso, iremos manter o cdigo de ordenao em um mtodo e colocar em outros mtodos apenas aquele pequeno trecho que difere de um para outro (o critrio de comparao). Para implementar esta nova soluo, utilizaremos uma interface denindo a interface de comparao:
i n t e r f a c e ComparadorDeFrutas { b o o l e a n Menor ( F r u t a a , F r u t a b ) ; }

O signicado do mtodo bvio: se a for menor que b, o mtodo devolve true, caso contrrio, devolve false. O que a interface ComparadorDeFrutas no dene o signicado da palavra menor. Isso deixado para cada classe concreta que ir implementar esta interface, como vemos abaixo, onde so denidas trs implementaes diferentes para ComparadorDeFrutas que utilizam, como critrio de comparao, o peso, o preo e o nome da fruta, respectivamente.
c l a s s ComparaPeso implements C o m p a r a d o r D e F r u t a s { p u b l i c b o o l e a n Menor ( F r u t a a , F r u t a b ) { r e t u r n ( a . p e s o < b . p e s o ) ; } } c l a s s ComparaPreo implements C o m p a r a d o r D e F r u t a s { p u b l i c b o o l e a n Menor ( F r u t a a , F r u t a b ) { r e t u r n ( a . p r e o < b . p r e o ) ; } } c l a s s ComparaNome implements C o m p a r a d o r D e F r u t a s { p u b l i c b o o l e a n Menor ( F r u t a a , F r u t a b ) { r e t u r n ( a . nome . compareTo ( b . nome ) < 0 ) ; } }

Agora, basta colocar como parmetro adicional do mtodo de ordenao o comparador desejado:
public c l a s s Quitanda { F r u t a [ ] f r u t a s = new F r u t a [ 5 ] ; public Quitanda ( ) { f r u t a s [ 0 ] = new F r u t a ( " L a r a n j a " , 0 . 5 , 1 0 0 ) ; f r u t a s [ 1 ] = new F r u t a ( " Maa " , 0 . 8 , 1 2 0 ) ; f r u t a s [ 2 ] = new F r u t a ( "Mamo" , 1 . 2 , 1 1 0 ) ;

124
f r u t a s [ 3 ] = new F r u t a ( " C e r e j a " , 5 . 0 , 2 0 ) ; f r u t a s [ 4 ] = new F r u t a ( " J a c a " , 0 . 4 , 5 0 0 ) ; } p u b l i c void imprime ( ) { f o r ( i n t i = 0 ; i < f r u t a s . l e n g t h ; i ++) f r u t a s [ i ] . imprime ( ) ; } public void ordena ( ComparadorDeFrutas c ) { int i , j ; Fruta a I n s e r i r ; f o r ( i = 1 ; i < f r u t a s . l e n g t h ; i ++) { aInserir = frutas [ i ]; j = i; w h i l e ( ( j > 0 ) && ( c . Menor ( a I n s e r i r , f r u t a s [ j 1 ] ) ) ) { f r u t a s [ j ] = f r u t a s [ j 1]; j ; } frutas [ j ] = aInserir ; } } p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { Q u i t a n d a x e p a = new Q u i t a n d a ( ) ; System . o u t . p r i n t l n ( " F r u t a s d e s o r d e n a d a s " ) ; xepa . imprime ( ) ;

CAPTULO 20. INTERFACES

System . o u t . p r i n t l n ( "Em ordem de p r e o : " ) ; C o m p a r a d o r D e F r u t a s cmp = new ComparaPreo ( ) ; x e p a . o r d e n a ( cmp ) ; xepa . imprime ( ) ; System . o u t . p r i n t l n ( "Em ordem de p e s o : " ) ; cmp = new ComparaPeso ( ) ; x e p a . o r d e n a ( cmp ) ; xepa . imprime ( ) ; System . o u t . p r i n t l n ( "Em ordem a l f a b t i c a : " ) ; x e p a . o r d e n a ( new ComparaNome ( ) ) ; / / n o t e e s t a f o r m a s u p e r c o n d e n s a d a . xepa . imprime ( ) ; } }

20.5. A IMPORTNCIA DE INTERFACES

125

20.5

A importncia de interfaces

O conceito de interfaces na programao orientada a objetos muito importante e o seu uso adequado traz inmeras vantagens no desenvolvimento de sistemas grandes e complexos. Eis algumas dessas vantagens: 1. Se os objetos interagem entre si atravs de referncias a interfaces e no a classes especcas, ca fcil mudar as classes utilizadas em um sistema sem interferir com aquelas que as utilizam. Por exemplo, se uma classe implementa uma certa interface, mudanas na implementao da classe que no alterem a assinatura dos mtodos desta interface no so notadas ao se utilizar objetos atravs desta interface. 2. Fica fcil implementar algo chamado polimorsmo de comportamento, ou seja, podemos utilizar em diferentes momentos classes com diferentes comportamentos, chaveando de um comportamento para outro quando for necessrio. O uso de interfaces permite que este chaveamento seja feito tanto quando o programa compilado quanto durante a sua execuo. O exerccio do berrio (veja a seo de exerccios a seguir) um exemplo deste polimorsmo onde interfaces so utilizadas para tornar um programa multilinge, ou seja, com muito pouco esforo pode-se escolher qual lngua (portugus, ingls, francs, etc.) um programa ou sistema utilizar para interagir com seus usurios. 3. Se se est desenvolvendo um programa ou sistema muito grande e complexo, pode ser necessrio utilizar vrios programadores ou, at mesmo, vrias equipes de programadores. Neste caso, o que se costuma fazer dividir o sistema em sub-sistemas e denir muito bem as interfaces de cada sub-sistema. A partir da, cada equipe pode desenvolver independentemente o seu sub-sistema sem necessitar de conhecimentos sobre o funcionamento interno dos outros sub-sistemas; basta conhecer as suas interfaces. Aps esta fase, passa-se fase de integrao, durante a qual os vrios sub-sistemas so compilados, executados e testados em conjunto. 4. O uso de interfaces pode ajudar a eliminar cdigo repetido (como no exemplo anterior do ComparadorDeFrutas), o que ajuda a melhorar muito a qualidade do cdigo. 5. Usando-se interfaces, possvel encomendar a terceiros a escrita de partes de um programa sem que esta pessoa tenha que conhecer o resto do programa ou mesmo ter acesso ao seu cdigo-fonte. Veja um exemplo desta prtica no exerccio das guras geomtricas abaixo, que se utiliza de uma interface Figura2D.

Exerccios
1. Seu chefe est fazendo um programa para manipulao de guras geomtricas. Como o programa muito complexo, ele pediu a sua ajuda encomendando a voc a implementao de trs classes (Quadrado, Retngulo e Crculo). Voc livre para denir como ser a implementao mas seu chefe deniu que as suas classes devem implementar a seguinte interface:
interface { double double void String Figura2D calcularea ( ) ; calculaPermetro (); mudaCor ( S t r i n g c o r ) ; pegaCor ( ) ;

126
}

CAPTULO 20. INTERFACES

2. Escreva duas implementaes para a interface VeculoDeCorrida, a seguir:


interface VeculoDeCorrida { S t r i n g marca ( ) ; S t r i n g modelo ( ) ; String cor ( ) ; in t potnciaEmCavalos ( ) ; }

Agora, escreva um mtodo veculoPreferido() que recebe um array de veculos de corrida como parmetro e, dentre os veculos vermelhos, imprime a marca e o modelo do que possuir a maior potncia. 3. Voc foi contratado para trabalhar em um berrio (!!!) e no seu primeiro dia de trabalho, deve escrever uma classe para informar aos pais dados sobre os seus bebs. A diculdade que muitos estrangeiros freqentam esse berrio e o seu programa deve ser capaz de dar informaes em portugus e em ingls (e, futuramente, em outros idiomas tambm). Para permitir isso, voc dever prover duas implementaes da interface a seguir, que indica as mensagens de texto que devero ser mostradas aos pais:
interface { String String String String } MensagensSobreNeoNatal nomeDoBeb ( S t r i n g nome ) ; d a t a D e N a s c i m e n t o ( Beb b ) ; p e s o ( d o u b l e p e s oE m Q u i l os ) ; t e m p e r a t u r a ( double t e m p e r a t u r a E m C e l s i u s ) ;

Ao se chamar o mtodo nomeDoBeb, por exemplo, sua implementao deve devolver uma mensagem como "O nome do beb Godofredo Manoelino de Moraes". Ao se chamar o mtodo peso, deve-se devolver algo como "O peso do beb 3140 gramas ". A primeira implementao deve se chamar MensagensBrasileiras e a segunda MensagensEstadosunidenses. As mensagens para os americanos devem apresentar o peso em libras (pounds) e a temperatura em graus fahrenheit. A interface Beb, que vocs no precisam implementar, pois podem supor que o berrio j possui as implementaes, a seguinte:
i n t e r f a c e Beb { S t r i n g nome ( ) ; int diaNascimento ( ) ; i n t m e s Na s c i m e nt o ( ) ; i n t anoNascimento ( ) ; d o u b l e p e s o ( ) ; / / SI , ou s e j a , em q u i l o s d o u b l e t e m p e r a t u r a ( ) ; / / SI , ou s e j a , em c e l s i u s }

A classe que o berrio vai usar para imprimir as informaes para os pais ter um mtodo similar ao seguinte:
class Berrio {

20.5. A IMPORTNCIA DE INTERFACES


Beb [ ] l i s t a D e B e b s ; / / a q u i vo o u t r o s m t o d o s p a r a i n s e r o e / / remoo de b e b s da l i s t a v o i d i m p r i m e D a d o s S o b r e B e b ( Beb b , M e n s a g e n s S o b r e N e o N a t a l m) { System . o u t . p r i n t l n (m. nomeDoBeb ( b . nome ( ) ) ; System . o u t . p r i n t l n (m. d a t a D e N a s c i m e n t o ( b ) ; System . o u t . p r i n t l n (m. p e s o ( b . p e s o ( ) ) ; System . o u t . p r i n t l n (m. t e m p e r a t u r a ( b . t e m p e r a t u r a ( ) ) ; } v o i d i m p r i m e ( i n t IDdoBeb , S t r i n g i d i o m a ) { M e n s a g e n s S o b r e N e o N a t a l m; i f ( idioma . equals ( " Portugus " ) ) m = new M e n s a g e n s B r a s i l e i r a s ( ) ; else m = new M e n s a g e n s E s t a d o s u n i d e n s e s ( ) ; i m p r i m e D a d o s S o b r e B e b ( l i s t a D e B e b s [ IDdoBeb ] , m ) ; } }

127

4. Dada a classe
c l a s s Pessoa { S t r i n g nome ; in t rg ; int cpf ; }

escreva duas implementaes da interface


interface LocalizadorDePessoas { P e s s o a l o c a l i z a P o r R G ( i n t rg , P e s s o a [ ] vp ) ; }

utilizando busca seqencial e busca binria. 5. Refatore o mtodo ZoolgicoVirtual.fazFuncionar() de forma a usar a classe Scanner para permitir que um usurio crie interativamente uma coleo de animais virtuais de diferentes tipos. 6. (Longo) Voc foi contratado para ajudar na implementao de uma loja virtual para venda, atravs da Web, de livros, CDs, LPs, DVDs, lmes VHS, etc. No seu primeiro dia de trabalho, seu chefe lhe mostrou a seguinte interface que utilizada para representar todos os produtos a serem vendidos pela loja: interface Produto

128 { String int int String String }

CAPTULO 20. INTERFACES

ttulo(); nmeroDeIdentificao(); // nmero nico identificando o produto ano(); autor(); mdia(); // devolve "livro", "CD", "DVD", etc.

No seu primeiro dia de trabalho, voc deve implementar uma classe contendo mtodos para: (a) dada uma lista de compras (um array de Produtos), devolver uma nova lista de compras contendo o mesmo contedo mas com os produtos ordenados de acordo com os seus nmerosDeIdentificao; (b) dadas duas listas de compras, cada uma delas j ordenadas com o mtodo acima, gerar e devolver uma nova lista ordenada resultante da fuso das duas listas iniciais; elementos que aparecerem nas duas listas iniciais devero aparecer duplicados na lista nal. (c) Agora, escreva pelos menos duas classes que implementem a interface Produto e, em seguida, d um exemplo de cdigo que cria duas listas de compras, as ordena, as funde, e nalmente imprime de forma clara e organizada as informaes sobre os produtos contidos na lista resultante da fuso.

Captulo 21

Herana
Quais novidades veremos neste captulo? Herana.

21.1

O Conceito de herana

A demanda pela construo de software em nossa sociedade muito grande. O nmero de bons programadores disponveis relativamente pequeno. Por isso, os projetistas de linguagens e sistemas de computao tm buscado formas de acelerar e facilitar o desenvolvimento de software. Uma das principais abordagens utilizadas a reutilizao de cdigo. Se conseguirmos escrever cdigo que reutilizado em diversos programas diferentes, teremos economizado tempo pois no ser necessrio reescrever este cdigo para cada novo programa. A biblioteca de classes de Java um exemplo de classes que foram escritas pelos programadores da Sun e que so reutilizadas diariamente por milhares de programadores em todo o mundo. Porm, algumas vezes, o programador necessita fazer alguma modicao em uma classe existente pois ela no atende exatamente s necessidades de um dado programa. Em alguns casos deseja-se modicar a implementao de um de seus mtodos, em outros casos deseja-se acrescentar alguma funcionalidade extra classe, com a adio de novos mtodos e atributos. Esta reutilizao de cdigo com extenses e modicaes, pode ser obtida em linguagens orientadas a objetos atravs do conceito de Herana. A gura 21.1 mostra um diagrama contendo 4 classes que se relacionam entre si atravs de herana. Este diagrama de classes segue um padro chamado UML (Unied Modeling Language). Este padro muito utilizado para modelar programas orientados a objetos, mas no veremos mais detalhes sobre ele neste livro. Apresentamos o diagrama aqui apenas a ttulo de ilustrao.

129

130

CAPTULO 21. HERANA

Figura 21.1: Diagrama de herana

21.2

Terminologia de herana

Dizemos que Pessoa a superclasse de Aluno e de Professor. Professor subclasse de Pessoa e superclasse de ProfessorDoutor. Dizemos ainda que Aluno herda de Pessoa os seus atributos e mtodos; ou que Aluno estende a classe Pessoa. Dizemos que Pessoa pai (ou me ) de Professor e que Professor lho (a) de Pessoa.

21.3

Implementao de herana na linguagem Java

Para especicar, em Java, que uma classe B subclasse de A, utilizamos a palavra extends:
class A { i n t a1 ; v o i d p a t a ( ) { a1 = 1 ; } } c l a s s B extends A { i n t b1 ; void vina ( ) { pata ( ) ; b1 = a1 ; } }

Note que B contm os mtodos e atributos de A e ainda acrescenta um novo atributo e um novo mtodo. Vejamos agora um exemplo mais complexo que implementa, em Java, o diagrama de classes apresentado no diagrama UML acima.

21.3. IMPLEMENTAO DE HERANA NA LINGUAGEM JAVA

131

c l a s s Pessoa { p r i v a t e S t r i n g nome ; p r i v a t e char s e x o ; p r i v a t e S t r i n g CPF ; p r i v a t e S t r i n g RG; p r i v a t e i n t a n oD e N a s ci m e n to ; v o i d imprimeDados ( ) { i f ( s e x o == F ) System . o u t . p r i n t l n ( "A S r a . " + nome + " n a s c e u no ano " + an o D e Na s c i m en t o + " . CPF : " + CPF + " , RG " + RG ) ; else System . o u t . p r i n t l n ( "O S r . " + nome + " n a s c e u no ano " + an o D e Na s c i m en t o + " . CPF : " + CPF + " , RG " + RG ) ; } } c l a s s Aluno e x t e n d s P e s s o a { private String curso ; private int anoDeIngresso ; v o i d imprimeDados ( ) { s u p e r . imprimeDados ( ) ; System . o u t . p r i n t l n ( " I n g r e s s o u no c u r s o " + c u r s o + " em " + anoDeIngresso ) ; } } c l a s s P r o f e s s o r extends Pessoa { private String departamento ; p r i v a t e i n t anoDeAdmisso ; v o i d imprimeDados ( ) { s u p e r . imprimeDados ( ) ; System . o u t . p r i n t l n ( " I n g r e s s o u no d e p t . " + d e p a r t a m e n t o + " em " + anoDeAdmisso ) ; } } c l a s s ProfessorDoutor extends P r o f e s s o r { p r i v a t e i n t anoDeObtenoDoutorado ; private String instituioDoDoutorado ; v o i d imprimeDados ( ) { s u p e r . imprimeDados ( ) ; System . o u t . p r i n t l n ( " D o u t o r a d o o b t i d o em " + i n s t i t u i o D o D o u t o r a d o + " em " + a n o D e O b t e n o D o u t o r a d o ) ; } }

132

CAPTULO 21. HERANA Um banco de dados da universidade pode armazenar objetos do tipo Pessoa da seguinte forma:

c l a s s ListaDePessoasDaUSP { P e s s o a [ ] membrosDaUSP ; L i s t a D e P e s s o a s D a U S P ( i n t tamanho ) { membrosDaUSP = new P e s s o a [ tamanho ] ; } / / m t o d o s p a r a a c r e s c e n t a r e r e m o v e r p e s s o a s da l i s t a de p e s s o a s void l i s t a T o d o s ( ) { int i ; f o r ( i = 0 ; i < membrosDaUSP . l e n g t h ; i ++) membrosDaUSP [ i ] . imprimeDados ( ) ; } / / demais mtodos . . . }

Note que, para o mtodo listaTodos, no interessa qual o tipo especco de cada pessoa (aluno, professor, professor doutor) uma vez que ele manipula apenas os atributos da superclasse Pessoa.

21.4

Hierarquia de classes

Quando um programa possui uma srie de classes relacionadas atravs de herana, dizemos que temos uma hierarquia de classes. Apresentamos na gura 21.2 uma hierarquia de classes para representar os diversos tipos de seres vivos.

Figura 21.2: Hierarquia de classes representando os seres vivos

21.5. RELACIONAMENTO UM

133

21.5

Relacionamento um

Nem sempre fcil determinarmos qual hierarquia de classes devemos utilizar. A relao superclassesubclasse deve necessariamente ser um relacionamento do tipo " um", ou seja, se B subclasse de A ento todo B um A. Em termos mais concretos, no exemplo dos seres vivos, Animal um SerVivo, e mais, todo animal um ser vivo. No existe nenhum animal que no seja um ser vivo. Ento o relacionamento superclasse-subclasse pode ser apropriado. Outra possibilidade seria ter uma hierarquia como a seguinte:

Figura 21.3: Hierarquia errada

A princpio, esta pode parecer uma hierarquia aceitvel. Mas na verdade ela est ERRADA. No podemos dizer que "um reino um ser vivo", no faz sentido, no podemos dizer que "um lo um reino"porque no . Ento a hierarquia no est boa.

21.6

Resumo

uma classe pode herdar de outra seus atributos e mtodos; uma subclasse pode estender a funcionalidade de sua superclasse acrescentando novos atributos e mtodos. Mas, e se uma subclasse implementar um mtodo com assinatura idntica a um mtodo da superclasse? Neste caso, quem prevalece o mtodo da subclasse e dizemos que o mtodo da subclasse se sobrepe ("overrides") ao mtodo da superclasse.

Exerccios
1. Retornando hierarquia de classes apresentada na gura 21.2, pense em quais mtodos e atributos deveriam estar presentes nas classes superiores da hierarquia e quais deveriam estar nas partes inferiores da hierarquia. 2. Figuras geomtricas so um bom exemplo para se construir um hierarquia de classes. Considere as guras quadrado, retngulo, tringulo (retngulo, acutngulo e obtusngulo) e losango. Construa duas diferentes hierarquias para estas classes, uma com dois nveis e outra com trs nveis, colocando os atributos que

134

CAPTULO 21. HERANA devem ser considerados comuns em cada nvel da hierarquia. Compare estas duas hierarquias, discutindo suas vantagens e desvantagens.

3. Desenvolva um conjunto de classes para controlar o saldo, depsitos e retiradas de contas bancrias bem como os dados do titular. Escreva inicialmente um diagrama modelando tanto contas corrente quanto contas poupana e aplicaes em fundo. Em seguida, implemente estas classes em Java.

Captulo 22

Javadoc
Quais novidades veremos neste captulo? Documentao com javadoc.

Vimos nos ltimos captulos que um conceito fundamental em programao orientada a objeto a separao clara entre implementao e interface. Ou seja, um programador que v usar objetos de uma classe deve se ater poro pblica da mesma, desprezando detalhes de implementao e as pores privadas (que no estariam acessveis de qualquer forma). Deste modo, passa a ser natural a exigncia de documentao de boa qualidade que permita ao usurio de uma classe saber tudo o que precisa sem que necessite ler o cdigo que a implementa. A entra o javadoc. O javadoc um programa que permite extrair, de um arquivo com cdigo Java, a sua documentao (texto explicativo). Essa documentao ento formatada em HTML (HyperText Markup Language), que a mesma linguagem que descreve as pginas da Web, de modo a facilitar a sua consulta. Assim possvel consultar a documentao de uma classe sem as distraes presentes sempre que esta est misturada ao cdigo. Um exemplo disso que, em sua congurao padro, o javadoc processa apenas a documentao das partes pblicas de seu cdigo, omitindo tudo o que privado. Para facilitar a vida do programa javadoc existem algumas convenes que devem ser seguidas. A primeira que apenas comentrios iniciados por /** (e terminados por */) so processados. Tambm o comentrio de cada parte pblica deve preced-la imediatamente. Vejamos um exemplo simples.
p u b l i c c l a s s Quadrado implements F i g u r a G e o m t r i c a { p r i v a t e double l a d o ; private String cor ; p u b l i c Quadrado ( d o u b l e l , S t r i n g c ) { lado = l ; cor = c ; } p u b l i c double c a l c u l a r e a ( )

135

136
{ return lado lado ; } p u b l i c v o i d mudaCor ( S t r i n g c ) { cor = c ; } }

CAPTULO 22. JAVADOC

As partes pblicas no cdigo acima so: 1. A prpria classe, ou seja, todo mundo pode criar objetos baseados nela; 2. O construtor; 3. Os mtodos calcularea e mudaCor. Cada um desses tens deveria ser antecedido por um comentrio explicando qual sua funo e como ele deve ser usado. Lembrando as convenes de como demarcar os comentrios descritas acima, teramos:
/ Uma c l a s s e p a r a r e p r e s e n t a r q u a d r a d o s . / p u b l i c c l a s s Quadrado implements F i g u r a G e o m t r i c a { p r i v a t e double l a d o ; private String cor ; / Construtor E x i g e o c o m p r i m e n t o do l a d o e a c o r do q u a d r a d o . / p u b l i c Quadrado ( d o u b l e l , S t r i n g c ) { lado = l ; cor = c ; } / C a l c u l a a r e a do q u a d r a d o b a s e a d a no s e u l a d o . / p u b l i c double c a l c u l a r e a ( ) { return lado lado ; } / A l t e r a a c o r do q u a d r a d o p a r a a c o r r e p r e s e n t a d a no S t r i n g c . / p u b l i c v o i d mudaCor ( S t r i n g c ) { cor = c ; }

137
}

Uma outra caracterstica interessante do javadoc que ele possui alguns marcadores especiais para que possa extrair informaes relevantes dos comentrios e format-las de modo especial. Os marcadores mais importantes so: Marcadores para comentrios de classes: @author: descreve o autor do cdigo; @version: usado para guardar informao sobre a verso, como seu nmero e data de ltima alterao. Marcadores para comentrios de mtodos: @param: usado para descrever os parmetros, geralmente na forma: @param nome-do-parmetro descrio @return: serve pra descrever o valor devolvido pelo mtodo. Marcador geral: @see. Pode ser usado em qualquer lugar para referenciar uma outra classe ou um mtodo de outra classe; assume geralmente uma das duas forma a seguir. @see nome-da-classe @see nome-da-classe#nome-do-mtodo Se usarmos os marcadores descritos acima na nossa classe Quadrado, teremos:
/ Uma c l a s s e p a r a r e p r e s e n t a r q u a d r a d o s . @author P a u l o S i l v a @ v e r s i o n 1 . 0 , a l t e r a d a em 1 0 / 0 6 / 2 0 0 3 @see F i g u r a G e o m t r i c a / p u b l i c c l a s s Quadrado implements F i g u r a G e o m t r i c a { p r i v a t e double l a d o ; private String cor ; / Construtor @param l d o u b l e r e p r e s e n t a n d o o c o m p r i m e n t o d o s l a d o s @param c S t r i n g com o nome da c o r da f i g u r a / p u b l i c Quadrado ( d o u b l e l , S t r i n g c ) { lado = l ; cor = c ; } / C a l c u l a a r e a do q u a d r a d o b a s e a d a no s e u l a d o @param No h p a r m e t r o s @return r e a computada

138
/ p u b l i c double c a l c u l a r e a ( ) { return lado lado ; } / A l t e r a a c o r do q u a d r a d o . @param c S t r i n g com o nome da nova c o r @return No h r e t o r n o / p u b l i c v o i d mudaCor ( S t r i n g c ) { cor = c ; } }

CAPTULO 22. JAVADOC

Na gura 22.1 apresentada a documentao gerada pelo Javadoc para a classe Quadrado. claro que para o marcador @see funcionar, voc tambm deve documentar a interface usando os padres de javadoc. Ao documentar a interface voc pode usar os mesmos marcadores usados para classe. Agora que temos nosso cdigo documentado de forma adequada, como podemos gerar a documentao em html? Para isso, basta ir ao diretrio com os arquivos .java e digitar javadoc -version -author -d doc *.java A documentao ser ento gerada e os arquivos resultantes sero colocados dentro do subdiretrio doc do diretrio atual. claro que o nome desse diretrio pode ser alterado mudando-se a palavra que segue o -doc presente acima. Por m, podemos tambm documentar as pores privadas de nossas classes. Para forar o javadoc a gerar documentao tambm para a parte privada, basta acrescentar o parmetro -private na linha de comando acima. Obs.: se desejado, os comentrios de javadoc podem conter comandos em HTML.

139

Figura 22.1: Documentao gerada pelo Javadoc

140

CAPTULO 22. JAVADOC

Captulo 23

O C Que H em Java
Quais novidades veremos neste captulo? Veremos como escrever programas na linguagem C a partir de nossos conhecimentos de Java.

23.1

O C que h em Java

Veremos neste captulo como so os programas na linguagem C e como podemos escrev-los usando o que aprendemos neste livro. Em resumo, podemos pensar que um programa em C uma nica classe Java sem a presena de atributos e composta apenas de mtodos estticos. Fora isso, o resto perfumaria. Vamos pensar um pouco em quais so as conseqncias da frase acima: como h apenas uma classe e no h atributos no possvel organizar o programa como diversos objetos, eventualmente pertencentes a classes diferentes, interagindo; como no h atributos s existem dois tipos de variveis: os parmetros e as variveis locais s funes; como no h classes e objetos de verdade, todas as variveis so de tipos primitivos: int, double ou char. Pelo menos h tambm a idia de array, ou vetor, e matrizes em C; em C no h o tipo boolean. No seu lugar usamos inteiros com o 0 representando falso e qualquer nmero no nulo representando verdadeiro. Note que as expresses lgicas passam ento a gerar valores inteiros como resultados. Esses pontos j so interessantes o suciente para vermos o que acontece. Consideremos o primeiro exemplo visto neste livro: o conversor de temperaturas. Voc lembra que ele era um objeto sem atributos? Vejamos o seu cdigo (adicionamos um main e os identicadores de acesso): 141

142

CAPTULO 23. O C QUE H EM JAVA

public c l a s s Conversor { s t a t i c double c e l s i u s P a r a F a h r e n h e i t ( double c ) { return 9.0 c / 5.0 + 3 2 . 0 ; } s t a t i c double f a h r e n h e i t P a r a C e l s i u s ( double f ) { return 5.0 ( f 3 2 .0 ) / 9 . 0 ; } p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { double f a r , c e l ; S c a n n e r s c = new S c a n n e r ( System . i n ) ; System . o u t . p r i n t ( " De um t e m p e r a t u r a em F a h r e n h e i t : " ) ; f a r = sc . nextDouble ( ) ; cel = fahrenheitParaCelsius ( far ); System . o u t . p r i n t l n ( "A t e m p e r a t u r a em C e l s i u s e : " + c e l ) ; System . o u t . p r i n t ( " De um t e m p e r a t u r a em C e l s i u s : " ) ; c e l = sc . nextDouble ( ) ; far = celsiusParaFahrenheit ( cel ); System . o u t . p r i n t l n ( "A t e m p e r a t u r a em F a h r e n h e i t e : " + f a r ) ; } }

Vejamos como caria esse programa na linguagem C:


/ Sempre c o l o q u e a p r o x i m a l i n h a no i n i c i o do programa . / / E l a p e r m i t e que v o c e i m p r i m a na t e l a e l e i a do t e c l a d o . / # i n c l u d e < s t d i o . h> / / / / / Como nao ha c l a s s e s , Do mesmo modo , como precisamos escrever Por f i m nao e x i s t e m e l e s tambem sumiram . s i m p l e s m e n t e apagamos a r e f e r e n c i a a e l a s . / t o d o s o s m e t o d o s s a o e s t a t i c o s nao / isso . / e s p e c i f i c a d o r e s de a c e s s o em C , l o g o / /

double c e l s i u s P a r a F a h r e n h e i t ( double c ) { return 9.0 c / 5.0 + 3 2 . 0 ; } double f a h r e n h e i t P a r a C e l s i u s ( double f ) { return 5.0 ( f 3 2 . 0) / 9 . 0 ; } / V e j a que a c a r a da main mudou . Agora e l a nao r e c e b e nada / / e d e v o l v e um i n t e i r o . / i n t main ( ) { double f a r , c e l ; / Oba , i m p r i m i r f i c o u m a i s f a c i l : o comando e m a i s c u r t o . /

23.2. DETALHES DE ENTRADA E SADA


p r i n t f ( " De um t e m p e r a t u r a em F a h r e n h e i t : " ) ; / A l e i t u r a tambem mudou , v e j a d e t a l h e s a b a i x o . / s c a n f ( "%l f " , &f a r ) ; cel = fahrenheitParaCelsius ( far ); p r i n t f ( "A t e m p e r a t u r a em C e l s i u s e : %f \ n " , c e l ) ; p r i n t f ( " De um t e m p e r a t u r a em C e l s i u s : " ) ; s c a n f ( "%l f " , &c e l ) ; far = celsiusParaFahrenheit ( cel ); p r i n t f ( "A t e m p e r a t u r a em F a h r e n h e i t e : %f \ n " , f a r ) ; / Para n o s e s s e r e t o r n o nao s e r v e p a r a nada , e um t o p i c o a v a n c a d o . / return 0; }

143

23.2

Detalhes de entrada e sada

Alm do sumio das classes, dos indicadores de acesso e dos termos static (pois todas as funes so assim) dos programas em C, uma outra mudana bastante visvel que os comandos para escrever na tela e para leitura do teclado mudam bastante. No lugar do System.out.println aparece o printf e no lugar dos mtodos da classe SavitchIn usamos o scanf. A forma de us-los tambm muda um pouco: 1. printf: imprime na tela. O primeiro parmetro deve ser sempre uma string (texto entre aspas). Diferentemente de Java, no podemos usar a soma para concatenar cadeias. Como apresentar ento variveis no meio de uma string que ser impressa pelo printf? Usamos nesse caso marcadores especiais para "deixar espao"para imprimir o valor da varivel e em seguida passamos estas variveis como parmetro. Vejamos um exemplo.
p r i n t f ( " E s s e e i n t e i r o %d , e s s e d o u b l e %f e o u l t i m o um c h a r %c " , u m I n t e i r o , umDouble , umChar ) ;

Caso desejemos que o printf pule de linha ao nal, devemos adicionar um \n no nal da string do printf:
p r i n t f ( " E s s e e i n t e i r o %d , e s s e d o u b l e %f e o u l t i m o um c h a r %c \ n " , u m I n t e i r o , umDouble , umChar ) ;

Vale a pena consultar um manual de C para ver o printf em ao. Ele um comando mais poderoso do que parece. 2. scanf: para ler valores do teclado usamos o scanf. Ele tambm recebe uma string com marcadores semelhantes do printf (a principal diferena que para ler um double usamos %lf e no %f). Depois aparecem as variveis que devem ser lidas antecedidas de um &. Por exemplo, se queremos ler um inteiro e um double fazemos:
s c a n f ( "%d%l f " , &u m I n t e i r o , &umDouble ) ;

144

CAPTULO 23. O C QUE H EM JAVA

23.3

Declarao de variveis

Em C, comum que a declarao de todas as variveis seja no incio da funo. Isso, porm, no obrigatrio (j foi, no mais). Para declarar vetores em C, a sintaxe mais simples do que em Java. Por exemplo, se queremos que a varivel a seja um vetor de 100 inteiros basta:
int a [100];

A mesma coisa para matrizes:


int a [100][100];

23.4

Parmetros de funes

Assim como em Java, os parmetros que so tipos primitivos modicados dentro da funo no se reetem fora dela. J se alterarmos o contedo de um vetor, esta se reete fora. Uma coisa interessante que possvel pedir ao C que ele permita que a alterao de parmetros que so de tipo primitivo reita-se fora da funo. Para isso deve-se anteceder o parmetro de um asterisco em toda a funo (inclusive na declarao do parmetro). Ao chamar a funo, a varivel que queremos alterar deve estar precedida de um &.
# i n c l u d e < s t d i o . h> / T r o c a d u a s v a r i a v e i s de l u g a r / v o i d swap ( i n t a , i n t b ) { i n t temp ; temp = a ; a = b ; b = temp ; } i n t main ( ) { int c , d ; c = 1; d = 2; swap(&c , &d ) ; p r i n t f ( " c = %d , d = %d " , c , d ) ; }

Outra mudana que os colchetes de parmetros que so vetores e matrizes devem vir aps os seus nomes (e no antes como em Java). Alm disso, se o parmetro uma matriz, voc deve informar na declarao da funo qual o nmero de linhas da matriz. Por exemplo
v o i d umaFuncao ( i n t umVetor [ ] , i n t u m a M a t r i z [ 1 0 0 ] [ ] )

23.5

Um ltimo exemplo

Vejamos um ltimo exemplo de programa em C. Queremos escrever um programa que l uma seqncia de inteiros estritamente positivos terminada por zero e imprime a sua mediana.

23.5. UM LTIMO EXEMPLO

145

# i n c l u d e < s t d i o . h> v o i d s e l e c a o D i r e t a ( i n t numeros [ ] , i n t f i m ) { i n t i , j , minimo , temp ; for ( i = 0 ; i < fim 1 ; i = i + 1) { / I n i c i a l m e n t e o menor e l e m e n t o j a v i s t o e o p r i m e i r o e l e m e n t o . / minimo = i ; for ( j = i + 1 ; j < fim ; j = j + 1) { i f ( numeros [ j ] < numeros [ minimo ] ) minimo = j ; } / C o l o c a o menor e l e m e n t o no i n i c i o do s u b v e t o r a t u a l . / temp = numeros [ i ] ; numeros [ i ] = numeros [ minimo ] ; numeros [ minimo ] = temp ; } } i n t main ( ) { / A c e i t a no maximo 100 numeros no v e t o r . / i n t numeros [ 1 0 0 ] ; i n t i = 1; / Le o v e t o r . / do { i ++; s c a n f ( "%d " , &numeros [ i ] ) ; } w h i l e ( numeros [ i ] > 0 ) ; / Ordena p a r a e n c o n t r a r a mediana . / s e l e c a o D i r e t a ( numeros , i ) ; / Agora f i c o u f a c i l . / p r i n t f ( "A m e d i a n a e : %d \ n " , numeros [ ( i 1 ) / 2 ] ) ; / O t a l return i n u t i l . / return 0; }

Exerccios
1. Escreva um programa em C que l uma sequncia de nmeros do teclado. Para cada valor x lido, o programa deve imprimir o valor de x2 e x!. Se x for igual a 0 (zero), o programa termina. Alm da funo main, seu programa dever conter as funes calculaQuadrado e calculaFatorial. 2. Escreva um programa em C que l um inteiro do teclado e verica se este nmero palndromo. Um

146

CAPTULO 23. O C QUE H EM JAVA nmero palndromo um nmero que lido de trs para frente o mesmo quando lido normalmente. Por exemplo, os nmeros 11111, 64546 e 1001 so palndromos, mas 1232 no .

3. Escreva um programa em C que l um nmero inteiro decimal do teclado e imprime a representao do nmero na base binria. 4. Escreva um programa em C que l um nmero real x do teclado e calcula os valores do seno e coseno de x. Para tal, utilize as sries de Taylor descritas no Captulo 10. 5. Escreva um programa em C que l uma seqencia de nmeros inteiros terminada por 0 (zero) do teclado e imprime estes valores ordenados. Para este exerccio, voc pode utilizar a funo de ordenao fornecida no exemplo da Seo 23.5. 6. Escreva uma funo metodoDaBolha que recebe um vetor e o ordena utilizando o mtodo da bolha explicado no Captulo 17. Em seguida, modique o programa do Exerccio 5 para utilizar esta nova funo de ordenao. Para nalizar, escreva uma funo que testa automaticamente sua funo metodoDaBolha.

Resolues
Exerccio 1
# i n c l u d e < s t d i o . h> i n t c a l c u l a Q u a d r a d o ( i n t numero ) { i n t quadrado ; q u a d r a d o = numero numero ; return quadrado ; } i n t c a l c u l a F a t o r i a l ( i n t numero ) { int f a t o r i a l = 1; w h i l e ( numero > 1 ) { f a t o r i a l = f a t o r i a l numero ; numero = numero 1 ; } return f a t o r i a l ; } i n t main ( ) { i n t numero ; i n t quadrado ; int f a t o r i a l ;

/ v a l o r l i d o do t e c l a d o / armazena o q u a d r a d o de numero / armazena o f a t o r i a l de numero

/ / /

p r i n t f ( " D i g i t e um i n t e i r o nao n u l o , ou 0 ( z e r o ) p a r a s a i r : " ) ; s c a n f ( "%d " , &numero ) ; w h i l e ( numero ! = 0 ) { q u a d r a d o = c a l c u l a Q u a d r a d o ( numero ) ; f a t o r i a l = c a l c u l a F a t o r i a l ( numero ) ; p r i n t f ( "O q u a d r a d o do numero %d e %d \ n " , numero , q u a d r a d o ) ; p r i n t f ( "O f a t o r i a l do numero %d e %d \ n " , numero , f a t o r i a l ) ;

23.5. UM LTIMO EXEMPLO

147

p r i n t f ( " D i g i t e um i n t e i r o nao n u l o , ou 0 ( z e r o ) p a r a s a i r : " ) ; s c a n f ( "%d " , &numero ) ; } return 0; }

Exerccio 2
# i n c l u d e < s t d i o . h> i n t c a l c u l a R e v e r s o ( i n t numero ) { int reverso = 0; w h i l e ( numero ! = 0 ) { / a c r e s c e n t a m a i s um d i g i t o a d i r e i t a de r e v e r s o / r e v e r s o = r e v e r s o 10 + numero % 1 0 ; / remove e s s e d i g i t o de numero / numero = numero / 1 0 ; } return r e v e r s o ; } i n t main ( ) { i n t numero ; int reverso ;

/ numero l i d o do t e c l a d o / / armazena o numero i n v e r t i d o /

p r i n t f ( " D i g i t e um nmero i n t e i r o p o s i t i v o : " ) ; s c a n f ( "%d " , &numero ) ; r e v e r s o = c a l c u l a R e v e r s o ( numero ) ; / Compara o r e v e r s o com o numero o r i g i n a l / i f ( r e v e r s o == numero ) p r i n t f ( "O numero %d e p a l i n d r o m e . \ n " , numero ) ; else p r i n t f ( "O numero %d nao e p a l i n d r o m e . \ n " , numero ) ; return 0; }

Exerccio 3
# i n c l u d e < s t d i o . h> i n t d e c i m a l P a r a B i n a r i o ( i n t numero ) { int digito ; int binario = 0; int potencia = 1; w h i l e ( numero > 0 ) {

148

CAPTULO 23. O C QUE H EM JAVA


/ e x t r a i p r o x i m o d i g i t o b i n a r i o menos s i g n i f i c a t i v o ( m a i s a d i r e i t a ) / d i g i t o = numero % 2 ; / remove e s s e d i g i t o de numero / numero = numero / 2 ; / a d i c i o n a o d i g i t o como o m a i s s i g n i f i c a t i v o a t e o momento / binario = binario + digito potencia ; potencia = potencia 10; } return b i n a r i o ; } i n t main ( ) { i n t numero ; / v a l o r na b a s e d e c i m a l l i d o do t e c l a d o / i n t b i n a r i o ; / v a l o r c o n v e r t i d o para a base b i n a r i a / p r i n t f ( " D i g i t e um numero d e c i m a l i n t e i r o p o s i t i v o : " ) ; s c a n f ( "%d " , &numero ) ; b i n a r i o = d e c i m a l P a r a B i n a r i o ( numero ) ; p r i n t f ( "A r e p r e s t a c a o b i n a r i a do numero d e c i m a l %d e %d \ n " , numero , b i n a r i o ) ; return 0; }

Apndice A

Utilizando o Dr. Java


Neste apndice introduzimos a ferramenta DrJava, um ambiente de desenvolvimento para a linguagem Java. Por ser ele mesmo escrito em Java, pode ser usado em diversos ambientes, como, por exemplo, Linux, Windows e Mac OS. Um ambiente de desenvolvimento (tambm conhecido por IDE, de Integrated Development Environment) um conjunto de ferramentas integradas que auxiliam a construo de programas. O DrJava se encontra em desenvolvimento e, por isso, alguns recursos desejveis ainda no esto disponveis. Entretanto, os recursos mais simples que ele fornece j so apropriados para os objetivos deste livro. Planejamos ento utilizar o DrJava para escrevermos nossos programas Java.

Objetivos
Neste apndice forneceremos uma breve introduo ao uso do DrJava. O contedo limitado e especco, suciente para que voc posteriormente seja capaz de conhecer melhor esta ferramenta por conta prpria. Recomendamos para isso a consulta de manuais e outros documentos, no necessariamente sobre DrJava apenas. As descobertas pelo prprio uso e atravs de dicas de colegas tambm so incentivadas. Neste apndice voc aprender a utilizar o DrJava para: escrever, compilar, manipular e depurar classes/objetos simples; gravar e reutilizar os arquivos que descrevem seus objetos. O DrJava pode ser obtido no endereo http://drjava.org/. Neste stio possvel ainda encontrar documentao detalhada sobre como instalar e utilizar o DrJava.

A.1

Conversor de Temperatura simples

Como exemplo inicial, vamos construir a classe Conversor descrita no Captulo 3. Lembrando, cada objeto dessa classe converte apenas a temperatura de 40 graus Celsius para a correspondente em graus Fahrenheit. Ao receber a mensagem celsiusParaFahrenheit, a classe Conversor devolve a temperatura em Fahrenheit equivalente a 40 graus Celsius. 149

150

APNDICE A. UTILIZANDO O DR. JAVA

Editando o cdigo-fonte num arquivo


Vejamos o que o DrJava nos oferece para criarmos a classe. Ao iniciar o ambiente DrJava, abre-se uma janela parecida com a seguinte.

O painel de denies, indicado na gura acima, um editor de textos. nele que digitaremos o cdigo Java que dene a classe Conversor. Ele se parece muito com um editor de textos comum, exceto que possui alguns recursos para facilitar a digitao de cdigo. Em particular, o comportamento das teclas <Enter> e <Tab> favorece a indentao do cdigo. Outro recurso til a colorao e o destaque do texto. Precisamos criar um arquivo novo para conter o cdigo da nossa classe. Para isso, bastaria escolher a opo New do menu File. Porm, quando abrimos o DrJava, um novo arquivo sem nome j foi criado, ento podemos us-lo nesse momento (em vez de criar um novo). Sendo assim, digite o seguinte cdigo no painel de denies.
c l a s s Conversor { int celsiusParaFahrenheit () { r e t u r n 9 40 / 5 + 3 2 ; } }

Ao digitar, note os recursos mencionados que ajudam a programao (principalmente o comportamento das teclas <Enter> e <Tab>).

Gravando e reutilizando o arquivo


Vamos agora gravar o arquivo no disco. Escolha o menu File (clicando com o mouse ou usando as teclas de atalho, que nesse caso a combinao <Alt>+<F>) e escolha o tem Save. Como o arquivo ainda no tem

A.1. CONVERSOR DE TEMPERATURA SIMPLES

151

nome, estaremos na verdade acionando a opo Save as.... Por isso, surgir um dilogo para denirmos a localizao e o nome do arquivo, como mostra a seguinte gura.

Podemos determinar a localizao, manipulando a combo box com rtulo Save In: (no topo do dilogo) e escolhendo um diretrio na caixa abaixo dela, ou podemos deixar a localizao como est. Desse modo, provavelmente o arquivo ser gravado no diretrio de onde o DrJava foi chamado. Tambm precisamos escolher o nome do arquivo. Em algumas ocasies, este deve ser obrigatoriamente idntico ao nome da classe, mais o suxo .java. No o nosso caso, mas mesmo assim vamos chamar o arquivo de Conversor.java. Como j digitamos o cdigo da classe, o DrJava preencheu o nome do arquivo no input eld de rtulo File Name: com o nome da classe. Note tambm que ele no acrescentou o suxo .java no nome, o que ser feito implicitamente quando nalizarmos (mas no h problema em digitar o suxo mesmo assim). Para conrmar a gravao, basta clicar no boto Save. As modicaes futuras podem ser gravadas com o comando Save, sem precisar escolher o nome do arquivo novamente. Com os arquivos das classes gravados em disco, podemos querer reutiliz-los no futuro. No DrJava, basta escolhermos a opo Open do menu File e um dilogo permitir que voc escolha o arquivo que deseja abrir novamente ( semelhante ao processo do Save as...).

Compilando a classe
Acabamos de denir a nossa classe, precisamos agora compilar para que possamos us-la. No menu Tools, temos duas opes para fazer isso, Compile All Documents e Compile Current Document. Como s temos um documento aberto (Conversor.java), qualquer uma das opes serve. Escolha ento Compile Current Document. Com isso compilaremos a nossa classe. Note que, no painel inferior da janela, a guia Compiler Output se abre mostrando algumas mensagens. Se tudo der certo, a nossa janela se parecer com a seguinte.

Usando a classe
Podemos nalmente usar a guia Interactions, que chamaremos de janela do interpretador, para criar e usar objetos da classe Conversor. Essa janela recebe comandos num prompt e a sintaxe desses comandos muito parecida com a da linguagem Java. Clique ento em Interactions e digite o seguinte.
C o n v e r s o r conv = new C o n v e r s o r ( ) ; conv . c e l s i u s P a r a F a h r e n h e i t ( )

152

APNDICE A. UTILIZANDO O DR. JAVA

A ausncia de ; no nal da linha do comando faz com que o interpretador imprima o valor devolvido pelo comando. A janela do interpretador dever se parecer com a gura abaixo.

A.2

Tratando erros

Utilizaremos agora a classe Conversor4 descrita no Captulo 3 para mostrarmos alguns outros recursos do DrJava. Para quem no lembra, objetos dessa classe convertem temperaturas entre graus Celsius e Fahrenheit fornecendo os seguintes mtodos. * double celsiusParaFahrenheit (double c): recebe uma temperatura c em graus celsius e devolve a temperatura correspondente em graus fahrenheit. * double fahrenheitParaCelsius (double f): recebe uma temperatura f em graus fahrenheit e devolve a temperatura correspondente em graus celsius. Neste apndice, porm, usaremos um cdigo um pouco diferente em relao ao do Captulo 3.

Erros no cdigo
Feche o arquivo Conversor.java usando a opo Close do menu File e crie um novo arquivo (na verdade, como havia apenas um arquivo aberto, um novo criado automaticamente). Digite nesse arquivo o cdigo abaixo (h erros intencionais nele). Voc pode tambm usar o recurso de copiar e colar (copy and paste).

A.2. TRATANDO ERROS

153

c l a s s Conversor4 { double c e l s i u s P a r a F a h r e n h e i t ( double c ) { double f = 9 . 0 c / 5 . 0 + 32.0 return f ; } double f a h r e n h e i t P a r a C e l s i u s ( double f ) { double c = 9 . 0 ( f 3 2 . 0 ) / 9 , 0 ; return c ; } }

Grave o arquivo e compile. Como o cdigo contm erros, o compilador no ter sucesso e imprimir algumas mensagens. Algo como mostra a gura abaixo.

O primeiro erro pode ser eliminado acrescentando-se um ; no nal da linha 5. Veja que o prprio compilador sugere isso. J a descrio do segundo erro pode ser um pouco confusa. importante saber que o compilador capaz de encontrar erros no cdigo, mas nem sempre pode determinar a causa exata. Nesses casos, as mensagens de erro apenas do pistas para descobrirmos o que est errado (algumas vezes pistas falsas). O segundo erro uma vrgula no lugar de um ponto, no nal da linha 10. H outros tipos de erro os quais o compilador no tem condies de detectar. Um exemplo o erro na frmula de converso da linha 10. H um 9.0 onde deveria estar um 5.0. No Captulo 4 apresentamos uma maneira de detectarmos tais erros atravs de testes. Mas depois de detectarmos, precisamos descobrir a causa deles. Veremos a seguir uma ferramenta til para essa tarefa. Mas antes corrija os erros e compile.

154

APNDICE A. UTILIZANDO O DR. JAVA

Depurador
Depurador (debugger) uma ferramenta que nos ajuda a corrigir erros (bugs) de programas. O depurador do DrJava oferece apenas recursos bsicos: pontos de parada (breakpoints), execuo passo a passo (step) e inspeo simples de variveis (watch). Mesmo assim, a classe Conversor4 no complexa o suciente para justicar a aplicao do depurador, vamos utiliz-la apenas para demonstrar rapidamente cada um desses recursos. Para ativar o depurador, escolha a opo Debug Mode do menu Debugger. Ao fazer isso, o painel de depurao exibido na janela principal.

Comearemos selecionando um ponto de parada no cdigo do Conversor4. Isso feito no painel de denies, posicionando o cursor na linha desejada e escolhendo a opo Toggle Breakpoint on Current Line do menu Debugger. O ponto de parada faz com que a execuo do programa seja temporariamente interrompida exatamente antes da linha ser executada. A partir da, para continuar a execuo, deve-se usar os comandos de "passo a passo"(step into, step over, step out, resume). O que cada comando faz pode ser encontrado na seo Documentation da pgina do DrJava <http://drjava.sourceforge.net> Posicione ento o cursor do painel de denies na linha 10 do Conversor4 e insira um ponto de parada (a linha car com um destaque vermelho). Para que o ponto de parada seja usado, temos que fazer com que o mtodo seja executado. Para isso digite o seguinte na janela do interpretador.
C o n v e r s o r 4 c4 = new C o n v e r s o r 4 ( ) ; c4 . f a h r e n h e i t P a r a C e l s i u s ( 4 2 )

A execuo do mtodo ser interrompida antes da linha 10 ser executada. O destaque azul da linha indica isso. Para continuar a execuo passo a passo (linha a linha), execute o comando step over algumas vezes (pressionando a tecla <F11>). Dessa forma, possvel constatar quais trechos de cdigo so usados numa execuo em particular.

A.2. TRATANDO ERROS

155

Um outro recurso bastante til, que deve ser usado em conjunto com esses que acabamos ver, a inspeo de valores de variveis (watch). Esse recurso nos informa o valor de certas variveis durante a execuo passo a passo. Para isso, necessrio preencher a coluna Name da tabela da guia Watches com os nomes das variveis que se deseja inspecionar (uma varivel em cada linha da tabela). Basta clicar numa clula da coluna Name, digitar o nome da varivel e pressionar <Enter>. Faa este procedimento para as variveis c e f. Teremos algo como a prxima gura.

Repita a execuo passo a passo descrita anteriormente e observe o que ocorre com a tabela. Dica: o interpretador armazena os ltimos comandos digitados na janela. Para acess-los, pressione as setas para cima e para baixo do teclado. Esse recurso se chama History e possui algumas opes teis no menu Tools.

156

APNDICE A. UTILIZANDO O DR. JAVA

Apndice B

Desenvolvimento Dirigido por Testes


Neste apndice, veremos um exemplo de como podemos desenvolver um programa ao mesmo tempo em que desenvolvemos seus testes. Ou melhor, a idia at um pouco mais radical, criar os testes e ir adaptando o programa at que o mesmo satisfaa a todos os testes criados. Esta abordagem chamada de Desenvolvimento Dirigido por Testes (Test-Driven Development) e a prtica de escrever os testes antes do cdigo a ser testado chamada de Programao com Testes a Priori (Test-First Programming). Para isto, devemos nos guiar pelo seguinte ciclo, de forma incremental: 1. Escreva teste(s); 2. Escreva cdigo para que os testes funcionem; 3. Observe o cdigo buscando formas de simplic-lo 1 4. Enquanto o programa no acabou, volte ao primeiro passo. O exemplo escolhido 2 o de um conversor de nmeros inteiros para algarismos romanos.

B.1

O Exemplo

Vamos comear do bsico. Inicialmente, queremos criar um teste que, nada mais natural, para o nmero 0 tenhamos como resultado um String vazio. Para isto usaremos uma palavra chave que existe a partir de Java 1.4: assert. Em linhas gerais, assert recebe um nico parmetro booleano e, se ele for verdadeiro, nada acontece; no entanto, se ele for falso, o assert gera uma mensagem de erro e interrompe a execuo do programa. interessante notar que necessrio ativar as vericaes do assert usando o parmetro -ea da mquina virtual Java, ou seja o seguinte programa deve ser executado com: java -ea TesteConversorNmerosRomanos. Usando o assert, o teste ca:
c l a s s TesteConversorNmerosRomanos { verdade existe toda uma teoria para isto, que se chama refatorao. idia original para este exemplo foi encontrada em http://www.differentpla.net/node/58, mas o exemplo a seguir foi criado de forma totalmente independente.
2A 1 Na

157

158

APNDICE B. DESENVOLVIMENTO DIRIGIDO POR TESTES


public void t e s t e s ( ) { C o n v e r s o r c = new C o n v e r s o r ( ) ; System . o u t . p r i n t l n ( " I n c i o d o s T e s t e s " ) ; a s s e r t ( c . c o n v e r t e ( 0 ) . compareTo ( " " ) = = 0 ) ; System . o u t . p r i n t l n ( " Fim d o s T e s t e s " ) ; } p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { T e s t e C o n v e r s o r N m e r o s R o m a n o s t = new T e s t e C o n v e r s o r N m e r o s R o m a n o s ( ) ; t . testes (); }

Como seria de se esperar, o trecho isolado acima nem mesmo compila, pois a classe Conversor ainda no existe. Mas, podemos resolver isto criando a seguinte classe:
c l a s s Conversor { public String converte ( int x ) { return " " ; } }

Agora, no s o programa compila, como executado sem erros. Logo, podemos aprimorar o nosso teste com a vericao da converso do inteiro 1.
c l a s s TesteConversorNmerosRomanos { public void t e s t e s ( ) { C o n v e r s o r c = new C o n v e r s o r ( ) ; System . assert assert System . out . p r i n t l n ( " I n c i o dos T e s t e s " ) ; ( c . c o n v e r t e ( 0 ) . compareTo ( " " ) = = 0 ) ; ( c . c o n v e r t e ( 1 ) . compareTo ( " I " ) = = 0 ) ; o u t . p r i n t l n ( " Fim d o s T e s t e s " ) ;

} p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { T e s t e C o n v e r s o r N m e r o s R o m a n o s t = new T e s t e C o n v e r s o r N m e r o s R o m a n o s ( ) ; t . testes (); } }

Agora, ao executar este teste, recebemos a seguinte mensagem de erro:


AssertionError : a t TesteConversorNmerosRomanos . t e s t e s ( TesteConversorNmerosRomanos . j a v a : 9 ) a t T e s t e C o n v e r s o r N m e r o s R o m a n o s . main ( T e s t e C o n v e r s o r N m e r o s R o m a n o s . j a v a : 1 5 ) a t s u n . r e f l e c t . N a t i v e M e t h o d A c c e s s o r I m p l . i n v o k e 0 ( N a t i v e Method ) a t sun . r e f l e c t . NativeMethodAccessorImpl . invoke ( NativeMethodAccessorImpl . j a v a : 3 9 ) a t sun . r e f l e c t . DelegatingMethodAccessorImpl . invoke ( DelegatingMethodAccessorImpl . j a v a : 2 5 )

B.1. O EXEMPLO
a t j a v a . l a n g . r e f l e c t . Method . i n v o k e ( Method . j a v a : 5 8 5 )

159

Esta mensagem indica que a segunda vericao falhou. O nosso prximo passo generalizar o programa para que ele funcione para o teste atual:
c l a s s Conversor { public String converte ( int x ) { i f ( x == 0 ) return " " ; return " I " ; } }

Desta forma, o Conversor voltou a funcionar. Est na hora de aumentarmos a nossa classe de testes com mais uma vericao:
a s s e r t ( c . c o n v e r t e ( 2 ) . compareTo ( " I I " ) = = 0 ) ;

Como novamente o Conversor falhou, vamos corrig-lo:


c l a s s Conversor { public String converte ( int x ) { i f ( x == 0 ) return " " ; i f ( x == 1 ) return " I " ; return " I I " ; } }

Mas, quando acrescentarmos o teste para o nmero 3, o nosso conversor vai falhar novamente. Continuando o desenvolvimento teremos:
c l a s s Conversor { public String converte ( int x ) { i f ( x == 0 ) return " " ; i f ( x == 1 ) return " I " ; i f ( x == 2 ) return " I I " ; return " I I I " ; } }

Olhando o cdigo acima, vemos um padro de repetio no uso de ifs e sempre que aparecem estas repeties interessante encontrar formas de reduz-las. Podemos simplicar o exemplo acima usando um lao simples:

160

APNDICE B. DESENVOLVIMENTO DIRIGIDO POR TESTES

c l a s s Conversor { public String converte ( int x ) { String s = "" ; while ( x > 0) { x; s = s + "I"; } return s ; } }

O novo cdigo continua passando pelo teste, mas ainda temos que ver o funcionamento para mais nmeros, no caso o 4 e o 5.
c l a s s TesteConversorNmerosRomanos { public void t e s t e s ( ) { C o n v e r s o r c = new C o n v e r s o r ( ) ; System . assert assert assert assert assert assert System . out . p r i n t l n ( " I n c i o dos T e s t e s " ) ; ( c . c o n v e r t e ( 0 ) . compareTo ( " " ) = = 0 ) ; ( c . c o n v e r t e ( 1 ) . compareTo ( " I " ) = = 0 ) ; ( c . c o n v e r t e ( 2 ) . compareTo ( " I I " ) = = 0 ) ; ( c . c o n v e r t e ( 3 ) . compareTo ( " I I I " ) = = 0 ) ; ( c . c o n v e r t e ( 4 ) . compareTo ( " IV " ) = = 0 ) ; ( c . c o n v e r t e ( 5 ) . compareTo ( "V" ) = = 0 ) ; o u t . p r i n t l n ( " Fim d o s T e s t e s " ) ;

} p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { T e s t e C o n v e r s o r N m e r o s R o m a n o s t = new T e s t e C o n v e r s o r N m e r o s R o m a n o s ( ) ; t . testes (); } } c l a s s Conversor { public String converte ( int x ) { String s = "" ; i f ( x == 4 ) r e t u r n " IV " ; i f ( x == 5 ) r e t u r n "V" ; while ( x > 0) { x; s = s + "I";

B.1. O EXEMPLO
} return s ; } }

161

O nosso conversor j funciona para os inteiros de 0 a 5. Pensando um pouco, podemos ver que os nmeros 6, 7 e 8 tem construo anloga ao 1, 2 e 3, e o while no nal pode nos ajudar. Logo, para a seguinte srie de asserts:
assert assert assert assert assert assert assert assert assert (c. (c. (c. (c. (c. (c. (c. (c. (c. converte converte converte converte converte converte converte converte converte ( 0 ) . compareTo ( " " ) = = 0 ) ; ( 1 ) . compareTo ( " I " ) = = 0 ) ; ( 2 ) . compareTo ( " I I " ) = = 0 ) ; ( 3 ) . compareTo ( " I I I " ) = = 0 ) ; ( 4 ) . compareTo ( " IV " ) = = 0 ) ; ( 5 ) . compareTo ( "V" ) = = 0 ) ; ( 6 ) . compareTo ( " VI " ) = = 0 ) ; ( 7 ) . compareTo ( " V I I " ) = = 0 ) ; ( 8 ) . compareTo ( " V I I I " ) = = 0 ) ;

O conversor seguinte funciona:


c l a s s Conversor { public String converte ( int x ) { String s = "" ; i f ( x == 4 ) r e t u r n " IV " ; i f ( x >= 5 ) { s = s + "V" ; x = x 5; } while ( x > 0) { x; s = s + "I"; } return s ; } }

J que o programa funciona vamos aumentar os testes para os nmeros 9 e 10. Para sanar a nova falha, vamos adicionar dois novos ifs:
c l a s s Conversor { public String converte ( int x ) { String s = "" ; i f ( x == 4 ) r e t u r n " IV " ;

162
i f ( x == 9 ) r e t u r n " IX " ; i f ( x == 1 0 ) r e t u r n "X" ; i f ( x >= 5 ) { s = s + "V" ; x = x 5; } while ( x > 0) { x; s = s + "I"; } return s ; } }

APNDICE B. DESENVOLVIMENTO DIRIGIDO POR TESTES

Novamente, aparece uma padro de repetio, ou duplicao, para simplicar o cdigo, apenas observando o padro IV e IX:
c l a s s Conversor { public String converte ( int x ) { String s = "" ; i f ( ( x == 4 ) | | ( x == 9 ) ) { s = s + "I"; x ++; } i f ( x == 1 0 ) r e t u r n s + "X" ; i f ( x >= 5 ) { s = s + "V" ; x = x 5; } while ( x > 0) { x; s = s + "I"; } return s ; } }

Alm do que bem fcil corrigir o cdigo para que o mesmo funcione para os nmeros 11, 12 e 13, basta trocar o if (x == 10) por:
i f ( x >= 1 0 ) { s = s + "X" ;

B.1. O EXEMPLO
x = x 10; }

163

Vamos agora, eliminar o cdigo duplicado criando um novo mtodo aux. Como este mtodo modica tanto a String como o valor de x, foi necessrio usar um objeto do tipo StringBuffer
c l a s s Conversor { p r i v a t e i n t aux ( i n t x , i n t v a l , S t r i n g B u f f e r s , char ch ) { i f ( x >= v a l ) { s . a p p e n d ( ch ) ; x = x val ; } return x ; } public String converte ( int x ) { S t r i n g B u f f e r s = new S t r i n g B u f f e r ( " " ) ; i f ( ( x == 4 ) | | ( x == 9 ) ) { s . append ( " I " ) ; x ++; } x = aux ( x , 1 0 , s , X ) ; x = aux ( x , 5 , s , V ) ; while ( x > 0) { x; s . append ( " I " ) ; } return s . t o S t r i n g ( ) ; } }

Continuando com os testes, para os nmeros 14 e 15, podemos vericar que basta repetir um trecho de cdigo para que o programa funcione, logo vamos criar mais um mtodo:
c l a s s Conversor { p r i v a t e i n t aux ( i n t x , i n t v a l , S t r i n g B u f f e r s , char ch ) { i f ( x >= v a l ) { s . a p p e n d ( ch ) ; x = x val ; } return x ; } p r i v a t e i n t aux2 ( i n t x , S t r i n g B u f f e r s )

164
{ s . append ( " I " ) ; return x + 1; }

APNDICE B. DESENVOLVIMENTO DIRIGIDO POR TESTES

public String converte ( int x ) { S t r i n g B u f f e r s = new S t r i n g B u f f e r ( " " ) ; i f ( ( x == 4 ) | | ( x == 9 ) ) { x = aux2 ( x , s ) ; } x = aux ( x , 1 0 , s , X ) ; i f ( ( x == 4 ) | | ( x == 9 ) ) { x = aux2 ( x , s ) ; } x = aux ( x , 5 , s , V ) ; while ( x > 0) { x; s . append ( " I " ) ; } return s . t o S t r i n g ( ) ; } }

interessante notar que agora podemos adicionar os nmeros at 18 que o teste funciona. Mas, para o 19 o teste falha novamente. Com um pouco de observao podemos ver que com pequenas alteraes tudo volta a funcionar, basta colocar uma chamada adicional ao mtodo aux. Mas, lembrando que teremos nmeros como o 30, o melhor seria adicionar um outro lao ao programa:
c l a s s Conversor { p r i v a t e i n t aux ( i n t x , i n t v a l , S t r i n g B u f f e r s , char ch ) { i f ( x >= v a l ) { s . a p p e n d ( ch ) ; x = x val ; } return x ; } p r i v a t e i n t aux2 ( i n t x , S t r i n g B u f f e r s ) { s . append ( " I " ) ; return x + 1; } public String converte ( int x ) { S t r i n g B u f f e r s = new S t r i n g B u f f e r ( " " ) ;

B.1. O EXEMPLO

165

w h i l e ( x >= 9 ) { i f ( x == 9 ) { x = aux2 ( x , s ) ; } x = aux ( x , 1 0 , s , X ) ; } i f ( x == 4 ) { x = aux2 ( x , s ) ; } x = aux ( x , 5 , s , V ) ; while ( x > 0) { x; s . append ( " I " ) ; } return s . t o S t r i n g ( ) ; } }

Este novo conversor funciona at o nmero 39. Para que ele funcione para o nmero 40 temos que entrar com uma nova letra, o L que corresponde ao 50. Agora que j conhecemos melhor o mecanismo de converso de nmeros, podemos escolher alguns testes para adicionar, ao invs de colocar testes para todos os nmeros. Para a nova srie de testes:
... assert assert assert assert assert assert assert assert assert assert (c. (c. (c. (c. (c. (c. (c. (c. (c. (c. converte converte converte converte converte converte converte converte converte converte ( 1 7 ) . compareTo ( " XVII " ) = = 0 ) ; ( 1 8 ) . compareTo ( " XVIII " ) = = 0 ) ; ( 1 9 ) . compareTo ( " XIX " ) = = 0 ) ; ( 2 0 ) . compareTo ( "XX" ) = = 0 ) ; ( 2 3 ) . compareTo ( " XXIII " ) = = 0 ) ; ( 3 4 ) . compareTo ( "XXXIV" ) = = 0 ) ; ( 3 9 ) . compareTo ( "XXXIX" ) = = 0 ) ; ( 4 6 ) . compareTo ( "XLVI" ) = = 0 ) ; ( 5 9 ) . compareTo ( " LIX " ) = = 0 ) ; ( 6 3 ) . compareTo ( " L X I I I " ) = = 0 ) ;

O seguinte conversor apenas adiciona a letra L:


c l a s s Conversor { p r i v a t e i n t aux ( i n t x , i n t v a l , S t r i n g B u f f e r s , char ch ) { i f ( x >= v a l ) { s . a p p e n d ( ch ) ; x = x val ; } return x ; }

166

APNDICE B. DESENVOLVIMENTO DIRIGIDO POR TESTES


p r i v a t e i n t aux2 ( i n t x , S t r i n g B u f f e r s ) { s . append ( " I " ) ; return x + 1; } public String converte ( int x ) { S t r i n g B u f f e r s = new S t r i n g B u f f e r ( " " ) ;

i f ( x >= 4 0 ) { i f ( x < 50) { s . a p p e n d ( "X" ) ; x = x + 10; } s . a p p e n d ( "L" ) ; x = x 50; } w h i l e ( x >= 9 ) { i f ( x == 9 ) { x = aux2 ( x , s ) ; } x = aux ( x , 1 0 , s , X ) ; } i f ( x == 4 ) { x = aux2 ( x , s ) ; } x = aux ( x , 5 , s , V ) ; while ( x > 0) { x; s . append ( " I " ) ; } return s . t o S t r i n g ( ) ; } }

Observe que colocar o X antes do L similar a colocar o I antes do X, ou do V, logo podemos mudar o nome do mtodo aux2 para precede e us-lo tambm neste caso. Assim como o mtodo aux pode ser chamado de colocaLetra e usado em outras partes:
c l a s s Conversor { p r i v a t e i n t c o l o c a L e t r a ( i n t x , i n t v a l , S t r i n g B u f f e r s , char ch ) { i f ( x >= v a l ) { s . a p p e n d ( ch ) ;

B.1. O EXEMPLO
x = x val ; } return x ; } p r i v a t e i n t p r e c e d e ( i n t x , i n t v a l , S t r i n g B u f f e r s , char ch ) { s . a p p e n d ( ch ) ; return x + val ; } public String converte ( int x ) { S t r i n g B u f f e r s = new S t r i n g B u f f e r ( " " ) ;

167

i f ( x >= 4 0 ) { i f ( x < 50) { x = p r e c e d e ( x , 1 0 , s , X ) ; } x = c o l o c a L e t r a ( x , 5 0 , s , L ) ; } w h i l e ( x >= 9 ) { i f ( x == 9 ) { x = precede (x , 1 , s , I ) ; } x = c o l o c a L e t r a ( x , 1 0 , s , X ) ; } i f ( x == 4 ) { x = precede (x , 1 , s , I ) ; } x = c o l o c a L e t r a ( x , 5 , s , V ) ; while ( x > 0) { x = colocaLetra (x , 1 , s , I ); } return s . t o S t r i n g ( ) ; } }

Observando o cdigo acima vemos que existe uma correspondncia entre os valores e os nmeros romanos I, V, X e L nas chamadas dos mtodos, logo, podemos criar um mtodo adicional que faz esta correspondncia, simplicando as chamadas.
c l a s s Conversor { p r i v a t e char c o r r e s p o n d e ( i n t i ) { i f ( i == 1 ) return I ;

168
e l s e i f ( i == 5 ) r e t u r n V ; e l s e i f ( i == 1 0 ) r e t u r n X ; else r e t u r n L ; }

APNDICE B. DESENVOLVIMENTO DIRIGIDO POR TESTES

private i n t c o l o c a L e t r a ( i n t x , i n t val , S t r i n g B u f f e r s ) { i f ( x >= v a l ) { s . append ( c o r r e s p o n d e ( v a l ) ) ; x = x val ; } return x ; } private i n t precede ( i n t x , i n t val , S t r i n g B u f f e r s ) { s . append ( c o r r e s p o n d e ( v a l ) ) ; return x + val ; } public String converte ( int x ) { S t r i n g B u f f e r s = new S t r i n g B u f f e r ( " " ) ; i f ( x >= 4 0 ) { i f ( x < 50) { x = precede ( x , 10 , s ) ; } x = c o l o c a L e t r a ( x , 50 , s ) ; } w h i l e ( x >= 9 ) { i f ( x == 9 ) { x = precede (x , 1 , s ) ; } x = c o l o c a L e t r a ( x , 10 , s ) ; } i f ( x == 4 ) { x = precede (x , 1 , s ) ; } x = colocaLetra (x , 5 , s ); while ( x > 0) { x = colocaLetra (x , 1 , s ); } return s . t o S t r i n g ( ) ; }

B.1. O EXEMPLO
}

169

Olhando o cdigo acima parece existir um padro entre as chamadas aos mtodos precede e colocaLetra, mas como ainda no est claro o que pode ser feito, vamos criar mais testes para que o conversor funcione com nmeros maiores do que 89.
... assert assert assert assert assert assert (c. (c. (c. (c. (c. (c. converte converte converte converte converte converte ( 9 0 ) . compareTo ( "XC" ) = = 0 ) ; ( 9 4 ) . compareTo ( "XCIV" ) = = 0 ) ; ( 9 9 ) . compareTo ( "XCIX" ) = = 0 ) ; ( 1 0 3 ) . compareTo ( " C I I I " ) = = 0 ) ; ( 1 4 9 ) . compareTo ( "CXLIX" ) = = 0 ) ; ( 3 4 9 ) . compareTo ( "CCCXLIX" ) = = 0 ) ;

Para isto temos que alterar os mtodos corresponde, adicionando a nova letra (C), e o mtodo converte, transcrito abaixo:
public String converte ( int x ) { S t r i n g B u f f e r s = new S t r i n g B u f f e r ( " " ) ; w h i l e ( x >= 9 0 ) { i f ( x < 100) { x = precede ( x , 10 , s ) ; } x = c o l o c a L e t r a ( x , 100 , s ) ; } i f ( x >= 4 0 ) { i f ( x < 50) { x = precede ( x , 10 , s ) ; } x = c o l o c a L e t r a ( x , 50 , s ) ; } w h i l e ( x >= 9 ) { i f ( x == 9 ) { x = precede (x , 1 , s ) ; } x = c o l o c a L e t r a ( x , 10 , s ) ; } i f ( x == 4 ) { x = precede (x , 1 , s ) ; } x = colocaLetra (x , 5 , s ); while ( x > 0) { x = colocaLetra (x , 1 , s ); }

170
return s . t o S t r i n g ( ) ; } }

APNDICE B. DESENVOLVIMENTO DIRIGIDO POR TESTES

Neste momento, o padro de duplicao do cdigo ca mais visvel, e podemos buscar uma forma de eliminar as repeties. Logo, foram feitas diversas modicaes no cdigo at chegarmos a verso seguinte (como tnhamos os testes, a cada modicao, o correto funcionamento da nova verso pode ser vericado).
c l a s s Conversor { p r i v a t e char c o r r e s p o n d e ( i n t i ) { i f ( i == 1 ) return I ; e l s e i f ( i == 5 ) r e t u r n V ; e l s e i f ( i == 1 0 ) r e t u r n X ; e l s e i f ( i == 5 0 ) r e t u r n L ; else r e t u r n C ; } private i n t c o l o c a L e t r a ( i n t x , i n t val , S t r i n g B u f f e r s ) { s . append ( c o r r e s p o n d e ( v a l ) ) ; x = x val ; return x ; } private i n t precede ( i n t x , i n t val , S t r i n g B u f f e r s ) { s . append ( c o r r e s p o n d e ( v a l ) ) ; return x + val ; } public String converte ( int x ) { S t r i n g B u f f e r s = new S t r i n g B u f f e r ( " " ) ; w h i l e ( x >= 9 0 ) { i f ( x < 100) { x = precede ( x , 10 , s ) ; } x = c o l o c a L e t r a ( x , 100 , s ) ; } w h i l e ( x >= 4 0 ) { i f ( x < 50) { x = precede ( x , 10 , s ) ; }

B.1. O EXEMPLO
x = c o l o c a L e t r a ( x , 50 , s ) ; } w h i l e ( x >= 9 ) { i f ( x < 10) { x = precede (x , 1 , s ) ; } x = c o l o c a L e t r a ( x , 10 , s ) ; } w h i l e ( x >= 4 ) { i f ( x < 5) { x = precede (x , 1 , s ) ; } x = colocaLetra (x , 5 , s ); } while ( x > 0) { x = colocaLetra (x , 1 , s ); } return s . t o S t r i n g ( ) ; } }

171

Neste ponto, o padro cou bem claro ( interessante notar que mesmo que alguns ifs tenham sido trocados por whiles devido as caractersticas do programa o lao s executado no mximo uma vez). Vale ressaltar mais uma vez que a garantia que o programa acima est correto vem da nossa classe de testes. Com um pouco de pacincia, d para trocar os whiles acima por apenas 3, temos abaixo o programa mais limpo:
c l a s s Conversor { p r i v a t e i n t v [ ] = {100 , 50 , 10 , 5 , 1}; p r i v a t e char c o r r e s p [ ] = { C , L , X , V , I } ; private int colocaLetra ( int x , int i , StringBuffer s ) { s . append ( c o r r e s p [ i ] ) ; x = x v[ i ]; return x ; } private int precede ( int x , int i , StringBuffer s ) { s . append ( c o r r e s p [ i ] ) ; return x + v [ i ] ; } public String converte ( int x ) { S t r i n g B u f f e r s = new S t r i n g B u f f e r ( " " ) ; int i = 0;

172

APNDICE B. DESENVOLVIMENTO DIRIGIDO POR TESTES

while ( i < v . l e n g t h 1) { w h i l e ( x >= v [ i ] v [ i + 2 ] ) { if (x < v[ i ]) { x = p r e c e d e ( x , i +2 , s ) ; } x = colocaLetra (x , i , s ); } w h i l e ( x >= v [ i + 1 ] v [ i + 2 ] ) { i f ( x < v [ i +1]) { x = p r e c e d e ( x , i +2 , s ) ; } x = c o l o c a L e t r a ( x , i +1 , s ) ; } i = i + 2; } while ( x > 0) { x = colocaLetra (x , v . length 1 , s ); } return s . t o S t r i n g ( ) ; } }

interessante notar que o programa acima ainda pode ser simplicado, mas j chegamos a um conversor que funciona at o nmero 399. Os passos apresentados, foram na medida do possvel, muito prximos a um desenvolvimento real. claro que durante o desenvolvimento do conversor ocorreram diversos erros, inclusive de compilao, mas os mesmos foram omitidos pois no apresentam interesse didtico.

Exerccios
1. Verique, atravs da metodologia testes primeiro, que o programa acima exvel, adicionando os nmeros romanos D e M. 2. Usando a mesma metodologia de testes primeiro, crie um programa que converte nmeros romanos em nmeros decimais.

Bibliograa
Philippe Breton, Histria da Informtica, Editora Unesp, 1987 Para aqueles que desejam se aprofundar na histria da computao, este livro fornece uma viso tcnica, econmica e social sobre a evoluo do uso dos computadores em nossa sociedade. Por ter sido escrito no nal da dcada de 1980, no cobre os ltimos avanos da informtica, como a linguagem Java e a Web. Samuel N. Kamin, M. Dennis Mickunas e Edward M. Reingold, An Introduction to Computer Science Using Java, McGraw-Hill, 1998 Talvez o primeiro livro a propor o uso de Java para um curso introdutrio Cincia da Computao. Escrito por alguns dos principais especialistas em linguagens de programao da Universidade de Illinois em Urbana-Champaign. Walter Savitch, Java, An Introduction to Computer Science & Programming, second edition, Prentice Hall, 2001 Um bom livro de introduo computao escrito pelo prolco Prof. Savitch da Universidade da California em San Diego. Daqui foi tirada a classe para entrada de dados sugerida neste livro para verses de Java anteriores 1.5. Bruce Ecklel, Thinking in Java, fourth edition, Prentice Hall, 2006. Excelente livro para aqueles que desejam se aprofundar na linguagem Java. Sua principal vantagem que ele explica com bastante detalhe o funcionamento da linguagem. Alm disso, o livro fornece diversas dicas sobre estilos de programao. O texto completo da terceira edio do livro encontra-se disponvel para ser baixado livremente em http://mindview.net/Books. Harvey Deitel e Paul Deitel, Java: Como Programar, sexta edio, Prentice Hall, 2005. Livro em portugus para aqueles que desejam obter mais detalhes sobre como programar em Java. Possui uma abordagem bastante acessvel e baseada em exemplos, alm de cobrir uma grande quantidade de tpicos. Jaime Nio e Frederick A. Hosch A Introduction to Programming and Object Oriented Design Um bom livro de introduo Cincia da Computao. Possui algumas semelhanas com nosso livro como o enfoque em orientao a objetos e nfase em testes e mesmo o uso do DrJava e seu painel interativo. O livro possui vrios exemplos interessantes e bastante completo, usando suas 900 pginas 173

174

BIBLIOGRAFIA para cobrir com profundidade vrios tpicos que apenas arranhamos ou nem citamos, como por exemplo herana e polimorsmo, excees, interfaces grcas e iteradores. The Java Tutorial, disponvel online em http://java.sun.com/docs/books/tutorial/ Referncia online que introduz os principais conceitos de Java. Apesar de ter um contedo bastante bsico, este livro possui a vantagem de poder ser facilmente acessado atravs da internet.

Você também pode gostar