299
FJ-11 Java e Orientação a Objetos

FJ-11 - sergiofanap | Disciplinas Fanap 1ºSEM · Conheça alguns de nossos cursos FJ-11: Java e Orientação a objetos FJ-26: Laboratório Web com JSF2 e CDI FJ-16: Laboratório

  • Upload
    lecong

  • View
    214

  • Download
    1

Embed Size (px)

Citation preview

FJ-11Java e Orientação a Objetos

Conheça mais da Caelum.

Cursos Onlinewww.caelum.com.br/online

Blog Caelumblog.caelum.com.br

Newsletterwww.caelum.com.br/newsletter

Facebookwww.facebook.com/caelumbr

Twittertwitter.com/caelum

Casa do CódigoLivros para o programador

www.casadocodigo.com.br

Conheça alguns de nossos cursos

FJ-11: Java e Orientação a objetos

FJ-26: Laboratório Web com JSF2 e CDI

FJ-16: Laboratório Java com Testes, XML e Design Patterns

FJ-19: Preparatório para Certificação de Programador Java

FJ-21: Java para Desenvolvimento Web

FJ-31: Java EE avançado e Web Services

FJ-91: Arquitetura e Design de Projetos Java

RR-71:Desenvolvimento Ágil para Web 2.0 com Ruby on Rails

RR-75:Ruby e Rails avançados: lidando com problemas do dia a dia

✓ Mais de 8000 alunos treinados;✓ Reconhecida nacionalmente;✓ Conteúdos atualizados para o mercado e para sua carreira;✓ Aulas com metodologia e didática cuidadosamente preparadas;✓ Ativa participação nas comunidades Java, Rails e Scrum;✓ Salas de aula bem equipadas;✓ Instrutores qualificados e experientes;✓ Apostilas disponíveis no site.

Para mais informações e outros cursos, visite: caelum.com.br/cursos

FJ-25: Persistência com JPA2 e Hibernate

Sobre esta apostilaEsta apostila daCaelumvisa ensinar de umamaneira elegante, mostrando apenas o que é necessário e quando

é necessário, no momento certo, poupando o leitor de assuntos que não costumam ser de seu interesse em

determinadas fases do aprendizado.

A Caelum espera que você aproveite esse material. Todos os comentários, críticas e sugestões serão muito

bem-vindos.

Essa apostila é constantemente atualizada e disponibilizada no site da Caelum. Sempre consulte o site para

novas versões e, ao invés de anexar o PDF para enviar a um amigo, indique o site para que ele possa sempre

baixar as últimas versões. Você pode conferir o código de versão da apostila logo no �nal do índice.

Baixe sempre a versão mais nova em: www.caelum.com.br/apostilas

Esse material é parte integrante do treinamento Java e Orientação a Objetos e distribuído gratuitamente ex-

clusivamente pelo site da Caelum. Todos os direitos são reservados à Caelum. A distribuição, cópia, revenda

e utilização para ministrar treinamentos são absolutamente vedadas. Para uso comercial deste material, por

favor, consulte a Caelum previamente.

www.caelum.com.br

1

Sumário

1 Como Aprender Java 11.1 O que é realmente importante? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.2 Sobre os exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1.3 Tirando dúvidas e indo além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2 O que é Java 32.1 Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2.2 Uma breve história do Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2.3 Máquina Virtual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2.4 Java lento? Hotspot e JIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.5 Versões do Java e a confusão do Java2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.6 JVM? JRE? JDK? O que devo baixar? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2.7 Onde usar e os objetivos do Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2.8 Especi�cação versus implementação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2.9 Como o FJ-11 está organizado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2.10 Compilando o primeiro programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.11 Executando seu primeiro programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

2.12 O que aconteceu? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

2.13 Para saber mais: como é o bytecode? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

2.14 Exercícios: Modi�cando o Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

2.15 O que pode dar errado? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2.16 Um pouco mais... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

2.17 Exercícios adicionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

3 Variáveis primitivas e Controle de �uxo 163.1 Declarando e usando variáveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

3.2 Tipos primitivos e valores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

3.3 Exercícios: Variáveis e tipos primitivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

3.4 Discussão em aula: convenções de código e código legível . . . . . . . . . . . . . . . . . . . . . 20

3.5 Casting e promoção . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

3.6 O if e o else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

3.7 OWhile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

3.8 O For . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

3.9 Controlando loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

3.10 Escopo das variáveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

3.11 Um bloco dentro do outro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

3.12 Para saber mais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

3.13 Exercícios: Fixação de sintaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

3.14 Desa�os: Fibonacci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

i

4 Orientação a objetos básica 324.1 Motivação: problemas do paradigma procedural . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

4.2 Criando um tipo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

4.3 Uma classe em Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

4.4 Criando e usando um objeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

4.5 Métodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

4.6 Métodos com retorno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

4.7 Objetos são acessados por referências . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

4.8 O método transfere() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

4.9 Continuando com atributos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

4.10 Para saber mais: Uma Fábrica de Carros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

4.11 Um pouco mais... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

4.12 Exercícios: Orientação a Objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

4.13 Desa�os . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

4.14 Fixando o conhecimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

5 Um pouco de arrays 585.1 O problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

5.2 Arrays de referências . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

5.3 Percorrendo uma array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

5.4 Percorrendo uma array no Java 5.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

5.5 Exercícios: Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62

5.6 Um pouco mais... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

5.7 Desa�os . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

5.8 Testando o conhecimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

6 Modi�cadores de acesso e atributos de classe 676.1 Controlando o acesso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

6.2 Encapsulamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

6.3 Getters e Setters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

6.4 Construtores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

6.5 A necessidade de um construtor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

6.6 Atributos de classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

6.7 Um pouco mais... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

6.8 Exercícios: Encapsulamento, construtores e static . . . . . . . . . . . . . . . . . . . . . . . . . . 81

6.9 Desa�os . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

7 Herança, reescrita e polimor�smo 847.1 Repetindo código? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

7.2 Reescrita de método . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88

7.3 Invocando o método reescrito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

7.4 Polimor�smo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90

7.5 Um outro exemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92

ii

7.6 Um pouco mais... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

7.7 Exercícios: Herança e Polimor�smo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

7.8 Discussões em aula: Alternativas ao atributo protected . . . . . . . . . . . . . . . . . . . . . . . 98

8 Eclipse IDE 998.1 O Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99

8.2 Apresentando o Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100

8.3 Views e Perspective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

8.4 Criando um projeto novo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

8.5 Criando o main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

8.6 Executando o main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

8.7 Pequenos truques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111

8.8 Exercícios: Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111

8.9 Discussão em aula: Refactoring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114

9 Classes Abstratas 1159.1 Repetindo mais código? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115

9.2 Classe abstrata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117

9.3 Métodos abstratos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118

9.4 Aumentando o exemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

9.5 Para saber mais... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

9.6 Exercícios: Classes Abstratas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

9.7 Desa�os . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123

10 Interfaces 12410.1 Aumentando nosso exemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

10.2 Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128

10.3 Di�culdade no aprendizado de interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132

10.4 Exemplo interessante: conexões com o banco de dados . . . . . . . . . . . . . . . . . . . . . . . 133

10.5 Exercícios: Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133

10.6 Exercícios avançados opcionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

10.7 Discussão: favoreça composição em relação à herança . . . . . . . . . . . . . . . . . . . . . . . 139

11 Exceções e controle de erros 14011.1 Motivação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140

11.2 Exercício para começar com os conceitos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142

11.3 Exceções de Runtime mais comuns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147

11.4 Outro tipo de exceção: Checked Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148

11.5 Um pouco da grande família�rowable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151

11.6 Mais de um erro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151

11.7 Lançando exceções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152

11.8 O que colocar dentro do try? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154

11.9 Criando seu próprio tipo de exceção . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155

iii

11.10 Para saber mais: �nally . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157

11.11 Exercícios: Exceções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157

11.12 Desa�os . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160

11.13 Discussão em aula: catch e throws em Exception . . . . . . . . . . . . . . . . . . . . . . . . . . . 160

12 Pacotes - Organizando suas classes e bibliotecas 16112.1 Organização . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161

12.2 Diretórios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162

12.3 Import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163

12.4 Acesso aos atributos, construtores e métodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165

12.5 Usando o Eclipse com pacotes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166

12.6 Exercícios: Pacotes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167

13 Ferramentas: jar e javadoc 16913.1 Arquivos, bibliotecas e versões . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169

13.2 Gerando o JAR pelo Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171

13.3 Javadoc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173

13.4 Gerando o Javadoc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174

13.5 Exercícios: Jar e Javadoc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178

14 O pacote java.lang 18014.1 Pacote java.lang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180

14.2 Um pouco sobre a classe System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180

14.3 java.lang.Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181

14.4 Casting de referências . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182

14.5 Métodos do java.lang.Object: equals e toString . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184

14.6 Integer e classes wrappers (box) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187

14.7 Autoboxing no Java 5.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188

14.8 java.lang.String . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189

14.9 java.lang.Math . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192

14.10 Exercícios: java.lang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192

14.11 Desa�o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195

14.12 Discussão em aula: O que você precisa fazer em Java? . . . . . . . . . . . . . . . . . . . . . . . . 196

15 Pacote java.io 19715.1 Conhecendo uma API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197

15.2 Orientação a objetos no java.io . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198

15.3 InputStream, InputStreamReader e Bu�eredReader . . . . . . . . . . . . . . . . . . . . . . . . . 198

15.4 Lendo Strings do teclado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200

15.5 A analogia para a escrita: OutputStream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201

15.6 Uma maneira mais fácil: Scanner e PrintStream . . . . . . . . . . . . . . . . . . . . . . . . . . . 203

15.7 Um pouco mais... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204

15.8 Exercícios: Java I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204

iv

15.9 Discussão em aula: Design Patterns e o Template Method . . . . . . . . . . . . . . . . . . . . . 208

16 Collections framework 21016.1 Arrays são trabalhosos, utilizar estrutura de dados . . . . . . . . . . . . . . . . . . . . . . . . . . 210

16.2 Listas: java.util.List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211

16.3 Listas no Java 5 e Java 7 com Generics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215

16.4 A importância das interfaces nas coleções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216

16.5 Ordenação: Collections.sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217

16.6 Exercícios: Ordenação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220

16.7 Conjunto: java.util.Set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223

16.8 Principais interfaces: java.util.Collection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225

16.9 Percorrendo coleções no Java 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226

16.10 Para saber mais: Iterando sobre coleções com java.util.Iterator . . . . . . . . . . . . . . . . . . . 227

16.11 Mapas - java.util.Map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228

16.12 Para saber mais: Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231

16.13 Para saber mais: Equals e HashCode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231

16.14 Para saber mais: Boas práticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232

16.15 Exercícios: Collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232

16.16 Desa�os . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235

17 Programação Concorrente e�reads 23617.1 �reads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236

17.2 Escalonador e trocas de contexto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239

17.3 Garbage Collector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241

17.4 Para saber mais: problemas com concorrência . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242

17.5 Para saber mais: Vector e Hashtable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245

17.6 Um pouco mais... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246

17.7 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246

17.8 Exercícios avançados de programação concorrente e locks . . . . . . . . . . . . . . . . . . . . . 247

18 E agora? 25018.1 Praticando Java e usando bibliotecas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250

18.2 Web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250

18.3 Certi�cação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251

18.4 Revistas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251

18.5 Grupos de Usuários . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251

18.6 Falando em Java - Próximos módulos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251

19 Apêndice - Sockets 25319.1 Motivação: uma API que usa os conceitos aprendidos . . . . . . . . . . . . . . . . . . . . . . . . 253

19.2 Protocolo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253

19.3 Porta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254

19.4 Socket . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255

v

19.5 Servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255

19.6 Cliente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257

19.7 Imagem geral . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259

19.8 Exercícios: Sockets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260

19.9 Desa�o: Múltiplos Clientes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262

19.10 Desa�o: broadcast das mensagens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262

19.11 Solução do sistema de chat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263

20 Apêndice - Instalação do Java 26720.1 Instalando no Ubuntu e em outros Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267

20.2 No Mac OS X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268

20.3 Instalação do JDK em ambiente Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268

21 Apêndice - Debugging 27221.1 O que é debugar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272

21.2 Debugando no Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272

21.3 Perspectiva de debug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274

21.4 Debug avançado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277

21.5 Pro�ling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284

21.6 Pro�ling no Eclipse TPTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284

Índice Remissivo 287Versão: 15.7.4

vi

Capítulo 1

Como Aprender Java

“Busco um instante feliz que justi�que minha existência”– Fiodór Dostoiévski

1.1 O que é realmente importante?

Muitos livros, ao passar dos capítulos, mencionam todos os detalhes da linguagem juntamente com seus prin-

cípios básicos. Isso acaba criando muita confusão, em especial porque o estudante não consegue distinguir

exatamente o que é primordial aprender no início, daquilo que pode ser estudado mais adiante.

Se uma classe abstrata deve ou não ter ao menos ummétodo abstrato, se o if só aceita argumentos booleanos

e todos os detalhes sobre classes internas, realmente não devem se tornar preocupações para aquele cujo

objetivo primário é aprender Java. Esse tipo de informação será adquirida com o tempo, e não é necessário

no início.

Neste curso, separamos essas informações em quadros especiais, já que são informações extras. Ou então,

apenas citamos num exercício e deixamos para o leitor procurar informações se for de seu interesse.

Por �m, falta mencionar algo sobre a prática, que deve ser tratada seriamente: todos os exercícios são muito

importantes e os desa�os podem ser feitos quando o curso terminar. De qualquer maneira recomendamos

aos alunos estudarem em casa, e praticarem bastante código e variações.

O curso

Para aqueles que estão fazendo o curso Java e Orientação a Objetos, recomendamos estudarem

em casa aquilo que foi visto durante a aula, tentando resolver os exercícios opcionais e os desa�os

apresentados.

Material do Treinamento Java e Orientação a Objetos

1.2 Sobre os exercícios

Os exercícios do curso variam de práticos até pesquisas na Internet, ou mesmo consultas sobre assuntos

avançados em determinados tópicos para incitar a curiosidade do aprendiz na tecnologia.

Existem também, em determinados capítulos, uma série de desa�os. Eles focammais no problema computa-

cional que na linguagem, porém são uma excelente forma de treinar a sintaxe e, principalmente, familiarizar

o aluno com a biblioteca padrão Java, além de proporcionar um ganho na velocidade de desenvolvimento.

1.3 Tirando dúvidas e indo além

Para tirar dúvidas dos exercícios, ou de Java em geral, recomendamos o fórum do GUJ (http://www.guj.com.

br/), onde sua dúvida será respondida prontamente. O GUJ foi fundado por desenvolvedores da Caelum, e

hoje conta com mais de um milhão de mensagens.

Fora isso, sinta-se à vontade para entrar emcontato com seu instrutor para tirar todas as dúvidas que surgirem

durante o curso.

Se o que você está buscando são livros de apoio, sugerimos conhecer a editora Casa do Código:

http://www.CasaDoCodigo.com.br

A Caelum fornece muitos outros cursos Java, com destaque para o FJ-21 que traz a aplicação do Java na web.

Há também cursos online que vão te ajudar a ir além, com muita interação com os instrutores:

http://www.caelum.com.br/

http://www.caelum.com.br/online

Capítulo 1 - Como Aprender Java - Sobre os exercícios - Página 2

Capítulo 2

O que é Java

“Computadores são inúteis, eles apenas dão respostas”– Picasso

Chegou a hora de responder as perguntas mais básicas sobre Java. Ao término desse capítulo, você será capaz

de:

• responder o que é Java;

• mostrar as vantagens e desvantagens do Java;

• entender bem o conceito de máquina virtual;

• compilar e executar um programa simples.

2.1 Java

Entender um pouco da história da plataforma Java é essencial para enxergar os motivos que a levaram ao

sucesso.

Quais eram os seus maiores problemas quando programava na década de 1990?

• ponteiros?

• gerenciamento de memória?

• organização?

• falta de bibliotecas?

• ter de reescrever parte do código ao mudar de sistema operacional?

Material do Treinamento Java e Orientação a Objetos

• custo �nanceiro de usar a tecnologia?

A linguagem Java resolve bem esses problemas, que até então apareciam com frequência nas outras lingua-

gens. Alguns desses problemas foram particularmente atacados porque uma das grandes motivações para a

criação da plataforma Java era de que essa linguagem fosse usada em pequenos dispositivos, como tvs, video-

cassetes, aspiradores, liquidi�cadores e outros. Apesar disso a linguagem teve seu lançamento focado no uso

em clientes web (browsers) para rodar pequenas aplicações (applets). Hoje em dia esse não é o grande mer-cado do Java: apesar de ter sido idealizado com um propósito e lançado com outro, o Java ganhou destaque

no lado do servidor.

O Java foi criado pela Sun (http://www.sun.com) e mantida através de um comitê (http://www.jcp.org). Seu

site principal era o java.sun.com, e java.com um site mais institucional, voltado ao consumidor de produtos

e usuários leigos, não desenvolvedores. Com a compra da Sun pela Oracle em 2009, muitas URLs e nomes

tem sido trocados para re�etir a marca da Oracle. A página principal do Java é: http://www.oracle.com/

technetwork/java/

No Brasil, diversos grupos de usuários se formaram para tentar disseminar o conhecimento da linguagem.

Um deles é o GUJ (http://www.guj.com.br), uma comunidade virtual com artigos, tutoriais e fórum paratirar dúvidas, o maior em língua portuguesa com mais de cem mil usuários e 1 milhão de mensagens.

Encorajamos todos os alunos a usar muito os fóruns do mesmo, pois é uma das melhores maneiras para

achar soluções para pequenos problemas que acontecem com grande frequência.

2.2 Uma breve história do Java

A Sun criou um time (conhecido como Green Team) para desenvolver inovações tecnológicas em 1992. Esse

time foi liderado por James Gosling, considerado o pai do Java. O time voltou com a ideia de criar um

interpretador (já era uma máquina virtual, veremos o que é isso mais a frente) para pequenos dispositivos,

facilitando a reescrita de so�ware para aparelhos eletrônicos, como vídeo cassete, televisão e aparelhos de

TV a cabo.

A ideia não deu certo. Tentaram fechar diversos contratos com grandes fabricantes de eletrônicos, como

Panasonic, mas não houve êxito devido ao con�ito de interesses e custos. Hoje, sabemos que o Java domina

o mercado de aplicações para celulares com mais de 2.5 bilhões de dispositivos compatíveis, porém em 1994

ainda era muito cedo para isso.

Com o advento da web, a Sun percebeu que poderia utilizar a ideia criada em 1992 para rodar pequenas

aplicações dentro do browser. A semelhança era que na internet havia uma grande quantidade de sistemas

operacionais e browsers, e com isso seria grande vantagem poder programar numa única linguagem, in-

dependente da plataforma. Foi aí que o Java 1.0 foi lançado: focado em transformar o browser de apenas

um cliente magro (thin client ou terminal burro) em uma aplicação que possa também realizar operaçõesavançadas, e não apenas renderizar html.

Os applets deixaram de ser o foco da Sun, e nem a Oracle nunca teve interesse. É curioso notar que a tec-

nologia Java nasceu com um objetivo em mente, foi lançado com outro, mas, no �nal, decolou mesmo no

Capítulo 2 - O que é Java - Uma breve história do Java - Página 4

Material do Treinamento Java e Orientação a Objetos

desenvolvimento de aplicações do lado do servidor. Sorte? Há hoje o Java FX, tentando dar força para o Java

não só no desktop mas como aplicações ricas na web, mas muitos não acreditam que haja espaço para tal,

considerando o destino de tecnologias como Adobe Flex e Microso� Silverlight.

Você pode ler a história da linguagem Java em: http://www.java.com/en/javahistory/

E um vídeo interessante: http://tinyurl.com/histjava

Em 2009 a Oracle comprou a Sun, fortalecendo a marca. A Oracle sempre foi, junto com a IBM, uma das

empresas que mais investiram e �zeram negócios através do uso da plataforma Java. Em 2011 surge a versão

Java 7 com algumas pequenas mudanças na linguagem.

2.3 Máquina Virtual

Em uma linguagem de programação como C e Pascal, temos a seguinte situação quando vamos compilar um

programa:

O código fonte é compilado para código de máquina especí�co de uma plataforma e sistema operacional.

Muitas vezes o próprio código fonte é desenvolvido visando uma única plataforma!

Esse código executável (binário) resultante será executado pelo sistema operacional e, por esse motivo, ele

deve saber conversar com o sistema operacional em questão.

Isto é, temos um código executável para cada sistema operacional. É necessário compilar uma vez para

Windows, outra para o Linux, e assim por diante, caso a gente queira que esse nosso so�ware possa ser

utilizado em várias plataformas. Esse é o caso de aplicativos como o OpenO�ce, Firefox e outros.

Como foi dito anteriormente, na maioria das vezes, a sua aplicação se utiliza das bibliotecas do sistema ope-

racional, como, por exemplo, a de interface grá�ca para desenhar as “telas”. A biblioteca de interface grá�ca

Capítulo 2 - O que é Java - Máquina Virtual - Página 5

Material do Treinamento Java e Orientação a Objetos

doWindows é bem diferente das do Linux: como criar então uma aplicação que rode de forma parecida nos

dois sistemas operacionais?

Precisamos reescrever ummesmo pedaço da aplicação para diferentes sistemas operacionais, já que eles não

são compatíveis.

Já o Java utiliza do conceito demáquina virtual, onde existe, entre o sistema operacional e a aplicação, umacamada extra responsável por “traduzir” - mas não apenas isso - o que sua aplicação deseja fazer para as

respectivas chamadas do sistema operacional onde ela está rodando no momento:

Dessa forma, a maneira com a qual você abre uma janela no Linux ou no Windows é a mesma: você ganha

independência de sistema operacional. Ou, melhor ainda, independência de plataforma em geral: não é

preciso se preocupar em qual sistema operacional sua aplicação está rodando, nem em que tipo de máquina,

con�gurações, etc.

Repare que umamáquina virtual é um conceito bemmais amplo que o de um interpretador. Como o próprio

nome diz, uma máquina virtual é como um “computador de mentira": tem tudo que um computador tem.

Em outras palavras, ela é responsável por gerenciar memória, threads, a pilha de execução, etc.

Sua aplicação roda sem nenhum envolvimento com o sistema operacional! Sempre conversando apenas com

a Java Virtual Machine (JVM).

Essa característica é interessante: como tudo passa pela JVM, ela pode tirar métricas, decidir onde é melhor

alocar a memória, entre outros. Uma JVM isola totalmente a aplicação do sistema operacional. Se uma JVM

termina abruptamente, só as aplicações que estavam rodando nela irão terminar: isso não afetará outras

JVMs que estejam rodando no mesmo computador, nem afetará o sistema operacional.

Essa camada de isolamento também é interessante quando pensamos em um servidor que não pode se su-

jeitar a rodar código que possa interferir na boa execução de outras aplicações.

Essa camada, a máquina virtual, não entende código java, ela entende um código de máquina especí�co.

Esse código de máquina é gerado por um compilador java, como o javac, e é conhecido por “bytecode”, poisexistem menos de 256 códigos de operação dessa linguagem, e cada “opcode” gasta um byte. O compilador

Capítulo 2 - O que é Java - Máquina Virtual - Página 6

Material do Treinamento Java e Orientação a Objetos

Java gera esse bytecode que, diferente das linguagens semmáquina virtual, vai servir para diferentes sistemas

operacionais, já que ele vai ser “traduzido” pela JVM.

Write once, run anywhere

Esse era um slogan que a Sun usava para o Java, já que você não precisa reescrever partes da sua

aplicação toda vez que quiser mudar de sistema operacional.

2.4 Java lento? Hotspot e JIT

Hotspot é a tecnologia que a JVMutiliza para detectar pontos quentes da sua aplicação: código que é executadomuito, provavelmente dentro de um ou mais loops. Quando a JVM julgar necessário, ela vai compilar estescódigos para instruções realmente nativas da plataforma, tendo emvista que isso vai provavelmentemelhorar

a performance da sua aplicação. Esse compilador é o JIT: Just inTime Compiler, o compilador que aparece“bem na hora” que você precisa.

Você pode pensar então: porque a JVM não compila tudo antes de executar a aplicação? É que teoricamente

compilar dinamicamente, amedida do necessário, pode gerar uma performancemelhor. Omotivo é simples:

imagine um .exe gerado pelo VisualBasic, pelo gcc ou pelo Delphi; ele é estático. Ele já foi otimizado baseado

em heurísticas, o compilador pode ter tomado uma decisão não tão boa.

Já a JVM, por estar compilando dinamicamente durante a execução, pode perceber que um determinado

código não está com performance adequada e otimizar mais um pouco aquele trecho, ou ainda mudar a

estratégia de otimização. É por esse motivo que as JVMs mais recentes (como a do Java 7) em alguns casos

chegam a ganhar de códigos C compilados com o GCC 3.x.

2.5 Versões do Java e a confusão do Java2

Java 1.0 e 1.1 são as versões muito antigas do Java, mas já traziam bibliotecas importantes como o JDBC e o

java.io.

Com o Java 1.2 houve um aumento grande no tamanho da API, e foi nesse momento em que trocaram a

nomenclatura de Java para Java2, com o objetivo de diminuir a confusão que havia entre Java e Javascript.

Mas lembre-se, não há versão “Java 2.0”, o 2 foi incorporado ao nome, tornando-se Java2 1.2.

Depois vieram o Java2 1.3 e 1.4, e o Java 1.5 passou a se chamar Java 5, tanto por uma questão de marketing

e porque mudanças signi�cativas na linguagem foram incluídas. É nesse momento que o “2” do nome Java

desaparece. Repare que para �ns de desenvolvimento, o Java 5 ainda é referido como Java 1.5.

Até a versão 1.4, existia um terceiro número (1.3.1, 1.4.1, 1.4.2, etc), indicando bug �xes e melhorias. A partir

do Java 5 existem apenas updates: Java 5 update 7, por exemplo.

Capítulo 2 - O que é Java - Java lento? Hotspot e JIT - Página 7

Material do Treinamento Java e Orientação a Objetos

Hoje a última versão disponível do Java é a 7, lançada em julho de 2011. Da versão 1.4 para a 5.0, a linguagem

sofreu muitas modi�cações, o que de certa forma fomentou a mudança no versionamento do Java. Já o Java

6 não trouxe nenhuma mudança na linguagem, mas trouxe mais recursos na API e muitas melhorias deperformance na VM. O novo Java 7 traz algumas pequenas mudanças na linguagem.

Existe compatibilidade para trás em todas as versões do Java. Um class gerado pelo javac da versão 1.2 precisa

necessariamente rodar em uma JVM 7. Por isso, recomendamos sempre usar a última versão do Java para

usufruir das tecnologias mais modernas mas sem correr o risco de quebrar aplicações antigas.

2.6 JVM? JRE? JDK?O que devo baixar?

O que gostaríamos de baixar no site da Oracle/Sun?

• JVM = apenas a virtual machine, esse download não existe, ela sempre vem acompanhada.

• JRE = Java Runtime Environment, ambiente de execução Java, formado pela JVM e bibliotecas, tudoque você precisa para executar uma aplicação Java. Mas nós precisamos de mais.

• JDK = Java Development Kit: Nós, desenvolvedores, faremos o download do JDK do Java SE (Stan-dard Edition). Ele é formado pela JRE somado a ferramentas, como o compilador.

Tanto o JRE e o JDK podem ser baixados do site http://java.sun.com, hoje gerenciado pela Oracle. Para

encontrá-los, acesse o link Java SE dentro dos top downloads. Consulte o apêndice de instalação do JDK

para maiores detalhes.

2.7 Onde usar e os objetivos do Java

No decorrer do curso, você pode achar que o Java tem menor produtividade quando comparada com a

linguagem que você está acostumado.

É preciso �car claro que a premissa do Java não é a de criar sistemas pequenos, onde temos um ou dois

desenvolvedores, mais rapidamente que linguagens como php, perl, e outras.

O foco da plataforma é outro: aplicações demédio a grande porte, onde o time de desenvolvedores tem váriaspessoas e sempre pode vir amudar e crescer. Não tenha dúvidas que criar a primeira versão de uma aplicaçãousando Java, mesmo utilizando IDEs e ferramentas poderosas, será mais trabalhoso que muitas linguagens

script ou de alta produtividade. Porém, com uma linguagem orientada a objetos e madura como o Java,

será extremamente mais fácil e rápido fazer alterações no sistema, desde que você siga as boas práticas e

recomendações sobre design orientado a objetos.

Além disso, a quantidade enorme de bibliotecas gratuitas para realizar os mais diversos trabalhos (tais como

relatórios, grá�cos, sistemas de busca, geração de código de barra, manipulação de XML, tocadores de vídeo,

manipuladores de texto, persistência transparente, impressão, etc) é um ponto fortíssimo para adoção do

Capítulo 2 - O que é Java - JVM? JRE? JDK? O que devo baixar? - Página 8

Material do Treinamento Java e Orientação a Objetos

Java: você pode criar uma aplicação so�sticada, usando diversos recursos, sem precisar comprar um com-

ponente especí�co, que costuma ser caro. O ecossistema do Java é enorme.

Cada linguagem tem seu espaço e seu melhor uso. O uso do Java é interessante em aplicações que virão

a crescer, em que a legibilidade do código é importante, onde temos muita conectividade e se há muitas

plataformas (ambientes e sistemas operacionais) heterogêneas (Linux, Unix, OSX e Windows misturados).

Você pode ver isso pela quantidade enorme de ofertas de emprego procurando desenvolvedores Java para

trabalhar com sistemas web e aplicações de integração no servidor.

Apesar disto, a Sun empenhou-se em tentar popularizar o uso do Java em aplicações desktop, mesmo com

o fraco marketshare do Swing/AWT/SWT em relação às tecnologias concorrentes (em especial Microso�

.NET). A atual tentativa é o Java FX, onde a Oracle tem investido bastante.

2.8 Especificação versus implementação

Outro ponto importante: quando falamos de Java Virtual Machine, estamos falando de uma especi�cação.

Ela diz como o bytecode deve ser interpretado pela JVM.Quando fazemos o download no site da Sun/Oracle,

o que vem junto é a Oracle JVM. Em outras palavras, existem outras JVMs disponíveis, como a JRockit da

BEA (também adquirida pela Oracle), a J9 da IBM, entre outras.

Esse é outro ponto interessante para as empresas. Caso não estejam gostando de algum detalhe da JVM

da Sun ou pre�ram trabalhar com outra empresa, pagando por suporte, elas podem trocar de JVM com a

garantia absoluta de que todo o sistema continuará funcionando. Isso porque toda JVM deve ser certi�cada

pela Sun, provando a sua compatibilidade. Não há nem necessidade de recompilar nenhuma de suas classes.

Alémde independência de hardware e sistema operacional, você tem a independência de vendor (fabricante):graças a ideia da JVM ser uma especi�cação e não um so�ware.

2.9 Como o FJ-11 está organizado

Java é uma linguagem simples: existem poucas regras, muito bem de�nidas.

Porém quebrar o paradigma procedural para mergulhar na orientação a objetos não é simples. Quebrar o

paradigma e ganhar �uência com a linguagem e API são os objetivos do FJ-11.

O começo pode ser um pouco frustrante: exemplos simples, controle de �uxo com o if, for, while e criaçãode pequenos programas que nem ao menos captam dados do teclado. Apesar de isso tudo ser necessário, é

só nos 20% �nais do curso que utilizaremos bibliotecas para, no �nal, criarmos um chat entre duas máquinas

que transferemStrings porTCP/IP.Neste ponto, teremos tudo que é necessário para entender completamente

como a API funciona, quem estende quem, e o porquê.

Depois desse capítulo no qual o Java, a JVM e primeiros conceitos são passados, veremos os comandos bá-

sicos do java para controle de �uxo e utilização de variáveis do tipo primitivo. Criaremos classes para testar

Capítulo 2 - O que é Java - Especi�cação versus implementação - Página 9

Material do Treinamento Java e Orientação a Objetos

esse pequeno aprendizado, sem saber exatamente o que é uma classe. Isso di�culta ainda mais a curva de

aprendizado, porém cada conceito será introduzido nomomento consideradomais apropriado pelos instru-

tores.

Passamos para o capítulo de orientação a objetos básico, mostrando os problemas do paradigma procedural

e a necessidade de algo diferente para resolvê-los. Atributos, métodos, variáveis do tipo referência e outros.

Passamos então para um pouco de arrays.

Os capítulos de modi�cadores de acesso, herança, classes abstratas e interfaces demonstram o conceito fun-

damental que o curso quer passar: encapsule, exponha o mínimo de suas classes, foque no que elas fazem,

no relacionamento entre elas. Com um bom design, a codi�cação �ca fácil e a modi�cação e expansão do

sistema também.

No decorrer desses capítulos, o Eclipse é introduzido de forma natural, evitando-se ao máximo wizards e

menus, priorizando mostrar os chamados code assists e quick �xes. Isso faz com que o Eclipse trabalhe deforma simbiótica com o desenvolvedor, sem se intrometer, sem fazer mágica.

Pacotes, javadoc, jars e java.lang apresentam os últimos conceitos fundamentais do Java, dando toda a fun-

dação para, então, passarmos a estudar as principais e mais utilizadas APIs do Java SE.

As APIs estudadas serão java.util, java.io e java.net. Todas elas usam e abusam dos conceitos vistos no de-

correr do curso, ajudando a sedimentá-los. Juntamente, temos os conceitos básicos do uso de�reads, e os

problemas e perigos da programação concorrente quando dados são compartilhados.

Resumindo: o objetivo do curso é apresentar o Java ao mesmo tempo que os fundamentos da orientação a

objetos são introduzidos. Bateremos muito no ponto de dizer que o importante é como as classes se relaci-

onam e qual é o papel de cada uma, e não em como elas realizam as suas obrigações. Programe voltado àinterface, e não à implementação.

2.10 Compilando o primeiro programa

Vamos para o nosso primeiro código! O programa que imprime uma linha simples.

Para mostrar uma linha, podemos fazer:

System.out.println("Minha primeira aplicação Java!");

Mas esse código não será aceito pelo compilador java. O Java é uma linguagem bastante burocrática, e precisa

de mais do que isso para iniciar uma execução. Veremos os detalhes e os porquês durante os próximos

capítulos. O mínimo que precisaríamos escrever é algo como:

1 class MeuPrograma {2 public static void main(String[] args) {3 System.out.println("Minha primeira aplicação Java!");4 }5 }

Capítulo 2 - O que é Java - Compilando o primeiro programa - Página 10

Material do Treinamento Java e Orientação a Objetos

Notação

Todos os códigos apresentados na apostila estão formatados com recursos visuais para auxiliar

a leitura e compreensão dos mesmos. Quando for digitar os códigos no computador, trate os

códigos como texto simples.

A numeração das linhas não faz parte do código e não deve ser digitada; é apenas um recursodidático. O Java é case sensitive: tome cuidado com maiúsculas e minúsculas.

Após digitar o código acima, grave-o como MeuPrograma.java em algum diretório. Para compilar, vocêdeve pedir para que o compilador de Java da Sun, chamado javac, gere o bytecode correspondente ao seucódigo Java.

Depois de compilar, o bytecode foi gerado. Quando o sistema operacional listar os arquivos contidos nodiretório atual, você poderá ver que um arquivo .class foi gerado, com o mesmo nome da sua classe Java.

Assustado com o código?

Para quem já tem uma experiência com Java, esse primeiro código é muito simples. Mas, se é seu

primeiro código em Java, pode ser umpouco traumatizante. Não deixe de ler o prefácio do curso,

que deixará você mais tranquilo em relação a curva de aprendizado da linguagem, conhecendo

como o curso está organizado.

Capítulo 2 - O que é Java - Compilando o primeiro programa - Página 11

Material do Treinamento Java e Orientação a Objetos

Preciso sempre programar usando oNotepad ou similar?

Não é necessário digitar sempre seu programa em um simples aplicativo como o Notepad. Você

pode usar um editor que tenha syntax highlighting e outros benefícios.

Mas, no começo, é interessante você usar algo que não possua ferramentas, para que você possa

se acostumar com os erros de compilação, sintaxe e outros. Depois do capítulo de polimor�smo

e herança sugerimos a utilização do Eclipse (http://www.eclipse.org), a IDE líder no mercado, e

gratuita. Existe um capítulo a parte para o uso do Eclipse nesta apostila.

No Linux, recomendamos o uso do gedit ou do kate. NoWindows, você pode usar o Notepad++

ou o TextPad. No Mac, TextWrangler ou TextMate.

2.11 Executando seu primeiro programa

Os procedimentos para executar seu programa são muito simples. O javac é o compilador Java, e o java é o

responsável por invocar a máquina virtual para interpretar o seu programa.

Ao executar, pode ser que a acentuação resultante saia errada devido a algumas con�gurações que deixamos

de fazer. Sem problemas.

2.12 O que aconteceu?

1 class MeuPrograma {2 public static void main(String[] args) {3

4 // miolo do programa começa aqui!5 System.out.println("Minha primeira aplicação Java!!");6 // fim do miolo do programa7

8 }9 }

O miolo do programa é o que será executado quando chamamos a máquina virtual. Por enquanto, todas

as linhas anteriores, onde há a declaração de uma classe e a de um método, não importam para nós nesse

momento. Mas devemos saber que toda aplicação Java começa por um ponto de entrada, e este ponto de

entrada é o método main.

Capítulo 2 - O que é Java - Executando seu primeiro programa - Página 12

Material do Treinamento Java e Orientação a Objetos

Ainda não sabemos o que é método, mas veremos no capítulo 4. Até lá, não se preocupe com essas declara-

ções. Sempre que um exercício for feito, o código que nos importa sempre estará nesse miolo.

No caso do nosso código, a linha do System.out.println faz com que o conteúdo entre aspas seja colocadona tela.

2.13 Para saber mais: como é o bytecode?

O MeuPrograma.class gerado não é legível por seres humanos (não que seja impossível). Ele está escrito noformato que a virtual machine sabe entender e que foi especi�cado que ela entendesse.

É como um assembly, escrito para esta máquina em especí�co. Podemos ler os mnemônicos utilizando a

ferramenta javap que acompanha o JDK:

javap -c MeuPrograma

E a saída:

MeuPrograma();Code:0: aload_01: invokespecial #1; //Method java/lang/Object."<init>":()V4: return

public static void main(java.lang.String[]);Code:0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;3: ldc #3; //String Minha primeira aplicação Java!!5: invokevirtual #4; //Method java/io/PrintStream.println:

(Ljava/lang/String;)V8: return

}

É o código acima, que a JVM sabe ler. É o “código de máquina”, da máquina virtual.

Umbytecode pode ser revertido para o .java original (comperda de comentários e nomes de variáveis locais).

Caso seu so�ware vá virar um produto de prateleira, é fundamental usar um ofuscador no seu código, que

vai embaralhar classes, métodos e um monte de outros recursos (indicamos o http://proguard.sf.net).

2.14 Exercícios: Modificando oHelloWorld

1) Altere seu programa para imprimir uma mensagem diferente.

Capítulo 2 - O que é Java - Para saber mais: como é o bytecode? - Página 13

Material do Treinamento Java e Orientação a Objetos

2) Altere seu programa para imprimir duas linhas de texto usando duas linhas de código System.out.

3) Sabendo que os caracteres \n representam uma quebra de linhas, imprima duas linhas de texto usandouma única linha de código System.out.

2.15 O que pode dar errado?

Muitos erros podem ocorrer no momento que você rodar seu primeiro código. Vamos ver alguns deles:

Código:

1 class X {2 public static void main (String[] args) {3 System.out.println("Falta ponto e vírgula")4 }5 }

Erro:

X.java:4: ';' expected}^

1 error

Esse é o erro de compilação mais comum: aquele onde um ponto e vírgula fora esquecido. Repare que o

compilador é explícito em dizer que a linha 4 é a com problemas. Outros erros de compilação podem ocorrerse você escreveu palavras chaves (as que colocamos em negrito) em maiúsculas, esqueceu de abrir e fechar

as {}, etc.

Durante a execução, outros erros podem aparecer:

- Se você declarar a classe como X, compilá-la e depois tentar usá-la como x minúsculo (java x), o Java te

avisa:

Exception in thread "main" java.lang.NoClassDefFoundError:X (wrong name: x)

- Se tentar acessar uma classe no diretório ou classpath errado, ou se o nome estiver errado, ocorrerá o

seguinte erro:

Exception in thread "main" java.lang.NoClassDefFoundError: X

- Se esquecer de colocar static ou o argumento String[] args no método main:

Capítulo 2 - O que é Java - O que pode dar errado? - Página 14

Material do Treinamento Java e Orientação a Objetos

Exception in thread "main" java.lang.NoSuchMethodError: main

Por exemplo:

class X {public void main (String[] args) {

System.out.println("Faltou o static, tente executar!");}

}

- Se não colocar o método main como public:

Main method not public.

Por exemplo:

class X {static void main (String[] args) {

System.out.println("Faltou o public");}

}

2.16 Um pouco mais...

1) Procure um colega, ou algum conhecido, que esteja em um projeto Java. Descubra porque Java foi esco-

lhido como tecnologia. O que é importante para esse projeto e o que acabou fazendo do Java a melhor

escolha?

2.17 Exercícios adicionais

1) Um arquivo fonte Java deve sempre ter a extensão .java, ou o compilador o rejeitará. Além disso, existemalgumas outras regras na hora de dar o nome de um arquivo Java. Experimente gravar o código deste

capítulo com OutroNome.java ou algo similar.

Compile e veri�que o nome do arquivo gerado. Como executar a sua aplicação?

Capítulo 2 - O que é Java - Um pouco mais... - Página 15

Capítulo 3

Variáveis primitivas e Controle de �uxo

“Péssima ideia, a de que não se pode mudar”–Montaigne

Aprenderemos a trabalhar com os seguintes recursos da linguagem Java:

• declaração, atribuição de valores, casting e comparação de variáveis;

• controle de �uxo através de if e else;

• instruções de laço for e while, controle de �uxo com break e continue.

3.1 Declarando e usando variáveis

Dentro de umbloco, podemos declarar variáveis e usá-las. Em Java, toda variável tem um tipo que não podeser mudado, uma vez que declarado:

tipoDaVariavel nomeDaVariavel;

Por exemplo, é possível ter uma idade que guarda um número inteiro:

int idade;

Com isso, você declara a variável idade, que passa a existir a partir daquela linha. Ela é do tipo int, queguarda um número inteiro. A partir daí, você pode usá-la, primeiramente atribuindo valores.

A linha a seguir é a tradução de: "idade deve valer quinze”.

idade = 15;

Material do Treinamento Java e Orientação a Objetos

Comentários em Java

Para fazer um comentário em java, você pode usar o // para comentar até o �nal da linha, ouentão usar o /* */ para comentar o que estiver entre eles.

/* comentário daqui,ate aqui */

// uma linha de comentário sobre a idadeint idade;

Além de atribuir, você pode utilizar esse valor. O código a seguir declara novamente a variável idade comvalor 15 e imprime seu valor na saída padrão através da chamada a System.out.println.

// declara a idadeint idade;idade = 15;

// imprime a idadeSystem.out.println(idade);

Por �m, podemos utilizar o valor de uma variável para algum outro propósito, como alterar ou de�nir uma

segunda variável. O código a seguir cria uma variável chamada idadeNoAnoQueVem com valor de idade maisum.

// calcula a idade no ano seguinteint idadeNoAnoQueVem;idadeNoAnoQueVem = idade + 1;

No mesmo momento que você declara uma variável, também é possível inicializá-la por praticidade:

int idade = 15;

Você pode usar os operadores +, -, / e * para operar com números, sendo eles responsáveis pela adição, sub-

tração, divisão emultiplicação, respectivamente. Além desses operadores básicos, há o operador % (módulo)

que nada mais é que o resto de uma divisão inteira. Veja alguns exemplos:

int quatro = 2 + 2;int tres = 5 - 2;

Capítulo 3 - Variáveis primitivas e Controle de �uxo - Declarando e usando variáveis - Página 17

Material do Treinamento Java e Orientação a Objetos

int oito = 4 * 2;int dezesseis = 64 / 4;

int um = 5 % 2; // 5 dividido por 2 dá 2 e tem resto 1;// o operador % pega o resto da divisão inteira

Como rodar esses códigos?

Você deve colocar esses trechos de código dentro do bloco main que vimos no capítulo anterior.

Isto é, isso deve �car no miolo do programa. Use bastante System.out.println, dessa formavocê pode ver algum resultado, caso contrário, ao executar a aplicação, nada aparecerá.

Por exemplo, para imprimir a idade e a idadeNoAnoQueVem podemos escrever o seguinte pro-grama de exemplo:

class TestaIdade {

public static void main(String[] args) {// imprime a idadeint idade = 20;System.out.println(idade);

// gera uma idade no ano seguinteint idadeNoAnoQueVem;idadeNoAnoQueVem = idade + 1;

// imprime a idadeSystem.out.println(idadeNoAnoQueVem);

}}

Representar números inteiros é fácil, mas como guardar valores reais, tais como frações de números inteiros

e outros? Outro tipo de variável muito utilizado é o double, que armazena um número com ponto �utuante(e que também pode armazenar um número inteiro).

double pi = 3.14;double x = 5 * 10;

O tipo boolean armazena um valor verdadeiro ou falso, e só: nada de números, palavras ou endereços, como

em algumas outras linguagens.

Capítulo 3 - Variáveis primitivas e Controle de �uxo - Declarando e usando variáveis - Página 18

Material do Treinamento Java e Orientação a Objetos

boolean verdade = true;

true e false são palavras reservadas do Java. É comum que um boolean seja determinado através de umaexpressão booleana, isto é, um trecho de código que retorna um booleano, como o exemplo:

int idade = 30;boolean menorDeIdade = idade < 18;

O tipo char guarda um, e apenas um, caractere. Esse caractere deve estar entre aspas simples. Não se esqueça

dessas duas características de uma variável do tipo char! Por exemplo, ela não pode guardar um código como

" pois o vazio não é um caractere!

char letra = 'a';System.out.println(letra);

Variáveis do tipo char são pouco usadas no dia a dia. Veremos mais a frente o uso das Strings, que usamosconstantemente, porém estas não são de�nidas por um tipo primitivo.

3.2 Tipos primitivos e valores

Esses tipos de variáveis são tipos primitivos do Java: o valor que elas guardam são o real conteúdo da variável.

Quando você utilizar o operador de atribuição = o valor será copiado.

int i = 5; // i recebe uma cópia do valor 5int j = i; // j recebe uma cópia do valor de ii = i + 1; // i vira 6, j continua 5

Aqui, i �ca com o valor de 6. Mas e j? Na segunda linha, j está valendo 5. Quando i passa a valer 6, seráque j também muda de valor? Não, pois o valor de um tipo primitivo sempre é copiado.

Apesar da linha 2 fazer j = i, a partir desse momento essas variáveis não tem relação nenhuma: o queacontece com uma, não re�ete em nada com a outra.

Outros tipos primitivos

Vimos aqui os tipos primitivos que mais aparecem. O Java tem outros, que são o byte, short,long e float.

Cada tipo possui características especiais que, para um programador avançado, podem fazer

muita diferença.

Capítulo 3 - Variáveis primitivas e Controle de �uxo - Tipos primitivos e valores - Página 19

Material do Treinamento Java e Orientação a Objetos

3.3 Exercícios: Variáveis e tipos primitivos

1) Na empresa onde trabalhamos, há tabelas com o quanto foi gasto em cada mês. Para fechar o balanço do

primeiro trimestre, precisamos somar o gasto total. Sabendo que, em Janeiro, foram gastos 15000 reais,

em Fevereiro, 23000 reais e emMarço, 17000 reais, faça um programa que calcule e imprima o gasto total

no trimestre. Siga esses passos:

a) Crie uma classe chamada BalancoTrimestral com um bloco main, como nos exemplos anteriores;

b) Dentro do main (o miolo do programa), declare uma variável inteira chamada gastosJaneiro einicialize-a com 15000;

c) Crie também as variáveis gastosFevereiro e gastosMarco, inicializando-as com 23000 e 17000, res-pectivamente, utilize uma linha para cada declaração;

d) Crie uma variável chamada gastosTrimestre e inicialize-a com a soma das outras 3 variáveis:

int gastosTrimestre = gastosJaneiro + gastosFevereiro + gastosMarco;

e) Imprima a variável gastosTrimestre.

2) Adicione código (sem alterar as linhas que já existem) na classe anterior para imprimir a média mensal

de gasto, criando uma variável mediaMensal junto com uma mensagem. Para isso, concatene a Stringcom o valor, usando "Valor da média mensal = "+ mediaMensal.

3.4 Discussão em aula: convenções de código e código legí-vel

Discuta com o instrutor e seus colegas sobre convenções de código Java. Por que existem? Por que são

importantes?

Discuta também as vantagens de se escrever código fácil de ler e se evitar comentários em excesso.

(Dica: procure por code conventions no campo de busca do site http://java.sun.com.)

3.5 Casting e promoção

Alguns valores são incompatíveis se você tentar fazer uma atribuição direta. Enquanto um número real

costuma ser representado emuma variável do tipo double, tentar atribuir ele a uma variável int não funcionaporque é um código que diz: "i deve valer d”, mas não se sabe se d realmente é um número inteiro ou não.

double d = 3.1415;int i = d; // não compila

Capítulo 3 - Variáveis primitivas e Controle de �uxo - Exercícios: Variáveis e tipos primitivos - Página 20

Material do Treinamento Java e Orientação a Objetos

Omesmo ocorre no seguinte trecho:

int i = 3.14;

Omais interessante, é que nem mesmo o seguinte código compila:

double d = 5; // ok, o double pode conter um número inteiroint i = d; // não compila

Apesar de 5 ser um bom valor para um int, o compilador não tem como saber que valor estará dentro dessedouble nomomento da execução. Esse valor pode ter sido digitado pelo usuário, e ninguém vai garantir queessa conversão ocorra sem perda de valores.

Já no caso a seguir, é o contrário:

int i = 5;double d2 = i;

O código acima compila sem problemas, já que um double pode guardar um número com ou sem ponto �u-tuante. Todos os inteiros representados por uma variável do tipo int podem ser guardados em uma variáveldouble, então não existem problemas no código acima.

Às vezes, precisamos que um número quebrado seja arredondado e armazenado num número inteiro. Para

fazer isso sem que haja o erro de compilação, é preciso ordenar que o número quebrado sejamoldado (cas-ted) como um número inteiro. Esse processo recebe o nome de casting.

double d3 = 3.14;int i = (int) d3;

O casting foi feito para moldar a variável d3 como um int. O valor de i agora é 3.

O mesmo ocorre entre valores int e long.

long x = 10000;int i = x; // não compila, pois pode estar perdendo informação

E, se quisermos realmente fazer isso, fazemos o casting:

long x = 10000;int i = (int) x;

Capítulo 3 - Variáveis primitivas e Controle de �uxo - Casting e promoção - Página 21

Material do Treinamento Java e Orientação a Objetos

Casos não tão comuns de casting e atribuição

Alguns castings aparecem também:

float x = 0.0;

O código acima não compila pois todos os literais com ponto �utuante são considerados doublepelo Java. E float não pode receber um double sem perda de informação, para fazer isso funci-onar podemos escrever o seguinte:

float x = 0.0f;

A letra f, que pode ser maiúscula ou minúscula, indica que aquele literal deve ser tratado como

float.Outro caso, que é mais comum:

double d = 5;float f = 3;

float x = f + (float) d;

Você precisa do casting porque o Java faz as contas e vai armazenando sempre nomaior tipo que

apareceu durante as operações, no caso o double.E, uma observação: no mínimo, o Java armazena o resultado em um int, na hora de fazer ascontas.

Até casting com variáveis do tipo char podem ocorrer. O único tipo primitivo que não pode seratribuído a nenhum outro tipo é o boolean.

Capítulo 3 - Variáveis primitivas e Controle de �uxo - Casting e promoção - Página 22

Material do Treinamento Java e Orientação a Objetos

Castings possíveis

Abaixo estão relacionados todos os casts possíveis na linguagem Java, mostrando a conversão deum valor para outro. A indicação Impl. quer dizer que aquele cast é implícito e automático, ouseja, você não precisa indicar o cast explicitamente (lembrando que o tipo boolean não pode ser

convertido para nenhum outro tipo).

Tamanho dos tipos

Na tabela abaixo, estão os tamanhos de cada tipo primitivo do Java.

3.6 O if e o else

A sintaxe do if no Java é a seguinte:

Capítulo 3 - Variáveis primitivas e Controle de �uxo - O if e o else - Página 23

Material do Treinamento Java e Orientação a Objetos

if (condicaoBooleana) {codigo;

}

Uma condição booleana é qualquer expressão que retorne true ou false. Para isso, você pode usar osoperadores <, >, <=, >= e outros. Um exemplo:

int idade = 15;if (idade < 18) {

System.out.println("Não pode entrar");}

Além disso, você pode usar a cláusula else para indicar o comportamento que deve ser executado no casoda expressão booleana ser falsa:

int idade = 15;if (idade < 18) {

System.out.println("Não pode entrar");} else {

System.out.println("Pode entrar");}

Você pode concatenar expressões booleanas através dos operadores lógicos "E” e "OU”. O "E” é representadopelo && e o "OU” é representado pelo ||.

Um exemplo seria veri�car se ele tem menos de 18 anos e se ele não é amigo do dono:

int idade = 15;boolean amigoDoDono = true;if (idade < 18 && amigoDoDono == false) {

System.out.println("Não pode entrar");}else {

System.out.println("Pode entrar");}

Esse código poderia �car ainda mais legível, utilizando-se o operador de negação, o !. Esse operador trans-forma o resultado de uma expressão booleana de false para true e vice versa.

1 int idade = 15;2 boolean amigoDoDono = true;3 if (idade < 18 && !amigoDoDono) {4 System.out.println("Não pode entrar");5 }

Capítulo 3 - Variáveis primitivas e Controle de �uxo - O if e o else - Página 24

Material do Treinamento Java e Orientação a Objetos

6 else {7 System.out.println("Pode entrar");8 }

Repare na linha 3 que o trecho amigoDoDono == false virou !amigoDoDono. Eles têm o mesmo valor.

Para comparar se uma variável tem o mesmo valor que outra variável ou valor, utilizamos o operador ==.Repare que utilizar o operador = dentro de um if vai retornar um erro de compilação, já que o operador = éo de atribuição.

int mes = 1;if (mes == 1) {

System.out.println("Você deveria estar de férias");}

3.7 OWhile

O while é um comando usado para fazer um laço (loop), isto é, repetir um trecho de código algumas vezes. Aideia é que esse trecho de código seja repetido enquanto uma determinada condição permanecer verdadeira.

int idade = 15;while (idade < 18) {

System.out.println(idade);idade = idade + 1;

}

O trecho dentro do bloco do while será executado até o momento em que a condição idade < 18 passe aser falsa. E isso ocorrerá exatamente no momento em que idade == 18, o que não o fará imprimir 18.

int i = 0;while (i < 10) {

System.out.println(i);i = i + 1;

}

Já o while acima imprime de 0 a 9.

3.8 O For

Outro comando de loop extremamente utilizado é o for. A ideia é a mesma do while: fazer um trecho decódigo ser repetido enquanto uma condição continuar verdadeira. Mas além disso, o for isola também umespaço para inicialização de variáveis e omodi�cador dessas variáveis. Isso faz com que �quemmais legíveis,

as variáveis que são relacionadas ao loop:

Capítulo 3 - Variáveis primitivas e Controle de �uxo - OWhile - Página 25

Material do Treinamento Java e Orientação a Objetos

for (inicializacao; condicao; incremento) {codigo;

}

Um exemplo é o a seguir:

for (int i = 0; i < 10; i = i + 1) {System.out.println("olá!");

}

Repare que esse for poderia ser trocado por:

int i = 0;while (i < 10) {

System.out.println("olá!");i = i + 1;

}

Porém, o código do for indica claramente que a variável i serve, em especial, para controlar a quantidadede laços executados. Quando usar o for? Quando usar o while? Depende do gosto e da ocasião.

Pós incremento ++

i = i + 1 pode realmente ser substituído por i++ quando isolado, porém, em alguns casos,temos essa instrução envolvida em, por exemplo, uma atribuição:

int i = 5;int x = i++;

Qual é o valor de x? O de i, após essa linha, é 6.O operador ++, quando vem após a variável, retorna o valor antigo, e incrementa (pós incre-mento), fazendo x valer 5.Se você tivesse usado o ++ antes da variável (pré incremento), o resultado seria 6:

int i = 5;int x = ++i; // aqui x valera 6

Capítulo 3 - Variáveis primitivas e Controle de �uxo - O For - Página 26

Material do Treinamento Java e Orientação a Objetos

3.9 Controlando loops

Apesar de termos condições booleanas nos nossos laços, em algummomento, podemos decidir parar o loop

por algum motivo especial sem que o resto do laço seja executado.

for (int i = x; i < y; i++) {if (i % 19 == 0) {

System.out.println("Achei um número divisível por 19 entre x e y");break;

}}

O código acima vai percorrer os números de x a y e parar quando encontrar um número divisível por 19,

uma vez que foi utilizada a palavra chave break.

Da mesma maneira, é possível obrigar o loop a executar o próximo laço. Para isso usamos a palavra chave

continue.

for (int i = 0; i < 100; i++) {if (i > 50 && i < 60) {

continue;}System.out.println(i);

}

O código acima não vai imprimir alguns números. (Quais exatamente?)

3.10 Escopo das variáveis

No Java, podemos declarar variáveis a qualquer momento. Porém, dependendo de onde você as declarou,

ela vai valer de um determinado ponto a outro.

// aqui a variável i não existeint i = 5;// a partir daqui ela existe

O escopo da variável é o nome dado ao trecho de código em que aquela variável existe e onde é possívelacessá-la.

Quando abrimos um novo bloco com as chaves, as variáveis declaradas ali dentro só valem até o �mdaquelebloco.

Capítulo 3 - Variáveis primitivas e Controle de �uxo - Controlando loops - Página 27

Material do Treinamento Java e Orientação a Objetos

// aqui a variável i não existeint i = 5;// a partir daqui ela existewhile (condicao) {

// o i ainda vale aquiint j = 7;// o j passa a existir

}// aqui o j não existe mais, mas o i continua dentro do escopo

No bloco acima, a variável j pára de existir quando termina o bloco onde ela foi declarada. Se você tentaracessar uma variável fora de seu escopo, ocorrerá um erro de compilação.

O mesmo vale para um if:

if (algumBooleano) {int i = 5;

}else {

int i = 10;}System.out.println(i); // cuidado!

Aqui a variável i não existe fora do if e do else! Se você declarar a variável antes do if, vai haver outro errode compilação: dentro do if e do else a variável está sendo redeclarada! Então o código para compilar efazer sentido �ca:

int i;if (algumBooleano) {

i = 5;}else {

i = 10;}System.out.println(i);

Uma situação parecida pode ocorrer com o for:

Capítulo 3 - Variáveis primitivas e Controle de �uxo - Escopo das variáveis - Página 28

Material do Treinamento Java e Orientação a Objetos

for (int i = 0; i < 10; i++) {System.out.println("olá!");

}System.out.println(i); // cuidado!

Neste for, a variável imorre ao seu término, não podendo ser acessada de fora do for, gerando um erro decompilação. Se você realmente quer acessar o contador depois do loop terminar, precisa de algo como:

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

System.out.println("olá!");}System.out.println(i);

3.11 Um bloco dentro do outro

Um bloco também pode ser declarado dentro de outro. Isto é, um if dentro de um for, ou um for dentrode um for, algo como:

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

// código}

}

3.12 Para saber mais

1) Vimos apenas os comandos mais usados para controle de �uxo. O Java ainda possui o do..while e oswitch. Pesquise sobre eles e diga quando é interessante usar cada um deles.

2) Algumas vezes, temos vários laços encadeados. Podemos utilizar o break para quebrar o laço mais in-terno. Mas, se quisermos quebrar um laço mais externo, teremos de encadear diversos ifs e seu código

�cará uma bagunça. O Java possui um artifício chamado labeled loops; pesquise sobre eles.

3) O que acontece se você tentar dividir um número inteiro por 0? E por 0.0?

4) Existe um caminho entre os tipos primitivos que indicam se há a necessidade ou não de casting entre

os tipos. Por exemplo, int -> long -> double (um int pode ser tratado como um double, mas não ocontrário). Pesquise (ou teste), e posicione os outros tipos primitivos nesse �uxo.

5) Além dos operadores de incremento, existem os de decremento, como --i e i--. Além desses, você podeusar instruções do tipo i += x e i -= x, o que essas instruções fazem? Teste.

Capítulo 3 - Variáveis primitivas e Controle de �uxo - Um bloco dentro do outro - Página 29

Material do Treinamento Java e Orientação a Objetos

3.13 Exercícios: Fixação de sintaxe

Mais exercícios de �xação de sintaxe. Para quem já conhece um pouco de Java, pode ser muito simples;

mas recomendamos fortemente que você faça os exercícios para se acostumar com erros de compilação,

mensagens do javac, convenção de código, etc...

Apesar de extremamente simples, precisamos praticar a sintaxe que estamos aprendendo. Para cada exercício,

crie um novo arquivo com extensão .java, e declare aquele estranho cabeçalho, dando nome a uma classe ecom um bloco main dentro dele:

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

// seu exercício vai aqui}

}

Não copie e cole de um exercício já existente! Aproveite para praticar.

1) Imprima todos os números de 150 a 300.

2) Imprima a soma de 1 até 1000.

3) Imprima todos os múltiplos de 3, entre 1 e 100.

4) Imprima os fatoriais de 1 a 10.

O fatorial de um número n é n * n-1 * n-2 ... até n = 1. Lembre-se de utilizar os parênteses.

O fatorial de 0 é 1

O fatorial de 1 é (0!) * 1 = 1

O fatorial de 2 é (1!) * 2 = 2

O fatorial de 3 é (2!) * 3 = 6

O fatorial de 4 é (3!) * 4 = 24

Faça um for que inicie uma variável n (número) como 1 e fatorial (resultado) como 1 e varia n de 1 até 10:

int fatorial = 1;for (int n = 1; n <= 10; n++) {

}

5) No código do exercício anterior, aumente a quantidade de números que terão os fatoriais impressos, até

20, 30, 40. Em um determinado momento, além desse cálculo demorar, vai começar a mostrar respostas

completamente erradas. Por quê?

Mude de int para long para ver alguma mudança.

Capítulo 3 - Variáveis primitivas e Controle de �uxo - Exercícios: Fixação de sintaxe - Página 30

Material do Treinamento Java e Orientação a Objetos

6) (opcional) Imprima os primeiros números da série de Fibonacci até passar de 100. A série de Fibonacci

é a seguinte: 0, 1, 1, 2, 3, 5, 8, 13, 21, etc... Para calculá-la, o primeiro elemento vale 0, o segundo vale 1, daí

por diante, o n-ésimo elemento vale o (n-1)-ésimo elemento somado ao (n-2)-ésimo elemento (ex: 8 = 5

+ 3).

7) (opcional) Escreva um programa que, dada uma variável x com algum valor inteiro, temos um novo x deacordo com a seguinte regra:

• se x é par, x = x / 2

• se x é impar, x = 3 * x + 1

• imprime x

• O programa deve parar quando x tiver o valor �nal de 1. Por exemplo, para x = 13, a saída será:40-> 20 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1

Imprimindo sem pular linha

Um detalhe importante é que uma quebra de linha é impressa toda vez que chamamos println.Para não pular uma linha, usamos o código a seguir:

System.out.print(variavel);

8) (opcional) Imprima a seguinte tabela, usando fors encadeados:

12 43 6 94 8 12 16n n*2 n*3 .... n*n

3.14 Desafios: Fibonacci

1) Faça o exercício da série de Fibonacci usando apenas duas variáveis.

Capítulo 3 - Variáveis primitivas e Controle de �uxo - Desa�os: Fibonacci - Página 31

Capítulo 4

Orientação a objetos básica

“Programação orientada a objetos é uma péssima ideia, que só poderia ter nascido na Califórnia.”– Edsger Dijkstra

Ao término deste capítulo, você será capaz de:

• dizer o que é e para que serve orientação a objetos;

• conceituar classes, atributos e comportamentos;

• entender o signi�cado de variáveis e objetos na memória.

4.1 Motivação: problemas do paradigma procedural

Orientação a objetos é uma maneira de programar que ajuda na organização e resolve muitos problemas

enfrentados pela programação procedural.

Consideremos o clássico problema da validação de um CPF. Normalmente, temos um formulário, no qual

recebemos essa informação, e depois temos que enviar esses caracteres para uma função que vai validá-lo,

como no pseudocódigo abaixo:

cpf = formulario->campo_cpfvalida(cpf)

Alguém te obriga a sempre validar esse CPF? Você pode, inúmeras vezes, esquecer de chamar esse validador.

Mais: considere que você tem 50 formulários e precise validar em todos eles o CPF. Se sua equipe tem 3

programadores trabalhando nesses formulários, quem �ca responsável por essa validação? Todos!

A situação pode piorar: na entrada de um novo desenvolvedor, precisaríamos avisá-lo que sempre deve-

mos validar o cpf de um formulário. É nesse momento que nascem aqueles guias de programação para o

Material do Treinamento Java e Orientação a Objetos

desenvolvedor que for entrar nesse projeto - às vezes, é um documento enorme. Em outras palavras, tododesenvolvedor precisa �car sabendo de uma quantidade enorme de informações, que, na maioria das vezes,

não está realmente relacionado à sua parte no sistema, mas ele precisa ler tudo isso, resultando um entravemuito grande!

Outra situação onde �cam claros os problemas da programação procedural, é quando nos encontramos na

necessidade de ler o código que foi escrito por outro desenvolvedor e descobrir como ele funciona interna-

mente. Um sistema bem encapsulado não deveria gerar essa necessidade. Em um sistema grande, simples-

mente não temos tempo de ler todo o código existente.

Considerando que você não erre nesse ponto e que sua equipe tenha uma comunicação muito boa (perceba

que comunicação excessiva pode ser prejudicial e atrapalhar o andamento), ainda temos outro problema:

imagine que, em todo formulário, você também quer que a idade do cliente seja validada - o cliente precisa

ter mais de 18 anos. Vamos ter de colocar um if... mas onde? Espalhado por todo seu código... Mesmo quese crie outra função para validar, precisaremos incluir isso nos nossos 50 formulários já existentes. Qual é a

chance de esquecermos em um deles? É muito grande.

A responsabilidade de veri�car se o cliente tem ou não tem 18 anos �cou espalhada por todo o seu código.

Seria interessante poder concentrar essa responsabilidade em um lugar só, para não ter chances de esquecer

isso.

Melhor ainda seria se conseguíssemos mudar essa validação e os outros programadores nem precisassem

�car sabendo disso. Emoutras palavras, eles criariam formulários e umúnico programador seria responsável

pela validação: os outros nem sabem da existência desse trecho de código. Impossível? Não, o paradigma da

orientação a objetos facilita tudo isso.

O problema do paradigma procedural é que não existe uma forma simples de criar conexão forte entre dados

e funcionalidades. No paradigma orientado a objetos é muito fácil ter essa conexão através dos recursos da

própria linguagem.

Quais as vantagens?

Orientação a objetos vai te ajudar emmuito em se organizar e escrevermenos, alémde concentrar

as responsabilidades nos pontos certos, �exibilizando sua aplicação, encapsulando a lógica denegócios.

Outra enorme vantagem, onde você realmente vai economizar montanhas de código, é o poli-mor�smo das referências, que veremos em um posterior capítulo.

Nos próximos capítulos, conseguiremos enxergar toda essa vantagem, mas, primeiramente é necessário co-

nhecer um pouco mais da sintaxe e da criação de tipos e referências em Java.

Capítulo 4 - Orientação a objetos básica - Motivação: problemas do paradigma procedural - Página 33

Material do Treinamento Java e Orientação a Objetos

4.2 Criando um tipo

Considere um programa para um banco, é bem fácil perceber que uma entidade extremamente importante

para o nosso sistema é a conta. Nossa ideia aqui é generalizarmos alguma informação, juntamente com

funcionalidades que toda conta deve ter.

O que toda conta tem e é importante para nós?

• número da conta

• nome do dono da conta

• saldo

• limite

O que toda conta faz e é importante para nós? Isto é, o que gostaríamos de “pedir à conta"?

• saca uma quantidade x

• deposita uma quantidade x

• imprime o nome do dono da conta

• devolve o saldo atual

• transfere uma quantidade x para uma outra conta y

• devolve o tipo de conta

Com isso, temos o projeto de uma conta bancária. Podemos pegar esse projeto e acessar seu saldo? Não. O

que temos ainda é o projeto. Antes, precisamos construir uma conta, para poder acessar o que ela tem, epedir a ela que faça algo.

Capítulo 4 - Orientação a objetos básica - Criando um tipo - Página 34

Material do Treinamento Java e Orientação a Objetos

Repare na �gura: apesar do papel do lado esquerdo especi�car uma Conta, essa especi�cação é uma Conta?

Nós depositamos e sacamos dinheiro desse papel? Não. Utilizamos a especi�cação da Conta para poder criar

instâncias que realmente são contas, onde podemos realizar as operações que criamos.

Apesar de declararmos que toda conta tem um saldo, um número e uma agência no pedaço de papel (como

à esquerda na �gura), são nas instâncias desse projeto que realmente há espaço para armazenar esses valores.

Ao projeto da conta, isto é, a de�nição da conta, damos o nome de classe. Ao que podemos construir a partirdesse projeto, as contas de verdade, damos o nome de objetos.

A palavra classe vem da taxonomia da biologia. Todos os seres vivos de uma mesma classe biológica têmuma série de atributos e comportamentos em comum, mas não são iguais, podem variar nos valores dessesatributos e como realizam esses comportamentos.

HomoSapiens de�ne um grupo de seres que possuem características em comum, porém a de�nição (a ideia,o conceito) de um Homo Sapiens é um ser humano? Não. Tudo está especi�cado na classe Homo Sapiens,mas se quisermos mandar alguém correr, comer, pular, precisaremos de uma instância de Homo Sapiens,ou então de um objeto do tipoHomo Sapiens.

Um outro exemplo: uma receita de bolo. A pergunta é certeira: você come uma receita de bolo? Não.

Precisamos instanciá-la, criar um objeto bolo a partir dessa especi�cação (a classe) para utilizá-la. Podemos

Capítulo 4 - Orientação a objetos básica - Criando um tipo - Página 35

Material do Treinamento Java e Orientação a Objetos

criar centenas de bolos a partir dessa classe (a receita, no caso), eles podem ser bem semelhantes, alguns até

idênticos, mas são objetos diferentes.

Podemos fazer milhares de analogias semelhantes. A planta de uma casa é uma casa? De�nitivamente não.

Não podemos morar dentro da planta de uma casa, nem podemos abrir sua porta ou pintar suas paredes.

Precisamos, antes, construir instâncias a partir dessa planta. Essas instâncias, sim, podemos pintar, decorar

ou morar dentro.

Pode parecer óbvio, mas a di�culdade inicial do paradigma da orientação a objetos é justo saber distinguir o

que é classe e o que é objeto. É comum o iniciante utilizar, obviamente de forma errada, essas duas palavras

como sinônimos.

4.3 Uma classe em Java

Vamos começar apenas com o que uma Conta tem, e não com o que ela faz (veremos logo em seguida).

Um tipo desses, como o especi�cado de Conta acima, pode ser facilmente traduzido para Java:

class Conta {int numero;String dono;double saldo;double limite;

// ..}

String

String é uma classe em Java. Ela guarda uma cadeia de caracteres, uma frase completa. Como es-

tamos ainda aprendendo o que é uma classe, entenderemos com detalhes a classe String apenasem capítulos posteriores.

Por enquanto, declaramos o que toda conta deve ter. Estes são os atributos que toda conta, quando criada,vai ter. Repare que essas variáveis foram declaradas fora de um bloco, diferente do que fazíamos quando

tinha aquele main. Quando uma variável é declarada diretamente dentro do escopo da classe, é chamada de

variável de objeto, ou atributo.

4.4 Criando e usando um objeto

Já temos uma classe em Java que especi�ca o que todo objeto dessa classe deve ter. Mas como usá-la? Além

dessa classe, ainda teremos o Programa.java e a partir dele é que vamos utilizar a classe Conta.

Capítulo 4 - Orientação a objetos básica - Uma classe em Java - Página 36

Material do Treinamento Java e Orientação a Objetos

Para criar (construir, instanciar) uma Conta, basta usar a palavra chave new. Devemos utilizar também osparênteses, que descobriremos o que fazem exatamente em um capítulo posterior:

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

new Conta();}

}

Bem, o código acima cria um objeto do tipo Conta, mas como acessar esse objeto que foi criado? Precisamoster alguma forma de nos referenciarmos a esse objeto. Precisamos de uma variável:

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

Conta minhaConta;minhaConta = new Conta();

}}

Pode parecer estranho escrevermos duas vezes Conta: uma vez na declaração da variável e outra vez no usodo new. Mas há um motivo, que em breve entenderemos.

Através da variável minhaConta, podemos acessar o objeto recém criado para alterar seu dono, seu saldo, etc:

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

Conta minhaConta;minhaConta = new Conta();

minhaConta.dono = "Duke";minhaConta.saldo = 1000.0;

System.out.println("Saldo atual: " + minhaConta.saldo);}

}

É importante �xar que o ponto foi utilizado para acessar algo em minhaConta. A minhaConta pertence aoDuke, e tem saldo de mil reais.

4.5 Métodos

Dentro da classe, também declararemos o que cada conta faz e como isto é feito - os comportamentos que

cada classe tem, isto é, o que ela faz. Por exemplo, de que maneira que uma Conta saca dinheiro? Especi�ca-

remos isso dentro da própria classe Conta, e não em um local desatrelado das informações da própria Conta.

Capítulo 4 - Orientação a objetos básica - Métodos - Página 37

Material do Treinamento Java e Orientação a Objetos

É por isso que essas “funções” são chamadas demétodos. Pois é a maneira de fazer uma operação com umobjeto.

Queremos criar um método que saca uma determinada quantidade e não devolve nenhuma informaçãopara quem acionar esse método:

1 class Conta {2 double salario;3 // ... outros atributos ...4

5 void saca(double quantidade) {6 double novoSaldo = this.saldo - quantidade;7 this.saldo = novoSaldo;8 }9 }

A palavra chave void diz que, quando você pedir para a conta sacar uma quantia, nenhuma informação seráenviada de volta a quem pediu.

Quando alguém pedir para sacar, ele também vai dizer quanto quer sacar. Por isso precisamos declarar o

método com algo dentro dos parênteses - o que vai aí dentro é chamado de argumento do método (ouparâmetro). Essa variável é uma variável comum, chamada também de temporária ou local, pois, ao �nalda execução desse método, ela deixa de existir.

Dentro do método, estamos declarando uma nova variável. Essa variável, assim como o argumento, vai

morrer no �m do método, pois este é seu escopo. No momento que vamos acessar nosso atributo, usamos a

palavra chave this para mostrar que esse é um atributo, e não uma simples variável. (veremos depois que éopcional)

Repare que, nesse caso, a conta pode estourar o limite �xado pelo banco. Mais para frente, evitaremos essa

situação, e de uma maneira muito elegante.

Da mesma forma, temos o método para depositar alguma quantia:

1 class Conta {2 // ... outros atributos e métodos ...3

4 void deposita(double quantidade) {5 this.saldo += quantidade;6 }7 }

Observe que não usamos uma variável auxiliar e, além disso, usamos a abreviação += para deixar o métodobem simples. O += soma quantidade ao valor antigo do saldo e guarda no próprio saldo, o valor resultante.

Para mandar uma mensagem ao objeto e pedir que ele execute um método, também usamos o ponto. O

termo usado para isso é invocação de método.

Capítulo 4 - Orientação a objetos básica - Métodos - Página 38

Material do Treinamento Java e Orientação a Objetos

O código a seguir saca dinheiro e depois deposita outra quantia na nossa conta:

1 class TestaAlgunsMetodos {2 public static void main(String[] args) {3 // criando a conta4 Conta minhaConta;5 minhaConta = new Conta();6

7 // alterando os valores de minhaConta8 minhaConta.dono = "Duke";9 minhaConta.saldo = 1000;10

11 // saca 200 reais12 minhaConta.saca(200);13

14 // deposita 500 reais15 minhaConta.deposita(500);16 System.out.println(minhaConta.saldo);17 }18 }

Uma vez que seu saldo inicial é 1000 reais, se sacarmos 200 reais, depositarmos 500 reais e imprimirmos o

valor do saldo, o que será impresso?

4.6 Métodos com retorno

Ummétodo sempre tem que de�nir o que retorna, nem que de�na que não há retorno, como nos exemplos

anteriores onde estávamos usando o void.

Ummétodo pode retornar um valor para o código que o chamou. No caso do nosso método saca , podemosdevolver um valor booleano indicando se a operação foi bem sucedida.

1 class Conta {2 // ... outros métodos e atributos ...3

4 boolean saca(double valor) {5 if (this.saldo < valor) {6 return false;7 }8 else {9 this.saldo = this.saldo - valor;10 return true;11 }

Capítulo 4 - Orientação a objetos básica - Métodos com retorno - Página 39

Material do Treinamento Java e Orientação a Objetos

12 }13 }

A declaração do método mudou! O método saca não tem void na frente. Isto quer dizer que, quando éacessado, ele devolve algum tipo de informação. No caso, um boolean. A palavra chave return indica que ométodo vai terminar ali, retornando tal informação.

Exemplo de uso:

minhaConta.saldo = 1000;boolean consegui = minhaConta.saca(2000);if (consegui) {

System.out.println("Consegui sacar");} else {

System.out.println("Não consegui sacar");}

Ou então, posso eliminar a variável temporária, se desejado:

minhaConta.saldo = 1000;if (minhaConta.saca(2000)) {

System.out.println("Consegui sacar");} else {

System.out.println("Não consegui sacar");}

Mais adiante, veremos que algumas vezes é mais interessante lançar uma exceção (exception) nesses casos.

Meu programa pode manter na memória não apenas uma conta, como mais de uma:

1 class TestaDuasContas {2 public static void main(String[] args) {3

4 Conta minhaConta;5 minhaConta = new Conta();

Capítulo 4 - Orientação a objetos básica - Métodos com retorno - Página 40

Material do Treinamento Java e Orientação a Objetos

6 minhaConta.saldo = 1000;7

8 Conta meuSonho;9 meuSonho = new Conta();10 meuSonho.saldo = 1500000;11 }12 }

4.7 Objetos são acessados por referências

Quando declaramos uma variável para associar a um objeto, na verdade, essa variável não guarda o objeto, e

sim uma maneira de acessá-lo, chamada de referência.

É por essemotivo que, diferente dos tipos primitivos como int e long, precisamos dar new depois de declaradaa variável:

1 public static void main(String args[]) {2 Conta c1;3 c1 = new Conta();4

5 Conta c2;6 c2 = new Conta();7 }

O correto aqui, é dizer que c1 se refere a um objeto. Não é correto dizer que c1 é um objeto, pois c1 é umavariável referência, apesar de, depois de um tempo, os programadores Java falarem “Tenho um objeto c dotipo Conta”, mas apenas para encurtar a frase “Tenho uma referência c a um objeto do tipo Conta”.

Basta lembrar que, em Java, uma variável nunca é um objeto. Não há, no Java, uma maneira de criarmos oque é conhecido como “objeto pilha” ou “objeto local”, pois todo objeto em Java, sem exceção, é acessado poruma variável referência.

Esse código nos deixa na seguinte situação:

Conta c1;c1 = new Conta();

Conta c2;c2 = new Conta();

Capítulo 4 - Orientação a objetos básica - Objetos são acessados por referências - Página 41

Material do Treinamento Java e Orientação a Objetos

Internamente, c1 e c2 vão guardar um número que identi�ca em que posição da memória aquela Conta seencontra. Dessamaneira, ao utilizarmos o “.” para navegar, o Java vai acessar a Conta que se encontra naquelaposição de memória, e não uma outra.

Para quem conhece, é parecido com um ponteiro, porém você não pode manipulá-lo como um número e

nem utilizá-lo para aritmética, ela é tipada.

Um outro exemplo:

1 class TestaReferencias {2 public static void main(String args[]) {3 Conta c1 = new Conta();4 c1.deposita(100);5

6 Conta c2 = c1; // linha importante!7 c2.deposita(200);8

9 System.out.println(c1.saldo);10 System.out.println(c2.saldo);11 }12 }

Qual é o resultado do código acima? O que aparece ao rodar?

O que acontece aqui? O operador = copia o valor de uma variável. Mas qual é o valor da variável c1? Éo objeto? Não. Na verdade, o valor guardado é a referência (endereço) de onde o objeto se encontra namemória principal.

Na memória, o que acontece nesse caso:

Conta c1 = new Conta();Conta c2 = c1;

Capítulo 4 - Orientação a objetos básica - Objetos são acessados por referências - Página 42

Material do Treinamento Java e Orientação a Objetos

Quando �zemos c2 = c1, c2 passa a fazer referência para o mesmo objeto que c1 referencia nesse instante.

Então, nesse código em especí�co, quando utilizamos c1 ou c2 estamos nos referindo exatamente aomesmoobjeto! Elas são duas referências distintas, porém apontam para omesmo objeto! Compará-las com “==” vainos retornar true, pois o valor que elas carregam é o mesmo!

Outra forma de perceber, é que demos apenas um new, então só pode haver um objeto Conta na memória.

Atenção: não estamos discutindo aqui a utilidade de fazer uma referência apontar pro mesmo objeto queoutra. Essa utilidade �cará mais clara quando passarmos variáveis do tipo referência como argumento para

métodos.

new

O que exatamente faz o new?

O new executa uma série de tarefas, que veremos mais adiante.

Mas, para melhor entender as referências no Java, saiba que o new, depois de alocar a memóriapara esse objeto, devolve uma “�echa”, isto é, um valor de referência. Quando você atribui isso a

uma variável, essa variável passa a se referir para esse mesmo objeto.

Podemos então ver outra situação:

1 public static void main(String args[]) {2 Conta c1 = new Conta();3 c1.dono = "Duke";4 c1.saldo = 227;5

6 Conta c2 = new Conta();7 c2.dono = "Duke";8 c2.saldo = 227;9

10 if (c1 == c2) {11 System.out.println("Contas iguais");12 }13 }

Capítulo 4 - Orientação a objetos básica - Objetos são acessados por referências - Página 43

Material do Treinamento Java e Orientação a Objetos

Ooperador == compara o conteúdo das variáveis, mas essas variáveis não guardam o objeto, e sim o endereçoem que ele se encontra. Como em cada uma dessas variáveis guardamos duas contas criadas diferentemente,

elas estão em espaços diferentes da memória, o que faz o teste no if valer false. As contas podem serequivalentes no nosso critério de igualdade, porém elas não são omesmo objeto. Quando se trata de objetos,

pode �car mais fácil pensar que o == compara se os objetos (referências, na verdade) são o mesmo, e não sesão iguais.

Para saber se dois objetos têm o mesmo conteúdo, você precisa comparar atributo por atributo. Veremos

uma solução mais elegante para isso também.

4.8 Ométodo transfere()

E se quisermos ter um método que transfere dinheiro entre duas contas? Podemos �car tentados a criar um

método que recebe dois parâmetros: conta1 e conta2 do tipo Conta. Mas cuidado: assim estamos pensandode maneira procedural.

A ideia é que, quando chamarmos o método transfere, já teremos um objeto do tipo Conta (o this), por-tanto o método recebe apenas um parâmetro do tipo Conta, a Conta destino (além do valor):

class Conta {

// atributos e métodos...

void transfere(Conta destino, double valor) {this.saldo = this.saldo - valor;destino.saldo = destino.saldo + valor;

}}

Capítulo 4 - Orientação a objetos básica - O método transfere() - Página 44

Material do Treinamento Java e Orientação a Objetos

Para deixar o código mais robusto, poderíamos veri�car se a conta possui a quantidade a ser transferida

disponível. Para �car ainda mais interessante, você pode chamar os métodos deposita e saca já existentespara fazer essa tarefa:

class Conta {

// atributos e métodos...

boolean transfere(Conta destino, double valor) {boolean retirou = this.saca(valor);if (retirou == false) {

// não deu pra sacar!return false;

}else {

destino.deposita(valor);return true;

}}

}

Quando passamos uma Conta como argumento, o que será que acontece na memória? Será que o objeto éclonado?

No Java, a passagem de parâmetro funciona como uma simples atribuição como no uso do “=”. Então, esse

parâmetro vai copiar o valor da variável do tipo Conta que for passado como argumento. E qual é o valor de

Capítulo 4 - Orientação a objetos básica - O método transfere() - Página 45

Material do Treinamento Java e Orientação a Objetos

uma variável dessas? Seu valor é um endereço, uma referência, nunca um objeto. Por isso não há cópia de

objetos aqui.

Esse último código poderia ser escrito com uma sintaxe muito mais sucinta. Como?

Transfere Para

Perceba que o nome deste método poderia ser transferePara ao invés de só transfere. A cha-mada do método �ca muito mais natural, é possível ler a frase em português que ela tem um

sentido:

conta1.transferePara(conta2, 50);

A leitura deste código seria “Conta1 transfere para conta2 50 reais”.

4.9 Continuando com atributos

As variáveis do tipo atributo, diferentemente das variáveis temporárias (declaradas dentro de um método),

recebem um valor padrão. No caso numérico, valem 0, no caso de boolean, valem false.

Você também pode dar valores default, como segue:

1 class Conta {2 int numero = 1234;3 String dono = "Duke";4 String cpf = "123.456.789-10";5 double saldo = 1000;6 double limite = 1000;7 }

Nesse caso, quando você criar uma conta, seus atributos já estão “populados” com esses valores colocados.

Imagine que comecemos a aumentar nossa classe Conta e adicionar nome, sobrenome e cpf do cliente donoda conta. Começaríamos a ter muitos atributos... e, se você pensar direito, uma Conta não tem nome, nemsobrenome nem cpf, quem tem esses atributos é um Cliente. Então podemos criar uma nova classe e fazeruma composição

Seus atributos também podem ser referências para outras classes. Suponha a seguinte classe Cliente:

1 class Cliente {2 String nome;3 String sobrenome;

Capítulo 4 - Orientação a objetos básica - Continuando com atributos - Página 46

Material do Treinamento Java e Orientação a Objetos

4 String cpf;5 }

1 class Conta {2 int numero;3 double saldo;4 double limite;5 Cliente titular;6 // ..7 }

E dentro do main da classe de teste:

1 class Teste {2 public static void main(String[] args) {3 Conta minhaConta = new Conta();4 Cliente c = new Cliente();5 minhaConta.titular = c;6 // ...7 }8 }

Aqui, simplesmente houve uma atribuição. O valor da variável c é copiado para o atributo titular do objetoao qual minhaConta se refere. Em outras palavras, minhaConta tem uma referência ao mesmo Cliente que cse refere, e pode ser acessado através de minhaConta.titular.

Você pode realmente navegar sobre toda essa estrutura de informação, sempre usando o ponto:

Cliente clienteDaMinhaConta = minhaConta.titular;clienteDaMinhaConta.nome = "Duke";

Ou ainda, pode fazer isso de uma forma mais direta e até mais elegante:

minhaConta.titular.nome = "Duke";

Um sistema orientado a objetos é um grande conjunto de classes que vai se comunicar, delegando responsa-

bilidades para quem for mais apto a realizar determinada tarefa. A classe Banco usa a classe Conta que usa aclasse Cliente, que usa a classe Endereco. Dizemos que esses objetos colaboram, trocando mensagens entresi. Por isso acabamos tendomuitas classes em nosso sistema, e elas costumam ter um tamanho relativamente

curto.

Mas, e se dentro do meu código eu não desse new em Cliente e tentasse acessá-lo diretamente?

Capítulo 4 - Orientação a objetos básica - Continuando com atributos - Página 47

Material do Treinamento Java e Orientação a Objetos

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

Conta minhaConta = new Conta();

minhaConta.titular.nome = "Manoel";// ...

}}

Quando damos new em um objeto, ele o inicializa com seus valores default, 0 para números, false paraboolean e null para referências. null é uma palavra chave em java, que indica uma referência para nenhumobjeto.

Se, em algum caso, você tentar acessar um atributo ou método de alguém que está se referenciando para

null, você receberá um erro durante a execução (NullPointerException, que veremos mais à frente). Dapara perceber, então, que o new não traz um efeito cascata, a menos que você dê um valor default (ou useconstrutores, que também veremos mais a frente):

1 class Conta {2 int numero;3 double saldo;4 double limite;5 Cliente titular = new Cliente(); // quando chamarem new Conta,6 //havera um new Cliente para ele.7 }

Com esse código, toda nova Conta criada já terá um novo Cliente associado, sem necessidade de instanciá-lo logo em seguida da instanciação de uma Conta. Qual alternativa você deve usar? Depende do caso: para

Capítulo 4 - Orientação a objetos básica - Continuando com atributos - Página 48

Material do Treinamento Java e Orientação a Objetos

toda nova Conta você precisa de um novo Cliente? É essa pergunta que deve ser respondida. Nesse nossocaso a resposta é não, mas depende do nosso problema.

Atenção: para quem não está acostumado com referências, pode ser bastante confuso pensar sempre emcomo os objetos estão namemória para poder tirar as conclusões de o que ocorrerá ao executar determinado

código, por mais simples que ele seja. Com tempo, você adquire a habilidade de rapidamente saber o efeito

de atrelar as referências, sem ter de gastar muito tempo para isso. É importante, nesse começo, você estar

sempre pensando no estado da memória. E realmente lembrar que, no Java "uma variável nunca carrega umobjeto, e sim uma referência para ele” facilita muito.

4.10 Para saber mais: Uma Fábrica de Carros

Além do Banco que estamos criando, vamos ver como �cariam certas classes relacionadas a uma fábrica decarros. Vamos criar uma classe Carro, com certos atributos, que descrevem suas características, e com certosmétodos, que descrevem seu comportamento.

1 class Carro {2 String cor;3 String modelo;4 double velocidadeAtual;5 double velocidadeMaxima;6

7 //liga o carro8 void liga() {9 System.out.println("O carro está ligado");10 }11

12 //acelera uma certa quantidade13 void acelera(double quantidade) {14 double velocidadeNova = this.velocidadeAtual + quantidade;15 this.velocidadeAtual = velocidadeNova;16 }17

18 //devolve a marcha do carro19 int pegaMarcha() {20 if (this.velocidadeAtual < 0) {21 return -1;22 }23 if (this.velocidadeAtual >= 0 && this.velocidadeAtual < 40) {24 return 1;25 }26 if (this.velocidadeAtual >= 40 && this.velocidadeAtual < 80) {27 return 2;28 }

Capítulo 4 - Orientação a objetos básica - Para saber mais: Uma Fábrica de Carros - Página 49

Material do Treinamento Java e Orientação a Objetos

29 return 3;30 }31 }

Vamos testar nosso Carro em um novo programa:

1 class TestaCarro {2 public static void main(String[] args) {3 Carro meuCarro;4 meuCarro = new Carro();5 meuCarro.cor = "Verde";6 meuCarro.modelo = "Fusca";7 meuCarro.velocidadeAtual = 0;8 meuCarro.velocidadeMaxima = 80;9

10 // liga o carro11 meuCarro.liga();12

13 // acelera o carro14 meuCarro.acelera(20);15 System.out.println(meuCarro.velocidadeAtual);16 }17 }

Nosso carro pode conter também um Motor:

1 class Motor {2 int potencia;3 String tipo;4 }

1 class Carro {2 String cor;3 String modelo;4 double velocidadeAtual;5 double velocidadeMaxima;6 Motor motor;7

8 // ..9 }

Podemos, criar diversos Carros e mexer com seus atributos e métodos, assim como �zemos no exemplo do

Banco.

Capítulo 4 - Orientação a objetos básica - Para saber mais: Uma Fábrica de Carros - Página 50

Material do Treinamento Java e Orientação a Objetos

4.11 Um pouco mais...

1) Quando declaramos uma classe, um método ou um atributo, podemos dar o nome que quisermos, se-

guindo uma regra. Por exemplo, o nome de um método não pode começar com um número. Pesquise

sobre essas regras.

2) Como você pode ter reparado, sempre damos nomes às variáveis com letras minúsculas. É que existem

convenções de código, dadas pela Sun, para facilitar a legibilidade do código entre programadores. Essaconvenção émuito seguida. Pesquise sobre ela no http://java.sun.com , procure por “code conventions”.

3) É necessário usar a palavra chave this quando for acessar um atributo? Para que, então, utilizá-la?

4) O exercício a seguir pedirá paramodelar um “funcionário”. Existe umpadrão para representar suas classes

em diagramas, que é amplamente utilizado, chamado UML. Pesquise sobre ele.

4.12 Exercícios: Orientação aObjetos

Omodelo de funcionários a seguir será utilizado para os exercícios de alguns dos posteriores capítulos.

O objetivo aqui é criar um sistema para gerenciar os funcionários do Banco.Os exercícios desse capítulo são extremamente importantes.

1) Modele um funcionário. Ele deve ter o nome do funcionário, o departamento onde trabalha, seu salário

(double), a data de entrada no banco (String) e seu RG (String).

Você deve criar alguns métodos de acordo com sua necessidade. Além deles, crie um método

recebeAumento que aumenta o salario do funcionário de acordo com o parâmetro passado como ar-gumento. Crie também um método calculaGanhoAnual, que não recebe parâmetro algum, devolvendoo valor do salário multiplicado por 12..

A ideia aqui é apenas modelar, isto é, só identi�que que informações são importantes e o que um funci-

onário faz. Desenhe no papel tudo o que um Funcionario tem e tudo que ele faz.

2) Transforme omodelo acima em uma classe Java. Teste-a, usando uma outra classe que tenha o main. Vocêdeve criar a classe do funcionário com o nome Funcionario, mas pode nomear como quiser a classe detestes. A de teste deve possuir o método main.

Um esboço da classe:

class Funcionario {

double salario;// seus outros atributos e métodos

void recebeAumento(double aumento) {// o que fazer aqui dentro?

Capítulo 4 - Orientação a objetos básica - Um pouco mais... - Página 51

Material do Treinamento Java e Orientação a Objetos

}

double calculaGanhoAnual() {// o que fazer aqui dentro?

}}

Você pode (e deve) compilar seu arquivo java sem que você ainda tenha terminado sua classe

Funcionario. Isso evitará que você receba dezenas de erros de compilação de uma vez só. Crie a classeFuncionario, coloque seus atributos e, antes de colocar qualquer método, compile o arquivo java. O ar-quivo Funcionario.class será gerado, mas não podemos “executá-lo” já que essa classe não temum main.De qualquer forma, a vantagem é que assim veri�camos que nossa classe Funcionario já está tomandoforma e está escrita em sintaxe correta.

Esse é um processo incremental. Procure desenvolver assim seus exercícios, para não descobrir só no �m

do caminho que algo estava muito errado.

Um esboço da classe que possui o main:

1 class TestaFuncionario {2

3 public static void main(String[] args) {4 Funcionario f1 = new Funcionario();5

6 f1.nome = "Hugo";7 f1.salario = 100;8 f1.recebeAumento(50);9

10 System.out.println("salario atual:" + f1.salario);11 System.out.println("ganho anual:" + f1.calculaGanhoAnual());12 }13 }

Incremente essa classe. Faça outros testes, imprima outros atributos e invoque os métodos que você criou

a mais.

Capítulo 4 - Orientação a objetos básica - Exercícios: Orientação a Objetos - Página 52

Material do Treinamento Java e Orientação a Objetos

Lembre-se de seguir a convenção java, isso é importantíssimo. Isto é, preste atenção nas maiúscu-

las e minúsculas, seguindo o seguinte exemplo: nomeDeAtributo, nomeDeMetodo, nomeDeVariavel,NomeDeClasse, etc...

Todas as classes no mesmo arquivo?

Você até pode colocar todas as classes no mesmo arquivo e apenas compilar esse arquivo. Ele vai

gerar um .class para cada classe presente nele.

Porém, por uma questão de organização, é boa prática criar um arquivo .java para cada classe.Em capítulos posteriores, veremos também determinados casos nos quais você será obrigado adeclarar cada classe em um arquivo separado.

Essa separação não é importante nesse momento do aprendizado, mas se quiser ir praticando

sem ter que compilar classe por classe, você pode dizer para o javac compilar todos os arquivosjava de uma vez:

javac *.java

3) Crie ummétodo mostra(), que não recebe nem devolve parâmetro algum e simplesmente imprime todosos atributos do nosso funcionário. Dessa maneira, você não precisa �car copiando e colando um monte

de System.out.println() para cada mudança e teste que �zer com cada um de seus funcionários, vocêsimplesmente vai fazer:

Funcionario f1 = new Funcionario();// brincadeiras com f1....f1.mostra();

Veremos mais a frente o método toString, que é uma solução muito mais elegante para mostrar a repre-sentação de um objeto como String, além de não jogar tudo pro System.out (só se você desejar).

O esqueleto do método �caria assim:

class Funcionario {

// seus outros atributos e métodos

void mostra() {System.out.println("Nome: " + this.nome);// imprimir aqui os outros atributos...// também pode imprimir this.calculaGanhoAnual()

}

Capítulo 4 - Orientação a objetos básica - Exercícios: Orientação a Objetos - Página 53

Material do Treinamento Java e Orientação a Objetos

}

4) Construa dois funcionários com o new e compare-os com o ==. E se eles tiverem os mesmos atributos?Para isso você vai precisar criar outra referência:

Funcionario f1 = new Funcionario();f1.nome = "Danilo";f1.salario = 100;

Funcionario f2 = new Funcionario();f2.nome = "Danilo";f2.salario = 100;

if (f1 == f2) {System.out.println("iguais");

} else {System.out.println("diferentes");

}

5) Crie duas referências para omesmo funcionário, compare-os com o ==. Tire suas conclusões. Para criarduas referências pro mesmo funcionário:

Funcionario f1 = new Funcionario():f1.nome = "Hugo";f1.salario = 100;

Funcionario f2 = f1;

O que acontece com o if do exercício anterior?

6) (opcional) Em vez de utilizar uma String para representar a data, crie uma outra classe, chamada Data.Ela possui 3 campos int, para dia, mês e ano. Faça com que seu funcionário passe a usá-la. (é parecidocom o último exemplo, em que a Conta passou a ter referência para um Cliente).

class Funcionario {Data dataDeEntrada; // qual é o valor default aqui?// seus outros atributos e métodos

}

class Data {int dia;int mes;int ano;

}

Modi�que sua classe TestaFuncionario para que você crie uma Data e atribua ela ao Funcionario:

Funcionario f1 = new Funcionario();//...

Capítulo 4 - Orientação a objetos básica - Exercícios: Orientação a Objetos - Página 54

Material do Treinamento Java e Orientação a Objetos

Data data = new Data(); // ligação!f1.dataDeEntrada = data;

Faça o desenho do estado da memória quando criarmos um Funcionario.

7) (opcional) Modi�que seu método mostra para que ele imprima o valor da dataDeEntrada daqueleFuncionario:

class Funcionario {

// seus outros atributos e métodosData dataDeEntrada;

void mostra() {System.out.println("Nome: " + this.nome);// imprimir aqui os outros atributos...

System.out.println("Dia: " + this.dataDeEntrada.dia);System.out.println("Mês: " + this.dataDeEntrada.mes);System.out.println("Ano: " + this.dataDeEntrada.ano);

}}

Teste-o. O que acontece se chamarmos o método mostra antes de atribuirmos uma data para esteFuncionario?

8) (opcional) O que acontece se você tentar acessar um atributo diretamente na classe? Como, por exemplo:

Funcionario.salario = 1234;

Esse código faz sentido? E este:

Funcionario.calculaGanhoAtual();

Faz sentido perguntar para o esquema do Funcionario seu valor anual?

9) (opcional-avançado)Crie ummétodona classe Data que devolva o valor formatado da data, isto é, devolvauma String com “dia/mes/ano”. Isso para que o método mostra da classe Funcionario possa �car assim:

class Funcionario {// atributos e metodos

void mostra() {// imprime outros atributos...System.out.println("Data de entrada: " + this.dataDeEntrada.formatada());

}}

Capítulo 4 - Orientação a objetos básica - Exercícios: Orientação a Objetos - Página 55

Material do Treinamento Java e Orientação a Objetos

4.13 Desafios

1) Um método pode chamar ele mesmo. Chamamos isso de recursão. Você pode resolver a série de Fibo-nacci usando um método que chama ele mesmo. O objetivo é você criar uma classe, que possa ser usada

da seguinte maneira:

Fibonacci fibonacci = new Fibonacci();for (int i = 1; i <= 6; i++) {

int resultado = fibonacci.calculaFibonacci(i);System.out.println(resultado);

}

Aqui imprimirá a sequência de Fibonacci até a sexta posição, isto é: 1, 1, 2, 3, 5, 8.

Este método calculaFibonacci não pode ter nenhum laço, só pode chamar ele mesmo como método.Pense nele como uma função, que usa a própria função para calcular o resultado.

2) Por que o modo acima é extremamente mais lento para calcular a série do que o modo iterativo (que se

usa um laço)?

3) Escreva o método recursivo novamente, usando apenas uma linha. Para isso, pesquise sobre o operadorcondicional ternário. (ternary operator)

4.14 Fixando o conhecimento

Oobjetivo dos exercícios a seguir é �xar o conceito de classes e objetos, métodos e atributos. Dada a estrutura

de uma classe, basta traduzi-la para a linguagem Java e fazer uso de um objeto da mesma em um programa

simples.

Se você está com di�culdade em alguma parte desse capítulo, aproveite e treine tudo o que vimos nos peque-

nos programas abaixo:

1) Programa 1

Classe: PessoaAtributos: nome, idade.Método: void fazAniversario()

Crie uma pessoa, coloque seu nome e idade iniciais, faça alguns aniversários (aumentando a idade) e

imprima seu nome e sua idade.

2) Programa 2

Classe: PortaAtributos: aberta, cor, dimensaoX, dimensaoY, dimensaoZMétodos: void abre()

void fecha()

Capítulo 4 - Orientação a objetos básica - Desa�os - Página 56

Material do Treinamento Java e Orientação a Objetos

void pinta(String s)boolean estaAberta()

Crie uma porta, abra e feche a mesma, pinte-a de diversas cores, altere suas dimensões e use o método

estaAberta para veri�car se ela está aberta.

3) Programa 3

Classe: CasaAtributos: cor, porta1, porta2, porta3Método: void pinta(String s),

int quantasPortasEstaoAbertas()

Crie uma casa e pinte-a. Crie três portas e coloque-as na casa; abra e feche as mesmas como desejar.

Utilize o método quantasPortasEstaoAbertas para imprimir o número de portas abertas.

Capítulo 4 - Orientação a objetos básica - Fixando o conhecimento - Página 57

Capítulo 5

Um pouco de arrays

“O homem esquecerá antes a morte do pai que a perda da propriedade"–Maquiavel

Ao término desse capítulo, você será capaz de:

• declarar e instanciar arrays;

• popular e percorrer arrays.

5.1 O problema

Dentro de um bloco, podemos declarar diversas variáveis e usá-las:

int idade1;int idade2;int idade3;int idade4;

Isso pode se tornar um problema quando precisamos mudar a quantidade de variáveis a serem declaradas

de acordo com um parâmetro. Esse parâmetro pode variar, como por exemplo, a quantidade de número

contidos num bilhete de loteria. Um jogo simples possui 6 números, mas podemos comprar um bilhete mais

caro, com 7 números ou mais.

Para facilitar esse tipo de caso podemos declarar um vetor (array) de inteiros:

int[] idades;

Material do Treinamento Java e Orientação a Objetos

O int[] é um tipo. Uma array é sempre um objeto, portanto, a variável idades é uma referência. Vamosprecisar criar um objeto para poder usar a array. Como criamos o objeto-array?

idades = new int[10];

O que �zemos foi criar uma array de int de 10 posições e atribuir o endereço no qual ela foi criada. Podemos

ainda acessar as posições do array:

idades[5] = 10;

Ocódigo acima altera a sexta posição do array. No Java, os índices do array vão de 0 a n-1, onde n é o tamanho

dado nomomento em que você criou o array. Se você tentar acessar uma posição fora desse alcance, um erro

ocorrerá durante a execução.

Arrays - um problema no aprendizado de muitas linguagens

Aprender a usar arrays pode ser um problema em qualquer linguagem. Isso porque envolve uma

série de conceitos, sintaxe e outros. No Java, muitas vezes utilizamos outros recursos em vez de

arrays, em especial os pacotes de coleções do Java, que veremos no capítulo 11. Portanto, �que

tranquilo caso não consiga digerir toda sintaxe das arrays num primeiro momento.

No caso do bilhete de loteria, podemos utilizar o mesmo recurso. Mais ainda, a quantidade de números do

nosso bilhete pode ser de�nido por uma variável. Considere que n indica quantos números nosso bilheteterá, podemos então fazer:

int numerosDoBilhete[] = new int[n];

E assim podemos acessar e modi�car os inteiros com índice de 0 a n-1.

5.2 Arrays de referências

É comum ouvirmos “array de objetos”. Porém quando criamos uma array de alguma classe, ela possui refe-

rências. O objeto, como sempre, está na memória principal e, na sua array, só �cam guardadas as referências(endereços).

Capítulo 5 - Um pouco de arrays - Arrays de referências - Página 59

Material do Treinamento Java e Orientação a Objetos

Conta[] minhasContas;minhasContas = new Conta[10];

Quantas contas foram criadas aqui? Na verdade, nenhuma. Foram criados 10 espaços que você pode utilizarpara guardar uma referência a uma Conta. Por enquanto, eles se referenciam para lugar nenhum (null). Sevocê tentar:

System.out.println(minhasContas[0].saldo);

Um erro durante a execução ocorrerá! Pois, na primeira posição da array, não há uma referência para uma

conta, nem para lugar nenhum. Você deve popular sua array antes.

Conta contaNova = new Conta();contaNova.saldo = 1000.0;minhasContas[0] = contaNova;

Ou você pode fazer isso diretamente:

minhasContas[1] = new Conta();minhasContas[1].saldo = 3200.0;

Uma array de tipos primitivos guarda valores, uma array de objetos guarda referências.

5.3 Percorrendo uma array

Percorrer uma array é muito simples quando fomos nós que a criamos:

Capítulo 5 - Um pouco de arrays - Percorrendo uma array - Página 60

Material do Treinamento Java e Orientação a Objetos

public static void main(String args[]) {int[] idades = new int[10];for (int i = 0; i < 10; i++) {

idades[i] = i * 10;}for (int i = 0; i < 10; i++) {

System.out.println(idades[i]);}

}

Porém, em muitos casos, recebemos uma array como argumento em ummétodo:

void imprimeArray(int[] array) {// não compila!!for (int i = 0; i < ????; i++) {

System.out.println(array[i]);}

}

Até onde o for deve ir? Toda array em Java tem um atributo que se chama length, e você pode acessá-lopara saber o tamanho do array ao qual você está se referenciando naquele momento:

void imprimeArray(int[] array) {for (int i = 0; i < array.length; i++) {

System.out.println(array[i]);}

}

Arrays não podem mudar de tamanho

A partir do momento que uma array foi criada, ela não podemudar de tamanho.

Se você precisar de mais espaço, será necessário criar uma nova array e, antes de se referir ela,

copie os elementos da array velha.

5.4 Percorrendo uma array no Java 5.0

O Java 5.0 traz uma nova sintaxe para percorremos arrays (e coleções, que veremos mais a frente).

No caso de você não ter necessidade de manter uma variável com o índice que indica a posição do elemento

no vetor (que é uma grande parte dos casos), podemos usar o enhanced-for.

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

Capítulo 5 - Um pouco de arrays - Percorrendo uma array no Java 5.0 - Página 61

Material do Treinamento Java e Orientação a Objetos

int[] idades = new int[10];for (int i = 0; i < 10; i++) {

idades[i] = i * 10;}

// imprimindo toda a arrayfor (int x : idades) {

System.out.println(x);}

}}

Não precisamos mais do length para percorrer matrizes cujo tamanho não conhecemos:

class AlgumaClasse {void imprimeArray(int[] array) {

for (int x : array) {System.out.println(x);

}}

}

Omesmo é válido para arrays de referências. Esse fornadamais é que um truque de compilação para facilitaressa tarefa de percorrer arrays e torná-la mais legível.

5.5 Exercícios: Arrays

1) Volte ao nosso sistema de Funcionario e crie uma classe Empresa dentro do mesmo arquivo .java. AEmpresa tem um nome, cnpj e uma referência a uma array de Funcionario, além de outros atributos quevocê julgar necessário.

class Empresa {// outros atributosFuncionario[] empregados;String cnpj;

}

2) A Empresa deve ter um método adiciona, que recebe uma referência a Funcionario como argumento eguarda esse funcionário. Algo como:

void adiciona(Funcionario f) {// algo tipo:// this.empregados[ ??? ] = f;// mas que posição colocar?

}

Capítulo 5 - Um pouco de arrays - Exercícios: Arrays - Página 62

Material do Treinamento Java e Orientação a Objetos

Você deve inserir o Funcionario em uma posição da array que esteja livre. Existem várias maneiras paravocê fazer isso: guardar um contador para indicar qual a próxima posição vazia ou procurar por uma

posição vazia toda vez. O que seria mais interessante?

É importante reparar que o método adiciona não recebe nome, rg, salário, etc. Essa seria uma ma-

neira nem um pouco estruturada, muito menos orientada a objetos de se trabalhar. Você antes cria um

Funcionario e já passa a referência dele, que dentro do objeto possui rg, salário, etc.

3) Crie uma classe TestaEmpresa que possuirá um método main. Dentro dele crie algumas instâncias deFuncionario e passe para a empresa pelo método adiciona. Repare que antes você vai precisar criar aarray, pois inicialmente o atributo empregados da classe Empresa não referencia lugar nenhum (seu valoré null):

Empresa empresa = new Empresa();empresa.empregados = new Funcionario[10];// ....

Ou você pode construir a array dentro da própria declaração da classe Empresa, fazendo com que todavez que uma Empresa é instanciada, a array de Funcionario que ela necessita também é criada.

Crie alguns funcionários e passe como argumento para o adiciona da empresa:

Funcionario f1 = new Funcionario();f1.salario = 1000;empresa.adiciona(f1);

Funcionario f2 = new Funcionario();f2.salario = 1700;empresa.adiciona(f2);

Você pode criar esses funcionários dentro de um loop e dar a cada um deles valores diferentes de salários:

for (int i = 0; i < 5; i++) {Funcionario f = new Funcionario();f.salario = 1000 + i * 100;empresa.adiciona(f);

}

Repare que temos de instanciar Funcionario dentro do laço. Se a instanciação de Funcionario �casseacima do laço, estaríamos adicionado cinco vezes a mesma instância de Funcionario nesta Empresa eapenas mudando seu salário a cada iteração, que nesse caso não é o efeito desejado.

Opcional: o método adiciona pode gerar umamensagem de erro indicando quando o array já está cheio.

4) Percorra o atributo empregados da sua instância da Empresa e imprima os salários de todos seus funcioná-rios. Para fazer isso, você pode criar um método chamado mostraEmpregados dentro da classe Empresa:

void mostraEmpregados() {for (int i = 0; i < this.empregados.length; i++) {

Capítulo 5 - Um pouco de arrays - Exercícios: Arrays - Página 63

Material do Treinamento Java e Orientação a Objetos

System.out.println("Funcionário na posição: " + i);// preencher para mostrar outras informacoes do funcionario

}}

Cuidado ao preencher esse método: alguns índices do seu array podem não conter referência para um

Funcionario construído, isto é, ainda se referirem para null. Se preferir, use o for novo do java 5.0.

Aí, através do seu main, depois de adicionar alguns funcionários, basta fazer:

empresa.mostraEmpregados();

5) (opcional) Em vez demostrar apenas o salário de cada funcionário, você pode chamar ométodo mostra()de cada Funcionario da sua array.

6) (Opcional) Crie um método para veri�car se um determinado Funcionario se encontra ou não comofuncionário desta empresa:

boolean contem(Funcionario f) {// ...

}

Você vai precisar fazer um for na sua array e veri�car se a referência passada como argumento se encontradentro da array. Evite ao máximo usar números hard-coded, isto é, use o .length ou o atributo livre.

7) (Opcional) Caso a array já esteja cheia no momento de adicionar um outro funcionário, criar uma nova

maior e copiar os valores. Isto é, fazer a realocação já que java não tem isso: uma array nasce e morre

com o mesmo length.

Usando o this para passar argumento

Dentro de ummétodo, você pode usar a palavra this para referenciar a si mesmo e pode passaressa referência como argumento.

5.6 Um pouco mais...

• Arrays podem ter mais de uma dimensão. Isto é, em vez de termos uma array de 10 contas, podemos

ter uma array de 10 por 10 contas e você pode acessar a conta na posição da coluna x e linha y. Na

verdade, uma array bidimensional em Java é uma array de arrays. Pesquise sobre isso.

Capítulo 5 - Um pouco de arrays - Um pouco mais... - Página 64

Material do Treinamento Java e Orientação a Objetos

• Uma array bidimensional não precisa ser retangular, isto é, cada linha pode ter um número diferente

de colunas. Como? Porque?

• O que acontece se criarmos uma array de 0 elementos? e -1?

• O método main recebe uma array de Strings como argumento. Essa array é passada pelo usuárioquando ele invoca o programa:

$ java Teste argumento1 outro maisoutro

E nossa classe:

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

for(String argumento: args) {

Capítulo 5 - Um pouco de arrays - Um pouco mais... - Página 65

Material do Treinamento Java e Orientação a Objetos

System.out.println(argumento);}

}}

Isso imprimirá:

argumento1outromaisoutro

5.7 Desafios

1) No capítulo anterior, você deve ter reparado que a versão recursiva para o problema de Fibonacci é lenta

porque toda hora estamos recalculando valores. Faça com que a versão recursiva seja tão boa quanto a

versão iterativa. (Dica: use arrays para isso)

5.8 Testando o conhecimento

1) O objetivo dos exercícios a seguir é �xar os conceitos vistos. Se você está com di�culdade em alguma

parte desse capítulo, aproveite e treine tudo o que vimos até agora no pequeno programa abaixo:

• Programa:Classe: Casa Atributos: cor, totalDePortas, portas[] Métodos: void pinta(String s), int

quantasPortasEstaoAbertas(), void adicionaPorta(Porta p), int totalDePortas()

Crie uma casa, pinte-a. Crie três portas e coloque-as na casa através do método adicionaPorta, abra efeche-as como desejar. Utilize ométodo quantasPortasEstaoAbertas para imprimir o número de portasabertas e o método totalDePortas para imprimir o total de portas em sua casa.

Capítulo 5 - Um pouco de arrays - Desa�os - Página 66

Capítulo 6

Modi�cadores de acesso e atributos de classe

“A marca do homem imaturo é que ele quer morrer nobremente por uma causa, enquanto a marca do homemmaduro é querer viver modestamente por uma."

– J. D. Salinger

Ao término desse capítulo, você será capaz de:

• controlar o acesso aos seus métodos, atributos e construtores através dos modi�cadores private e pu-

blic;

• escrever métodos de acesso a atributos do tipo getters e setters;

• escrever construtores para suas classes;

• utilizar variáveis e métodos estáticos.

6.1 Controlando o acesso

Um dos problemas mais simples que temos no nosso sistema de contas é que o método saca permite sacarmesmo que o limite tenha sido atingido. A seguir você pode lembrar como está a classe Conta:

class Conta {int numero;Cliente titular;double saldo;double limite;

// ..

Material do Treinamento Java e Orientação a Objetos

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

}}

A classe a seguir mostra como é possível ultrapassar o limite usando o método saca:

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

Conta minhaConta = new Conta();minhaConta.saldo = 1000.0;minhaConta.limite = 1000.0;minhaConta.saca(50000); // saldo + limite é só 2000!!

}}

Podemos incluir um if dentro do nosso método saca() para evitar a situação que resultaria em uma contaem estado inconsistente, com seu saldo abaixo do limite. Fizemos isso no capítulo de orientação a objetos

básica.

Apesar demelhorar bastante, ainda temos um problemamais grave: ninguém garante que o usuário da classe

vai sempre utilizar o método para alterar o saldo da conta. O código a seguir ultrapassa o limite diretamente:

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

Conta minhaConta = new Conta();minhaConta.limite = 100;minhaConta.saldo = -200; //saldo está abaixo dos 100 de limite

}}

Como evitar isso? Uma ideia simples seria testar se não estamos ultrapassando o limite toda vez que formos

alterar o saldo:

class TestaContaEstouro3 {

public static void main(String args[]) {// a ContaConta minhaConta = new Conta();minhaConta.limite = 100;minhaConta.saldo = 100;

// quero mudar o saldo para -200double novoSaldo = -200;

Capítulo 6 - Modi�cadores de acesso e atributos de classe - Controlando o acesso - Página 68

Material do Treinamento Java e Orientação a Objetos

// testa se o novoSaldo ultrapassa o limite da contaif (novoSaldo < -minhaConta.limite) { //

System.out.println("Não posso mudar para esse saldo");} else {

minhaConta.saldo = novoSaldo;}

}}

Esse código iria se repetir ao longo de toda nossa aplicação e, pior, alguém pode esquecer de fazer essa

comparação em algum momento, deixando a conta na situação inconsistente. A melhor forma de resolver

isso seria forçar quem usa a classe Conta a invocar o método saca e não permitir o acesso direto ao atributo.É o mesmo caso da validação de CPF.

Para fazer isso no Java, basta declarar que os atributos não podem ser acessados de fora da classe através da

palavra chave private:

class Conta {private double saldo;private double limite;// ...

}

private é ummodi�cador de acesso (também chamado demodi�cador de visibilidade).

Marcando um atributo como privado, fechamos o acesso ao mesmo em relação a todas as outras classes,

fazendo com que o seguinte código não compile:

class TestaAcessoDireto {public static void main(String args[]) {Conta minhaConta = new Conta();//não compila! você não pode acessar o atributo privado de outra classeminhaConta.saldo = 1000;

}}

TesteAcessoDireto.java:5 saldo has private access in ContaminhaConta.saldo = 1000;

^1 error

Na orientação a objetos, é prática quase que obrigatória proteger seus atributos com private. (discutiremosoutros modi�cadores de acesso em outros capítulos).

Capítulo 6 - Modi�cadores de acesso e atributos de classe - Controlando o acesso - Página 69

Material do Treinamento Java e Orientação a Objetos

Cada classe é responsável por controlar seus atributos, portanto ela deve julgar se aquele novo valor é válido

ou não! Esta validação não deve ser controlada por quem está usando a classe e sim por ela mesma, centra-

lizando essa responsabilidade e facilitando futuras mudanças no sistema. Muitas outras vezes nem mesmo

queremos que outras classes saibam da existência de determinado atributo, escondendo-o por completo, já

que ele diz respeito ao funcionamento interno do objeto.

Repare que, quem invoca o método saca não faz a menor ideia de que existe um limite que está sendochecado. Para quem for usar essa classe, basta saber o que o método faz e não como exatamente ele o faz (o

que ummétodo faz é sempre mais importante do que como ele faz: mudar a implementação é fácil, já mudar

a assinatura de um método vai gerar problemas).

A palavra chave private também pode ser usada para modi�car o acesso a um método. Tal funcionalidadeé utilizada em diversos cenários: quando existe um método que serve apenas para auxiliar a própria classe e

quando há código repetido dentro de dois métodos da classe são os mais comuns. Sempre devemos expôr o

mínimo possível de funcionalidades, para criar um baixo acoplamento entre as nossas classes.

Da mesma maneira que temos o private, temos o modi�cador public, que permite a todos acessarem umdeterminado atributo ou método :

class Conta {//...public void saca(double quantidade) {

//posso sacar até saldo+limiteif (quantidade > this.saldo + this.limite){

System.out.println("Não posso sacar fora do limite!");} else {

this.saldo = this.saldo - quantidade;}

}}

E quando não há modificador de acesso?

Até agora, tínhamos declarado variáveis e métodos sem nenhum modi�cador como private epublic. Quando isto acontece, o seu método ou atributo �ca num estado de visibilidade inter-mediário entre o private e o public, que veremos mais pra frente, no capítulo de pacotes.

É muito comum, e faz todo sentido, que seus atributos sejam private e quase todos seus métodos sejampublic (não é uma regra!). Desta forma, toda conversa de um objeto com outro é feita por troca de mensa-gens, isto é, acessando seus métodos. Algo muito mais educado que mexer diretamente em um atributo que

não é seu!

Melhor ainda! O dia em que precisarmos mudar como é realizado um saque na nossa classe Conta, adivinheonde precisaríamos modi�car? Apenas no método saca, o que faz pleno sentido. Como exemplo, imaginecobrar CPMF de cada saque: basta você modi�car ali, e nenhum outro código, fora a classe Conta, precisará

Capítulo 6 - Modi�cadores de acesso e atributos de classe - Controlando o acesso - Página 70

Material do Treinamento Java e Orientação a Objetos

ser recompilado. Mais: as classes que usam essemétodo nemprecisam�car sabendo de talmodi�cação! Você

precisa apenas recompilar aquela classe e substituir aquele arquivo .class. Ganhamos muito em esconder ofuncionamento do nosso método na hora de dar manutenção e fazer modi�cações.

6.2 Encapsulamento

O que começamos a ver nesse capítulo é a ideia de encapsular, isto é, esconder todos os membros de umaclasse (como vimos acima), além de esconder como funcionam as rotinas (no caso métodos) do nosso sis-

tema.

Encapsular é fundamental para que seu sistema seja suscetível a mudanças: não precisaremos mudar umaregra de negócio em vários lugares, mas sim em apenas um único lugar, já que essa regra está encapsulada.(veja o caso do método saca)

O conjunto de métodos públicos de uma classe é também chamado de interface da classe, pois esta é a únicamaneira a qual você se comunica com objetos dessa classe.

Programando voltado para a interface e não para a implementa-ção

É sempre bom programar pensando na interface da sua classe, como seus usuários a estarão

utilizando, e não somente em como ela vai funcionar.

A implementação em si, o conteúdo dos métodos, não tem tanta importância para o usuário

dessa classe, uma vez que ele só precisa saber o que cada método pretende fazer, e não como ele

faz, pois isto pode mudar com o tempo.

Essa frase vem do livro Design Patterns, de Eric Gamma et al. Um livro cultuado no meio da

orientação a objetos.

Capítulo 6 - Modi�cadores de acesso e atributos de classe - Encapsulamento - Página 71

Material do Treinamento Java e Orientação a Objetos

Sempre que vamos acessar um objeto, utilizamos sua interface. Existem diversas analogias fáceis no mundo

real:

• Quando você dirige um carro, o que te importa são os pedais e o volante (interface) e não o motor que

você está usando (implementação). É claro que um motor diferente pode te dar melhores resultados,

mas o que ele faz é o mesmo que um motor menos potente, a diferença está em como ele faz. Paratrocar um carro a álcool para um a gasolina você não precisa reaprender a dirigir! (trocar a imple-

mentação dos métodos não precisa mudar a interface, fazendo com que as outras classes continuem

usando eles da mesma maneira).

• Todos os celulares fazem a mesma coisa (interface), eles possuem maneiras (métodos) de discar, ligar,

desligar, atender, etc. O que muda é como eles fazem (implementação), mas repare que para o usuário

comum pouco importa se o celular é GSM ou CDMA, isso �ca encapsulado na implementação (que

aqui são os circuitos).

Já temos conhecimentos su�cientes para resolver aquele problema da validação de CPF:

class Cliente {private String nome;private String endereco;private String cpf;private int idade;

public void mudaCPF(String cpf) {validaCPF(cpf);this.cpf = cpf;

}

private void validaCPF(String cpf) {// série de regras aqui, falha caso não seja válido

}

// ..}

Se alguém tentar criar um Cliente e não usar o mudaCPF para alterar um cpf diretamente, vai receber umerro de compilação, já que o atributo CPF é privado. E o dia que você não precisar veri�car o CPF de quemtem mais de 60 anos? Seu método �ca o seguinte:

public void mudaCPF(String cpf) {if (this.idade <= 60) {

validaCPF(cpf);}this.cpf = cpf;

}

Capítulo 6 - Modi�cadores de acesso e atributos de classe - Encapsulamento - Página 72

Material do Treinamento Java e Orientação a Objetos

O controle sobre o CPF está centralizado: ninguém consegue acessá-lo sem passar por aí, a classe Cliente éa única responsável pelos seus próprios atributos!

6.3 Getters e Setters

O modi�cador private faz com que ninguém consiga modi�car, nem mesmo ler, o atributo em questão.Com isso, temos umproblema: como fazer paramostrar o saldo de uma Conta, já que nemmesmo podemosacessá-lo para leitura?

Precisamos então arranjar umamaneira de fazer esse acesso. Sempre que precisamos arrumar umamaneirade fazer alguma coisa com um objeto, utilizamos de métodos! Vamos então criar um método, digamospegaSaldo, para realizar essa simples tarefa:

public class Conta {

private double saldo;

// outros atributos omitidos

private double pegaSaldo() {return this.saldo;

}

// deposita() saca() e transfere() omitidos}

Para acessarmos o saldo de uma conta, podemos fazer:

class TestaAcessoComPegaSaldo {public static void main(String args[]) {Conta minhaConta = new Conta();minhaConta.deposita(1000);System.out.println("Saldo: " + minhaConta.pegaSaldo());

}}

Para permitir o acesso aos atributos (já que eles são private) de uma maneira controlada, a prática maiscomum é criar dois métodos, um que retorna o valor e outro que muda o valor.

A convenção para esses métodos é de colocar a palavra get ou set antes do nome do atributo. Por exemplo,a nossa conta com saldo, limite e titular �ca assim, no caso da gente desejar dar acesso a leitura e escritaa todos os atributos:

Capítulo 6 - Modi�cadores de acesso e atributos de classe - Getters e Setters - Página 73

Material do Treinamento Java e Orientação a Objetos

public class Conta {

private double saldo;private double limite;private Cliente titular;

public double getSaldo() {return this.saldo;

}

public void setSaldo(double saldo) {this.saldo = saldo;

}

public double getLimite() {return this.limite;

}

public void setLimite(double limite) {this.limite = limite;

}

public Cliente getTitular() {return this.titular;

}

public void setTitular(Cliente titular) {this.titular = titular;

}}

É uma má prática criar uma classe e, logo em seguida, criar getters e setters para todos seus atributos. Você

só deve criar um getter ou setter se tiver a real necessidade. Repare que nesse exemplo setSaldo não deveriater sido criado, já que queremos que todos usem deposita() e saca().

Outro detalhe importante, ummétodo getX não necessariamente retorna o valor de um atributo que chama Xdo objeto em questão. Isso é interessante para o encapsulamento. Imagine a situação: queremos que o banco

sempre mostre como saldo o valor do limite somado ao saldo (uma prática comum dos bancos que costumailudir seus clientes). Poderíamos sempre chamar c.getLimite() + c.getSaldo(), mas isso poderia geraruma situação de “replace all” quando precisássemos mudar como o saldo é mostrado. Podemos encapsular

isso em ummétodo e, porque não, dentro do próprio getSaldo? Repare:

public class Conta {

private double saldo;

Capítulo 6 - Modi�cadores de acesso e atributos de classe - Getters e Setters - Página 74

Material do Treinamento Java e Orientação a Objetos

private double limite;private Cliente titular;

public double getSaldo() {return this.saldo + this.limite;

}

// deposita() saca() e transfere() omitidos

public Cliente getTitular() {return this.titular;

}

public void setTitular(Cliente titular) {this.titular = titular;

}}

O código acima nem possibilita a chamada do método getLimite(), ele não existe. E nem deve existir en-quanto não houver essa necessidade. Ométodo getSaldo() não devolve simplesmente o saldo... e sim o quequeremos que sejamostrado como se fosse o saldo. Utilizar getters e setters não só ajuda você a proteger seusatributos, como também possibilita ter de mudar algo em um só lugar... chamamos isso de encapsulamento,

pois esconde a maneira como os objetos guardam seus dados. É uma prática muito importante.

Nossa classe está totalmente pronta? Isto é, existe a chance dela �car com menos dinheiro do que o limite?

Pode parecer que não, mas, e se depositarmos um valor negativo na conta? Ficaríamos com menos di-

nheiro que o permitido, já que não esperávamos por isso. Para nos proteger disso basta mudarmos ométodo

deposita() para que ele veri�que se o valor é necessariamente positivo.

Depois disso precisaríamos mudar mais algum outro código? A resposta é não, graças ao encapsulamento

dos nossos dados.

Cuidado com os getters e setters!

Como já dito, não devemos criar getters e setters sem um motivo explicito. No blog da Caelum

há um artigo que ilustra bem esses casos:

http://blog.caelum.com.br/2006/09/14/nao-aprender-oo-getters-e-setters/

6.4 Construtores

Quando usamos a palavra chave new, estamos construindo um objeto. Sempre quando o new é chamado, eleexecuta o construtor da classe. O construtor da classe é um bloco declarado com o mesmo nome que aclasse:

Capítulo 6 - Modi�cadores de acesso e atributos de classe - Construtores - Página 75

Material do Treinamento Java e Orientação a Objetos

class Conta {int numero;Cliente titular;double saldo;double limite;

// construtorConta() {

System.out.println("Construindo uma conta.");}

// ..}

Então, quando �zermos:

Conta c = new Conta();

Amensagem “construindo uma conta” aparecerá. É como uma rotina de inicialização que é chamada sempre

que um novo objeto é criado. Um construtor pode parecer, mas não é um método.

O construtor default

Até agora, as nossas classes não possuíam nenhum construtor. Então como é que era possível

dar new, se todo new chama um construtor obrigatoriamente?

Quando você não declara nenhum construtor na sua classe, o Java cria um para você. Esse cons-

trutor é o construtor default, ele não recebe nenhum argumento e o corpo dele é vazio.

A partir domomento que você declara um construtor, o construtor default não émais fornecido.

O interessante é que um construtor pode receber um argumento, podendo assim inicializar algum tipo de

informação:

class Conta {int numero;Cliente titular;double saldo;double limite;

// construtorConta(Cliente titular) {

this.titular = titular;

Capítulo 6 - Modi�cadores de acesso e atributos de classe - Construtores - Página 76

Material do Treinamento Java e Orientação a Objetos

}

// ..}

Esse construtor recebe o titular da conta. Assim, quando criarmos uma conta, ela já terá um determinado

titular.

Cliente carlos = new Cliente();carlos.nome = "Carlos";

Conta c = new Conta(carlos);System.out.println(c.titular.nome);

6.5 A necessidade de um construtor

Tudo estava funcionando até agora. Para que utilizamos um construtor?

A ideia é bem simples. Se toda conta precisa de um titular, como obrigar todos os objetos que forem criados

a ter um valor desse tipo? Basta criar um único construtor que recebe essa String!

O construtor se resume a isso! Dar possibilidades ou obrigar o usuário de uma classe a passar argumentos

para o objeto durante o processo de criação do mesmo.

Por exemplo, não podemos abrir um arquivo para leitura sem dizer qual é o nome do arquivo que desejamos

ler! Portanto, nada mais natural que passar uma String representando o nome de um arquivo na hora decriar um objeto do tipo de leitura de arquivo, e que isso seja obrigatório.

Você pode ter mais de um construtor na sua classe e, no momento do new, o construtor apropriado seráescolhido.

Construtor: um método especial?

Um construtor não é um método. Algumas pessoas o chamam de um método especial, mas

de�nitivamente não é, já que não possui retorno e só é chamado durante a construção do objeto.

Capítulo 6 - Modi�cadores de acesso e atributos de classe - A necessidade de um construtor - Página 77

Material do Treinamento Java e Orientação a Objetos

Chamando outro construtor

Um construtor só pode rodar durante a construção do objeto, isto é, você nunca conseguirá

chamar o construtor em um objeto já construído. Porém, durante a construção de um objeto,

você pode fazer com que um construtor chame outro, para não ter de �car copiando e colando:

class Conta {int numero;Cliente titular;double saldo;double limite;

// construtorConta (Cliente titular) {

// faz mais uma série de inicializações e configuraçõesthis.titular = titular;

}

Conta (int numero, Cliente titular) {this(titular); // chama o construtor que foi declarado acimathis.numero = numero;

}

//..}

Existe um outro motivo, o outro lado dos construtores: facilidade. Às vezes, criamos um construtor que

recebe diversos argumentos para não obrigar o usuário de uma classe a chamar diversos métodos do tipo

'set'.

No nosso exemplo do CPF, podemos forçar que a classe Cliente receba no mínimo o CPF, dessa maneiraum Cliente já será construído e com um CPF válido.

Java Bean

Quando criamos uma classe com todos os atributos privados, seus getters e setters e um cons-

trutor vazio (padrão), na verdade estamos criando um Java Bean (mas não confunda com EJB,

que é Enterprise Java Beans).

Para saber mais acesse: http://java.sun.com/products/javabeans/

Capítulo 6 - Modi�cadores de acesso e atributos de classe - A necessidade de um construtor - Página 78

Material do Treinamento Java e Orientação a Objetos

6.6 Atributos de classe

Nosso banco também quer controlar a quantidade de contas existentes no sistema. Como poderíamos fazer

isto? A ideia mais simples:

Conta c = new Conta();totalDeContas = totalDeContas + 1;

Aqui, voltamos em um problema parecido com o da validação de CPF. Estamos espalhando um código por

toda aplicação, e quem garante que vamos conseguir lembrar de incrementar a variável totalDeContas todavez?

Tentamos então, passar para a seguinte proposta:

class Conta {private int totalDeContas;//...

Conta() {this.totalDeContas = this.totalDeContas + 1;

}}

Quando criarmos duas contas, qual será o valor do totalDeContas de cada uma delas? Vai ser 1. Pois cadauma tem essa variável. O atributo é de cada objeto.

Seria interessante então, que essa variável fosse única, compartilhada por todos os objetos dessa classe. Dessamaneira, quando mudasse através de um objeto, o outro enxergaria o mesmo valor. Para fazer isso em java,

declaramos a variável como static.

private static int totalDeContas;

Quando declaramos um atributo como static, ele passa a não ser mais um atributo de cada objeto, e simum atributo da classe, a informação �ca guardada pela classe, não é mais individual para cada objeto.

Para acessarmos um atributo estático, não usamos a palavra chave this, mas sim o nome da classe:

class Conta {private static int totalDeContas;//...

Conta() {Conta.totalDeContas = Conta.totalDeContas + 1;

}}

Capítulo 6 - Modi�cadores de acesso e atributos de classe - Atributos de classe - Página 79

Material do Treinamento Java e Orientação a Objetos

Já que o atributo é privado, como podemos acessar essa informação a partir de outra classe? Precisamos de

um getter para ele!

class Conta {private static int totalDeContas;//...

Conta() {Conta.totalDeContas = Conta.totalDeContas + 1;

}

public int getTotalDeContas() {return Conta.totalDeContas;

}}

Como fazemos então para saber quantas contas foram criadas?

Conta c = new Conta();int total = c.getTotalDeContas();

Precisamos criar uma conta antes de chamar o método! Isso não é legal, pois gostaríamos de saber quantas

contas existem sem precisar ter acesso a um objeto conta. A ideia aqui é a mesma, transformar esse método

que todo objeto conta tem em um método de toda a classe. Usamos a palavra static de novo, mudando ométodo anterior.

public static int getTotalDeContas() {return Conta.totalDeContas;

}

Para acessar esse novo método:

int total = Conta.getTotalDeContas();

Repare que estamos chamando um método não com uma referência para uma Conta, e sim usando o nomeda classe.

Métodos e atributos estáticos

Métodos e atributos estáticos só podem acessar outros métodos e atributos estáticos da mesma

classe, o que faz todo sentido já que dentro de ummétodo estático não temos acesso à referência

this, pois um método estático é chamado através da classe, e não de um objeto.

O static realmente traz um “cheiro” procedural, porém em muitas vezes é necessário.

Capítulo 6 - Modi�cadores de acesso e atributos de classe - Atributos de classe - Página 80

Material do Treinamento Java e Orientação a Objetos

6.7 Um pouco mais...

1) Em algumas empresas, o UML é amplamente utilizado. Às vezes, o programador recebe o UML já pronto,

completo, e só deve preencher a implementação, devendo seguir à risca o UML. O que você acha dessa

prática? Quais as vantagens e desvantagens.

2) Se uma classe só tem atributos e métodos estáticos, que conclusões podemos tirar? O que lhe parece um

método estático em casos como esses?

3) No caso de atributos booleanos, pode-se usar no lugar do get o su�xo is. Dessamaneira, caso tivéssemosum atributo booleano ligado, em vez de getLigado poderíamos ter isLigado.

6.8 Exercícios: Encapsulamento, construtores e static

1) Adicione o modi�cador de visibilidade (private, se necessário) para cada atributo e método da classeFuncionario. Tente criar um Funcionario no main e modi�car ou ler um de seus atributos privados. Oque acontece?

2) Crie os getters e setters necessários da sua classe Funcionario. Por exemplo:

class Funcionario {private double salario;

// ...

public double getSalario() {return this.salario;

}

public void setSalario(double salario) {this.salario = salario;

}}

Não copie e cole! Aproveite para praticar sintaxe. Logo passaremos a usar o Eclipse e aí sim teremos

procedimentos mais simples para este tipo de tarefa.

Repare que o método calculaGanhoAnual parece também um getter. Aliás, seria comum alguém nomeá-lo de getGanhoAnual. Getters não precisam apenas retornar atributos. Eles podem trabalhar com essesdados.

3) Modi�que suas classes que acessam e modi�cam atributos de um Funcionario para utilizar os getters esetters recém criados.

Por exemplo, onde você encontra:

Capítulo 6 - Modi�cadores de acesso e atributos de classe - Um pouco mais... - Página 81

Material do Treinamento Java e Orientação a Objetos

f.salario = 100;System.out.println(f.salario);

passa para:

f.setSalario(100);System.out.println(f.getSalario());

4) Faça com que sua classe Funcionario possa receber, opcionalmente, o nome do Funcionario durante acriação do objeto. Utilize construtores para obter esse resultado.

Dica: utilize um construtor sem argumentos também, para o caso de a pessoa não querer passar o nome

do Funcionario.

Seria algo como:

class Funcionario {public Funcionario() {

// construtor sem argumentos}

public Funcionario(String nome) {// construtor que recebe o nome

}}

Por que você precisa do construtor sem argumentos para que a passagem do nome seja opcional?

5) (opcional) Adicione um atributo na classe Funcionario de tipo int que se chama identi�cador. Esseidenti�cador deve ter um valor único para cada instância do tipo Funcionario. O primeiro Funcionarioinstanciado tem identi�cador 1, o segundo 2, e assim por diante. Você deve utilizar os recursos aprendidos

aqui para resolver esse problema.

Crie um getter para o identi�cador. Devemos ter um setter?

6) (opcional) Crie os getters e setters da sua classe Empresa e coloque seus atributos como private. Lembre-se de que não necessariamente todos os atributos devem ter getters e setters.

Por exemplo, na classe Empresa, seria interessante ter um setter e getter para a sua array de funcionários?Não seria mais interessante ter um método como este?

class Empresa {// ...

public Funcionario getFuncionario (int posicao) {return this.empregados[posicao];

}}

Capítulo 6 - Modi�cadores de acesso e atributos de classe - Exercícios: Encapsulamento, construtores e static - Página 82

Material do Treinamento Java e Orientação a Objetos

7) (opcional) Na classe Empresa, em vez de criar um array de tamanho �xo, receba como parâmetro noconstrutor o tamanho do array de Funcionario.

Com esse construtor, o que acontece se tentarmos dar new Empresa() sem passar argumento algum? Porquê?

8) (opcional) Como garantir que datas como 31/2/2012 não sejam aceitas pela sua classe Data?

9) (opcional) Crie a classe PessoaFisica. Queremos ter a garantia de que pessoa física alguma tenhaCPF in-valido, nem seja criada PessoaFisica sem cpf inicial. (você não precisa escrever o algoritmo de validaçãode cpf, basta passar o cpf por um método valida(String x)...)

6.9 Desafios

1) Porque esse código não compila?

class Teste {int x = 37;public static void main(String [] args) {

System.out.println(x);}

}

2) Imagine que tenha uma classe FabricaDeCarro e quero garantir que só existe um objeto desse tipo emtoda a memória. Não existe uma palavra chave especial para isto em Java, então teremos de fazer nossa

classe de tal maneira que ela respeite essa nossa necessidade. Como fazer isso? (pesquise: singleton design

pattern)

Capítulo 6 - Modi�cadores de acesso e atributos de classe - Desa�os - Página 83

Capítulo 7

Herança, reescrita e polimor�smo

“O homem absurdo é aquele que nunca muda.”– Georges Clemenceau

Ao término desse capítulo, você será capaz de:

• dizer o que é herança e quando utilizá-la;

• reutilizar código escrito anteriormente;

• criar classes �lhas e reescrever métodos;

• usar todo o poder que o polimor�smo dá.

7.1 Repetindo código?

Como toda empresa, nosso Banco possui funcionários. Vamos modelar a classe Funcionario:

class Funcionario {String nome;String cpf;double salario;// métodos devem vir aqui

}

Alémde um funcionário comum, há tambémoutros cargos, comoos gerentes. Os gerentes guardamamesma

informação que um funcionário comum, mas possuem outras informações, além de ter funcionalidades um

pouco diferentes. Um gerente no nosso banco possui também uma senha numérica que permite o acesso ao

sistema interno do banco, além do número de funcionários que ele gerencia:

Material do Treinamento Java e Orientação a Objetos

class Gerente {String nome;String cpf;double salario;int senha;int numeroDeFuncionariosGerenciados;

public boolean autentica(int senha) {if (this.senha == senha) {

System.out.println("Acesso Permitido!");return true;

} else {System.out.println("Acesso Negado!");return false;

}}

// outros métodos}

Precisamos mesmo de outra classe?

Poderíamos ter deixado a classe Funcionario mais genérica, mantendo nela senha de acesso, eo número de funcionários gerenciados. Caso o funcionário não fosse um gerente, deixaríamos

estes atributos vazios.

Essa é uma possibilidade, porém podemos começar a ter muito atributos opcionais, e a classe

�caria estranha. E em relação aos métodos? A classe Gerente tem ométodo autentica, que nãofaz sentido existir em um funcionário que não é gerente.

Se tivéssemos um outro tipo de funcionário que tem características diferentes do funcionário comum, pre-

cisaríamos criar uma outra classe e copiar o código novamente!

Além disso, se umdia precisarmos adicionar uma nova informação para todos os funcionários, precisaremos

passar por todas as classes de funcionário e adicionar esse atributo. O problema acontece novamente por não

centralizarmos as informações principais do funcionário em um único lugar!

Existe um jeito, em Java, de relacionarmos uma classe de tal maneira que uma delas herda tudo que a outratem. Isto é uma relação de classe mãe e classe �lha. No nosso caso, gostaríamos de fazer com que o Gerentetivesse tudo que um Funcionario tem, gostaríamos que ela fosse uma extensão de Funcionario. Fazemosisto através da palavra chave extends.

class Gerente extends Funcionario {int senha;int numeroDeFuncionariosGerenciados;

Capítulo 7 - Herança, reescrita e polimor�smo - Repetindo código? - Página 85

Material do Treinamento Java e Orientação a Objetos

public boolean autentica(int senha) {if (this.senha == senha) {

System.out.println("Acesso Permitido!");return true;

} else {System.out.println("Acesso Negado!");return false;

}}

// setter da senha omitido}

Em todo momento que criarmos um objeto do tipo Gerente, este objeto possuirá também os atributos de�-nidos na classe Funcionario, pois um Gerente é um Funcionario:

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

Gerente gerente = new Gerente();

// podemos chamar métodos do Funcionario:gerente.setNome("João da Silva");

// e também métodos do Gerente!gerente.setSenha(4231);

}}

Dizemos que a classe Gerente herda todos os atributos e métodos da classe mãe, no nosso caso, aFuncionario. Para ser mais preciso, ela também herda os atributos e métodos privados, porém não con-segue acessá-los diretamente. Para acessar um membro privado na �lha indiretamente, seria necessário que

a mãe expusesse um outro método visível que invocasse esse atributo ou método privado.

Capítulo 7 - Herança, reescrita e polimor�smo - Repetindo código? - Página 86

Material do Treinamento Java e Orientação a Objetos

Super e Sub classe

A nomenclatura mais encontrada é que Funcionario é a superclasse de Gerente, e Gerente é asubclasse de Funcionario. Dizemos tambémque todo Gerente é um Funcionário. Outra formaé dizer que Funcionario é classemãe de Gerente e Gerente é classe �lha de Funcionario.

E se precisamos acessar os atributos que herdamos? Não gostaríamos de deixar os atributos de Funcionario,public, pois dessa maneira qualquer um poderia alterar os atributos dos objetos deste tipo. Existe um outromodi�cador de acesso, o protected, que �ca entre o private e o public. Um atributo protected só podeser acessado (visível) pela própria classe e por suas subclasses (e mais algumas outras classes, mas veremos

isso em outro capítulo).

class Funcionario {protected String nome;protected String cpf;protected double salario;// métodos devem vir aqui

}

Sempre usar protected?

Então porque usar private? Depois de um tempo programando orientado a objetos, você vaicomeçar a sentir que nem sempre é uma boa ideia deixar que a classe �lha acesse os atributos

da classe mãe, pois isso quebra um pouco a ideia de que só aquela classe deveria manipular seus

atributos. Essa é uma discussão um pouco mais avançada.

Além disso, não só as subclasses, mas também as outras classes, podem acessar os atributos

protected, que veremos mais a frente (mesmo pacote). Veja outras alternativas ao protectedno exercício de discussão em sala de aula juntamente com o instrutor.

Da mesma maneira, podemos ter uma classe Diretor que estenda Gerente e a classe Presidente pode es-tender diretamente de Funcionario.

Fique claro que essa é uma decisão de negócio. Se Diretor vai estender de Gerente ou não, vai depender se,

para você, Diretor é um Gerente.

Uma classe pode ter várias �lhas, mas pode ter apenas uma mãe, é a chamada herança simples do java.

Capítulo 7 - Herança, reescrita e polimor�smo - Repetindo código? - Página 87

Material do Treinamento Java e Orientação a Objetos

7.2 Reescrita de método

Todo �m de ano, os funcionários do nosso banco recebem uma boni�cação. Os funcionários comuns rece-

bem 10% do valor do salário e os gerentes, 15%.

Vamos ver como �ca a classe Funcionario:

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

public double getBonificacao() {return this.salario * 0.10;

}// métodos

}

Se deixarmos a classe Gerente como ela está, ela vai herdar o método getBonificacao.

Gerente gerente = new Gerente();gerente.setSalario(5000.0);System.out.println(gerente.getBonificacao());

O resultado aqui será 500. Não queremos essa resposta, pois o gerente deveria ter 750 de bônus nesse caso.

Para consertar isso, uma das opções seria criar um novo método na classe Gerente, chamado, por exemplo,getBonificacaoDoGerente. O problema é que teríamos dois métodos em Gerente, confundindo bastantequem for usar essa classe, além de que cada um da uma resposta diferente.

No Java, quando herdamos um método, podemos alterar seu comportamento. Podemos reescrever (rees-crever, sobrescrever, override) este método:

Capítulo 7 - Herança, reescrita e polimor�smo - Reescrita de método - Página 88

Material do Treinamento Java e Orientação a Objetos

class Gerente extends Funcionario {int senha;int numeroDeFuncionariosGerenciados;

public double getBonificacao() {return this.salario * 0.15;

}// ...

}

Agora o método está correto para o Gerente. Refaça o teste e veja que o valor impresso é o correto (750):

Gerente gerente = new Gerente();gerente.setSalario(5000.0);System.out.println(gerente.getBonificacao());

7.3 Invocando o método reescrito

Depois de reescrito, não podemos mais chamar o método antigo que fora herdado da classe mãe: realmente

alteramos o seu comportamento. Mas podemos invocá-lo no caso de estarmos dentro da classe.

Imagine que para calcular a boni�cação de um Gerente devemos fazer igual ao cálculo de um Funcionarioporem adicionando R$ 1000. Poderíamos fazer assim:

class Gerente extends Funcionario {int senha;int numeroDeFuncionariosGerenciados;

public double getBonificacao() {return this.salario * 0.10 + 1000;

}// ...

}

Aqui teríamos um problema: o dia que o getBonificacao do Funcionario mudar, precisaremos mudar ométodo do Gerente para acompanhar a nova boni�cação. Para evitar isso, o getBonificacao do Gerentepode chamar o do Funcionario utilizando a palavra chave super.

class Gerente extends Funcionario {int senha;int numeroDeFuncionariosGerenciados;

public double getBonificacao() {

Capítulo 7 - Herança, reescrita e polimor�smo - Invocando o método reescrito - Página 89

Material do Treinamento Java e Orientação a Objetos

return super.getBonificacao() + 1000;}// ...

}

Essa invocação vai procurar o método com o nome getBonificacao de uma super classe de Gerente. Nocaso ele logo vai encontrar esse método em Funcionario.

Essa é uma prática comum, pois muitos casos o método reescrito geralmente faz “algo a mais” que o método

da classe mãe. Chamar ou não o método de cima é uma decisão sua e depende do seu problema. Algumas

vezes não faz sentido invocar o método que reescrevemos.

7.4 Polimorfismo

O que guarda uma variável do tipo Funcionario? Uma referência para um Funcionario, nunca o objeto emsi.

Na herança, vimos que todo Gerente é um Funcionario, pois é uma extensão deste. Podemos nos referir aum Gerente como sendo um Funcionario. Se alguém precisa falar com um Funcionario do banco, podefalar com um Gerente! Porque? Pois Gerente é um Funcionario. Essa é a semântica da herança.

Gerente gerente = new Gerente();Funcionario funcionario = gerente;funcionario.setSalario(5000.0);

Polimor�smo é a capacidade de um objeto poder ser referenciado de várias formas. (cuidado, polimor�smo

não quer dizer que o objeto �ca se transformando, muito pelo contrário, um objeto nasce de um tipo emorre

daquele tipo, o que pode mudar é a maneira como nos referimos a ele).

Até aqui tudo bem, mas e se eu tentar:

funcionario.getBonificacao();

Capítulo 7 - Herança, reescrita e polimor�smo - Polimor�smo - Página 90

Material do Treinamento Java e Orientação a Objetos

Qual é o retorno desse método? 500 ou 750? No Java, a invocação de método sempre vai ser decididaem tempo de execução. O Java vai procurar o objeto na memória e, aí sim, decidir qual método deve serchamado, sempre relacionando com sua classe de verdade, e não com a que estamos usando para referenciá-

lo. Apesar de estarmos nos referenciando a esse Gerente como sendo um Funcionario, o método executadoé o do Gerente. O retorno é 750.

Parece estranho criar um gerente e referenciá-lo como apenas um funcionário. Por que faríamos isso? Na

verdade, a situação que costuma aparecer é a que temos um método que recebe um argumento do tipo

Funcionario:

class ControleDeBonificacoes {private double totalDeBonificacoes = 0;

public void registra(Funcionario funcionario) {this.totalDeBonificacoes += funcionario.getBonificacao();

}

public double getTotalDeBonificacoes() {return this.totalDeBonificacoes;

}}

E, em algum lugar da minha aplicação (ou no main, se for apenas para testes):

ControleDeBonificacoes controle = new ControleDeBonificacoes();

Gerente funcionario1 = new Gerente();funcionario1.setSalario(5000.0);controle.registra(funcionario1);

Funcionario funcionario2 = new Funcionario();funcionario2.setSalario(1000.0);controle.registra(funcionario2);

System.out.println(controle.getTotalDeBonificacoes());

Repare que conseguimos passar um Gerente para ummétodo que recebe um Funcionario como argumento.Pense como numa porta na agência bancária com o seguinte aviso: “Permitida a entrada apenas de Funcio-

nários”. Um gerente pode passar nessa porta? Sim, pois Gerente é um Funcionario.

Qual será o valor resultante? Não importa que dentro do método registra do ControleDeBonificacoesreceba Funcionario. Quando ele receber umobjeto que realmente é um Gerente, o seumétodo reescrito seráinvocado. Rea�rmando: não importa como nos referenciamos a um objeto, o método que será invocadoé sempre o que é dele.

Capítulo 7 - Herança, reescrita e polimor�smo - Polimor�smo - Página 91

Material do Treinamento Java e Orientação a Objetos

No dia em que criarmos uma classe Secretaria, por exemplo, que é �lha de Funcionario, precisaremosmudar a classe de ControleDeBonificacoes? Não. Basta a classe Secretaria reescrever os métodos quelhe parecerem necessários. É exatamente esse o poder do polimor�smo, juntamente com a reescrita de mé-

todo: diminuir o acoplamento entre as classes, para evitar que novos códigos resultem em modi�cações em

inúmeros lugares.

Repare que quem criou ControleDeBonificacoes pode nunca ter imaginado a criação da classe Secretariaou Engenheiro. Contudo, não será necessário reimplementar esse controle em cada nova classe: reaprovei-tamos aquele código.

Herança versus acoplamento

Note que o uso de herança aumenta o acoplamento entre as classes, isto é, o quanto uma classedepende de outra. A relação entre classe mãe e �lha é muito forte e isso acaba fazendo com que

o programador das classes �lhas tenha que conhecer a implementação da classe pai e vice-versa

- �ca difícil fazer uma mudança pontual no sistema.

Por exemplo, imagine se tivermos que mudar algo na nossa classe Funcionario, mas não quisés-semos que todos os funcionários sofressem a mesma mudança. Precisaríamos passar por cada

uma das �lhas de Funcionario veri�cando se ela se comporta como deveria ou se devemos so-brescrever o tal método modi�cado.

Esse é um problema da herança, e não do polimor�smo, que resolveremos mais tarde com a

ajuda de Interfaces.

7.5 Um outro exemplo

Imagine que vamos modelar um sistema para a faculdade que controle as despesas com funcionários e pro-

fessores. Nosso funcionário �ca assim:

class EmpregadoDaFaculdade {private String nome;private double salario;double getGastos() {

return this.salario;}String getInfo() {

return "nome: " + this.nome + " com salário " + this.salario;}// métodos de get, set e outros

}

Capítulo 7 - Herança, reescrita e polimor�smo - Um outro exemplo - Página 92

Material do Treinamento Java e Orientação a Objetos

O gasto que temos com o professor não é apenas seu salário. Temos de somar um bônus de 10 reais por

hora/aula. O que fazemos então? Reescrevemos o método. Assim como o getGastos é diferente, o getInfotambém será, pois temos de mostrar as horas/aula também.

class ProfessorDaFaculdade extends EmpregadoDaFaculdade {private int horasDeAula;double getGastos() {

return this.getSalario() + this.horasDeAula * 10;}String getInfo() {

String informacaoBasica = super.getInfo();String informacao = informacaoBasica + " horas de aula: "

+ this.horasDeAula;return informacao;

}// métodos de get, set e outros que forem necessários

}

A novidade, aqui, é a palavra chave super. Apesar do método ter sido reescrito, gostaríamos de acessar ométodo da classe mãe, para não ter de copiar e colocar o conteúdo desse método e depois concatenar com a

informação das horas de aula.

Como tiramos proveito do polimor�smo? Imagine que temos uma classe de relatório:

class GeradorDeRelatorio {public void adiciona(EmpregadoDaFaculdade f) {

System.out.println(f.getInfo());System.out.println(f.getGastos());

}}

Podemos passar para nossa classe qualquer EmpregadoDaFaculdade! Vai funcionar tanto para professor,quanto para funcionário comum.

Um certo dia, muito depois de terminar essa classe de relatório, resolvemos aumentar nosso sistema, e co-

locar uma classe nova, que representa o Reitor. Como ele também é um EmpregadoDaFaculdade, será quevamos precisar alterar algo na nossa classe de Relatorio? Não. Essa é a ideia! Quem programou a classeGeradorDeRelatorio nunca imaginou que existiria uma classe Reitor e, mesmo assim, o sistema funciona.

class Reitor extends EmpregadoDaFaculdade {// informações extras

String getInfo() {return super.getInfo() + " e ele é um reitor";

}// não sobrescrevemos o getGastos!!!

}

Capítulo 7 - Herança, reescrita e polimor�smo - Um outro exemplo - Página 93

Material do Treinamento Java e Orientação a Objetos

7.6 Um pouco mais...

1) Se não houvesse herança em Java, como você poderia reaproveitar o código de outra classe?

2) Uma discussão muito atual é sobre o abuso no uso da herança. Algumas pessoas usam herança apenas

para reaproveitar o código, quando poderiam ter feito uma composição. Procure sobre herança versuscomposição.

3) Mesmo depois de reescrever ummétodo da classe mãe, a classe �lha ainda pode acessar o método antigo.

Isto é feito através da palavra chave super.método(). Algo parecido ocorre entre os construtores dasclasses, o que?

Mais sobre o mau uso da herança

No blog da Caelum existe um artigo interessante abordando esse tópico:

http://blog.caelum.com.br/2006/10/14/como-nao-aprender-orientacao-a-objetos-heranca/

JamesGosling, umdos criadores do Java, é umcrítico domauuso da herança. Nesta entrevista ele

discute a possibilidade de se utilizar apenas interfaces e composição, eliminando a necessidade

da herança:

http://www.artima.com/intv/gosling3P.html

7.7 Exercícios: Herança e Polimorfismo

1) Vamos criar uma classe Conta, que possua um saldo os métodos para pegar saldo, depositar e sacar.

a) Crie a classe Conta:

public class Conta {}

b) Adicione o atributo saldo

public class Conta {private double saldo;

}

c) Crie os métodos getSaldo(), deposita(double) e saca(double)

public class Conta {private double saldo;

public void deposita(double valor) {this.saldo += valor;

}

Capítulo 7 - Herança, reescrita e polimor�smo - Um pouco mais... - Página 94

Material do Treinamento Java e Orientação a Objetos

public void saca(double valor) {this.saldo -= valor;

}

public double getSaldo() {return this.saldo;

}}

2) Adicione um método na classe Conta, que atualiza essa conta de acordo com uma taxa percentual forne-cida.

class Conta {private double saldo;

// outros métodos aqui também ...

void atualiza(double taxa) {this.saldo += this.saldo * taxa;

}}

3) Crie duas subclasses da classe Conta: ContaCorrente e ContaPoupanca. Ambas terão o método atualizareescrito: A ContaCorrente deve atualizar-se com o dobro da taxa e a ContaPoupanca deve atualizar-secom o triplo da taxa.

Além disso, a ContaCorrente deve reescrever o método deposita, a �m de retirar uma taxa bancária dedez centavos de cada depósito.

• Crie as classes ContaCorrente e ContaPoupanca. Ambas são �lhas da classe Conta:

public class ContaCorrente extends Conta {}

public class ContaPoupanca extends Conta {}

• Reescreva o método atualiza na classe ContaCorrente, seguindo o enunciado:

public class ContaCorrente extends Conta {public void atualiza(double taxa) {

this.saldo += this.saldo * taxa * 2;}

}

Repare que, para acessar o atributo saldo herdado da classe Conta, você vai precisar trocar o mo-di�cador de visibilidade de saldo para protected.

Capítulo 7 - Herança, reescrita e polimor�smo - Exercícios: Herança e Polimor�smo - Página 95

Material do Treinamento Java e Orientação a Objetos

• Reescreva o método atualiza na classe ContaPoupanca, seguindo o enunciado:

public class ContaPoupanca extends Conta {public void atualiza(double taxa) {

this.saldo += this.saldo * taxa * 3;}

}

• Na classe ContaCorrente, reescreva o método deposita para descontar a taxa bancária de dez cen-tavos:

public class ContaCorrente extends Conta {public void atualiza(double taxa) {

this.saldo += this.saldo * taxa * 2;}

public void deposita(double valor) {this.saldo += valor - 0.10;

}}

4) Crie uma classe com método main e instancie essas classes, atualize-as e veja o resultado. Algo como:

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

Conta c = new Conta();ContaCorrente cc = new ContaCorrente();ContaPoupanca cp = new ContaPoupanca();

c.deposita(1000);cc.deposita(1000);cp.deposita(1000);

c.atualiza(0.01);cc.atualiza(0.01);cp.atualiza(0.01);

Capítulo 7 - Herança, reescrita e polimor�smo - Exercícios: Herança e Polimor�smo - Página 96

Material do Treinamento Java e Orientação a Objetos

System.out.println(c.getSaldo());System.out.println(cc.getSaldo());System.out.println(cp.getSaldo());

}}

Após imprimir o saldo (getSaldo()) de cada uma das contas, o que acontece?

5) O que você acha de rodar o código anterior da seguinte maneira:

Conta c = new Conta();Conta cc = new ContaCorrente();Conta cp = new ContaPoupanca();

Compila? Roda? O que muda? Qual é a utilidade disso? Realmente, essa não é a maneira mais útil do po-

limor�smo - veremos o seu real poder no próximo exercício. Porém existe uma utilidade de declararmos

uma variável de um tipo menos especí�co do que o objeto realmente é.

É extremamente importante perceber que não importa como nos referimos a um objeto, o método queserá invocado é sempre o mesmo! A JVM vai descobrir em tempo de execução qual deve ser invocado,

dependendo de que tipo é aquele objeto, não importando como nos referimos a ele.

6) (opcional)Vamos criar uma classe que seja responsável por fazer a atualização de todas as contas bancárias

e gerar um relatório com o saldo anterior e saldo novo de cada uma das contas.

Além disso, conforme atualiza as contas, o banco quer saber quanto do dinheiro do banco foi atualizado

até o momento. Por isso, precisamos ir guardando o saldoTotal e adicionar um getter à classe.

public class AtualizadorDeContas {private double saldoTotal = 0;private double selic;

public AtualizadorDeContas(double selic) {this.selic = selic;

}

public void roda(Conta c) {// aqui você imprime o saldo anterior, atualiza a conta,// e depois imprime o saldo final// lembrando de somar o saldo final ao atributo saldoTotal

}

// outros métodos, colocar o getter para saldoTotal!}

7) (opcional) No método main, vamos criar algumas contas e rodá-las:

Capítulo 7 - Herança, reescrita e polimor�smo - Exercícios: Herança e Polimor�smo - Página 97

Material do Treinamento Java e Orientação a Objetos

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

Conta c = new Conta();Conta cc = new ContaCorrente();Conta cp = new ContaPoupanca();

c.deposita(1000);cc.deposita(1000);cp.deposita(1000);

AtualizadorDeContas adc = new AtualizadorDeContas(0.01);

adc.roda(c);adc.roda(cc);adc.roda(cp);

System.out.println("Saldo Total: " + adc.getSaldoTotal());}

}

8) (Opcional) Use a palavra chave super nosmétodos atualiza reescritos, para não ter de refazer o trabalho.

9) (Opcional) Se você precisasse criar uma classe ContaInvestimento, e seu método atualiza fosse com-plicadíssimo, você precisaria alterar a classe AtualizadorDeContas?

10) (Opcional, Trabalhoso) Crie uma classe Banco que possui um array de Conta. Repare que numarray de Conta você pode colocar tanto ContaCorrente quanto ContaPoupanca. Crie um métodopublic void adiciona(Conta c), um método public Conta pegaConta(int x) e outro public intpegaTotalDeContas(), muito similar a relação anterior de Empresa-Funcionario.

Faça com que seu método main crie diversas contas, insira-as no Banco e depois, com um for, percorratodas as contas do Banco para passá-las como argumento para o AtualizadorDeContas.

7.8 Discussões em aula: Alternativas ao atributo protected

Discuta com o instrutor e seus colegas alternativas ao uso do atributo protected na herança. Preciso real-mente afrouxar o encapsulamento do atributo por causa da herança? Como fazer para o atributo continuar

private na mãe e as �lhas conseguirem de alguma formar trabalhar com ele?

Capítulo 7 - Herança, reescrita e polimor�smo - Discussões em aula: Alternativas ao atributo protected - Página 98

Capítulo 8

Eclipse IDE

“Dá-se importância aos antepassados quando já não temos nenhum."– François Chateaubriand

Neste capítulo, você será apresentado ao Ambiente de Desenvolvimento Eclipse e suas principais funciona-

lidades.

8.1 O Eclipse

O Eclipse (http://www.eclipse.org) é uma IDE (integrated development environment). Diferente de uma

RAD, onde o objetivo é desenvolver omais rápido possível através do arrastar-e-soltar domouse, ondemonta-nhas de código são gerados em background, uma IDE te auxilia no desenvolvimento, evitando se intrometer

e fazer muita mágica.

O Eclipse é a IDE líder de mercado. Formada por um consórcio liderado pela IBM, possui seu código livre.

A última versão é a 4.2, mas com qualquer versão posterior a do 3.1 você terá suporte ao Java 5, 6 e 7.

Veremos aqui os principais recursos do Eclipse. Você perceberá que ele evita ao máximo te atrapalhar e ape-

nas gera trechos de códigos óbvios, sempre ao seu comando. Existem também centenas de plugins gratuitos

para gerar diagramas UML, suporte a servidores de aplicação, visualizadores de banco de dados e muitos

outros.

Baixe o Eclipse do site o�cial http://www.eclipse.org. Apesar de ser escrito em Java, a biblioteca grá�ca usada

no Eclipse, chamada SWT, usa componentes nativos do sistema operacional. Por isso você deve baixar a

versão correspondente ao seu sistema operacional.

Descompacte o arquivo e pronto, basta rodar o executável.

Material do Treinamento Java e Orientação a Objetos

Outras IDEs

Uma outra IDE open source famosa é o Netbeans, da Oracle. (http://www.netbeans.org).

Além dessas, Oracle, Borland e a própria IBM possuem IDEs comerciais e algumas versões mais

restritas de uso livre.

A empresa JetBrains desenvolve o IntelliJ IDEA, uma IDE paga que tem ganho muitos adeptos.

8.2 Apresentando o Eclipse

Clique no ícone do Eclipse no seu Desktop.

A primeira pergunta que ele te faz é que workspace você vai usar. Workspace de�ne o diretório em que as

suas con�gurações pessoais e seus projetos serão gravados.

Você pode deixar o diretório pré-de�nido.

Logo em seguida, uma tela de Welcome será aberta, onde você tem diversos links para tutoriais e ajuda.

Clique em Workbench. A tela de Welcome do Eclipse 4 é um pouco diferente, ams possui exatamente os

mesmos recursos nos mesmos locais.

Capítulo 8 - Eclipse IDE - Apresentando o Eclipse - Página 100

Material do Treinamento Java e Orientação a Objetos

8.3 Views e Perspective

Feche a tela de Welcome e você verá a tela abaixo. Nesta tela, destacamos as Views (em linha contínua) e as

Perspectives (em linha pontilhada) do Eclipse.

Capítulo 8 - Eclipse IDE - Views e Perspective - Página 101

Material do Treinamento Java e Orientação a Objetos

Mude para a perspectiva Resource, clicando no ícone ao lado da perspectiva Java, selecionando Other e

depois Resource. Neste momento, trabalharemos com esta perspectiva, antes da de Java, pois ela possui um

conjunto de Views mais simples.

A View Navigator mostra a estrutura de diretório assim como está no sistema de arquivos. A View Outline

mostra um resumo das classes, interfaces e enumerações declaradas no arquivo java atualmente editado

(serve também para outros tipos de arquivos).

Capítulo 8 - Eclipse IDE - Views e Perspective - Página 102

Material do Treinamento Java e Orientação a Objetos

No menuWindow -> Show View -> Other, você pode ver as dezenas de Views que já vem embutidas noEclipse. Acostume-se a sempre procurar novas Views, elas podem te ajudar em diversas tarefas.

8.4 Criando um projeto novo

Vá em File -> New -> Project. Seleciona Java Project e clique em Next.

Capítulo 8 - Eclipse IDE - Criando um projeto novo - Página 103

Material do Treinamento Java e Orientação a Objetos

Crie um projeto chamado banco.

Você pode chegar nessa mesma tela clicando com o botão da direta no espaço da View Navigator e seguindo

o mesmo menu. Nesta tela, con�gure seu projeto como na tela abaixo:

Capítulo 8 - Eclipse IDE - Criando um projeto novo - Página 104

Material do Treinamento Java e Orientação a Objetos

Isto é, marque “create separate source and output folders”, desta maneira seus arquivos java e arquivos class

estarão em diretórios diferentes, para você trabalhar de uma maneira mais organizada.

Clique em Finish. O Eclipse pedirá para trocar a perspectiva para Java; escolha “No” para permanecer emResource. Na View Navigator, você verá o novo projeto e suas pastas e arquivos:

Vamos iniciar nosso projeto criando a classe Conta. Para isso, vá em File -> New -> Other -> Class. Clique

em Next e crie a classe seguindo a tela abaixo:

Clique em Finish. O Eclipse possui diversos wizards, mas usaremos o mínimo deles. O interessante é usar o

Capítulo 8 - Eclipse IDE - Criando um projeto novo - Página 105

Material do Treinamento Java e Orientação a Objetos

code assist e quick �xes que a ferramenta possui e veremos em seguida. Não se atente às milhares de opçõesde cada wizard, a parte mais interessante do Eclipse não é essa.

Escreva o método deposita como abaixo e note que o Eclipse reclama de erro em this.saldo pois esteatributo não existe.

Vamos usar o recurso do Eclipse de quick �x. Coloque o cursor em cima do erro e aperte Ctrl + 1.

O Eclipse sugerirá possíveis formas de consertar o erro; uma delas é, justamente, criar o campo saldo naclasse Conta, que é nosso objetivo. Clique nesta opção.

Este recurso de quick �xes, acessível pelo Ctrl+1, é uma das grandes facilidades do Eclipse e é extremamente

poderoso. Através dele é possível corrigir boa parte dos erros na hora de programar e, como �zemos, eco-

nomizar a digitação de certos códigos repetitivos. No nosso exemplo, não precisamos criar o campo antes;

Capítulo 8 - Eclipse IDE - Criando um projeto novo - Página 106

Material do Treinamento Java e Orientação a Objetos

o Eclipse faz isso para nós. Ele até acerta a tipagem, já que estamos somando ele a um double. O private écolocado por motivos que já estudamos.

Vá ao menu File -> Save para gravar. Control + S tem o mesmo efeito.

8.5 Criando o main

Crie uma nova classe chamada Principal. Vamos colocar ummétodo main para testar nossa Conta. Em vezde digitar todo o método main, vamos usar o code assist do Eclipse. Escreva só main e aperte Ctrl + Espaçologo em seguida.

Capítulo 8 - Eclipse IDE - Criando o main - Página 107

Material do Treinamento Java e Orientação a Objetos

O Eclipse sugerirá a criação do método main completo; selecione esta opção. O control + espaço é chamadode code assist. Assim como os quick �xes são de extrema importância. Experimente usar o code assist emdiversos lugares.

Dentro do método main, comece a digitar o seguinte código:

Conta conta = new Conta();conta.deposita(100.0);

Observe que, na hora de invocar o método sobre o objeto conta, o Eclipse sugere os métodos possíveis. Este

recurso é bastante útil, principalmente quando estivermos programando com classes que não são as nossas,

como da API do Java. O Eclipse aciona este recurso quando você digita o ponto logo após um objeto (e você

pode usar o Ctrl+Espaço para acioná-lo).

Vamos imprimir o saldo com System.out.println. Mas, mesmo nesse código, o Eclipse nos ajuda. Escrevasyso e aperte Ctrl+Espaço que o Eclipse escreverá System.out.println() para você.

Para imprimir, chame o conta.getSaldo():

System.out.println(conta.getSaldo());

Note que o Eclipse acusará erro em getSaldo() porque este método não existe na classe Conta. Vamos usarCtrl+1 em cima do erro para corrigir o problema:

Capítulo 8 - Eclipse IDE - Criando o main - Página 108

Material do Treinamento Java e Orientação a Objetos

OEclipse sugere criar ummétodo getSaldo() na classe Conta. Selecione esta opção e ométodo será inseridoautomaticamente.

public Object getSaldo() {// TODO Auto-generated method stubreturn null;

}

Ele gera um método não exatamente como queríamos, pois nem sempre há como o Eclipse ter de antemão

informações su�cientes para que ele acerta a assinatura do seumétodo. Modi�que ométodo getSaldo comosegue:

public double getSaldo() {return this.saldo;

}

Esses pequenos recursos do Eclipse são de extrema utilidade. Dessa maneira, você pode programar sem se

preocupar com métodos que ainda não existem, já que a qualquer momento ele pode gerar o esqueleto (a

parte da assinatura do método).

8.6 Executando o main

Vamos rodar o método main dessa nossa classe. No Eclipse, clique com o botão direito no arquivoPrincipal.java e vá em Run as... Java Application.

Capítulo 8 - Eclipse IDE - Executando o main - Página 109

Material do Treinamento Java e Orientação a Objetos

O Eclipse abrirá uma View chamada Console onde será apresentada a saída do seu programa:

Quando você precisar rodar de novo, basta clicar no ícone verde de play na toolbar, que roda o programa

anterior. Ao lado desse ícone tem uma setinha onde são listados os 10 últimos executados.

Capítulo 8 - Eclipse IDE - Executando o main - Página 110

Material do Treinamento Java e Orientação a Objetos

8.7 Pequenos truques

O Eclipse possui muitos atalhos úteis para o programador. Sem dúvida os 3 mais importantes de conhecer e

de praticar são:

• Ctrl + 1 Aciona o quick �xes com sugestões para correção de erros.

• Ctrl + Espaço Completa códigos

• Ctrl + 3 Aciona modo de descoberta de menu. Experimente digitar Ctrl+3 e depois digitar ggas eenter. Ou então de Ctrl + 3 e digite new class.

Você pode ler muito mais detalhes sobre esses atalhos no blog da Caelum: http://blog.caelum.com.br/

as-tres-principais-teclas-de-atalho-do-eclipse/

Existem dezenas de outros. Dentre os mais utilizados pelos desenvolvedores da Caelum, escolhemos os

seguintes para comentar:

• Ctrl + F11 roda a última classe que você rodou. É o mesmo que clicar no ícone verde que parece umbotão de play na barra de ferramentas.

• Ctrl + PgUp e Ctrl + PgDown Navega nas abas abertas. Útil quando estiver editando vários arquivosao mesmo tempo.

• Ctrl + Shi� + F Formata o código segundo as convenções do Java

• Ctrl + M Expande a View atual para a tela toda (mesmo efeito de dar dois cliques no título da View)

• Ctrl + Shi� + L Exibe todos os atalhos possíveis.

• Ctrl + O Exibe um outline para rápida navegação

• Alt + Shi� + X e depois J Roda o main da classe atual. Péssimo para pressionar! Mais fácil você digitarControl+3 e depois digitar Run!. Abuse desde já do Control+3

Veremos mais no decorrer do curso, em especial quando virmos pacotes.

8.8 Exercícios: Eclipse

1) Dentro do projeto banco, crie as classes ContaCorrente e ContaPoupanca no nosso projeto do Eclipse.Na classe Conta, crie os métodos atualiza e saca como no capítulo anterior. Desta vez, tente abusar docontrol + espaço e control + 1.

Por exemplo:

publ<ctrl espaco> v<ctrl espaco> atualiza(do<ctrl espaço> taxa){

Repare que até mesmo nomes de variáveis, ele cria para você! Acompanhe as dicas do instrutor.

Muitas vezes, ao criarmos um objeto, nem mesmo declaramos a variável:

Capítulo 8 - Eclipse IDE - Pequenos truques - Página 111

Material do Treinamento Java e Orientação a Objetos

new ContaCorrente();

Vá nessa linha e dê control + 1. Ele vai sugerir e declarará a variável pra você.

2) Imagine que queremos criar um setter do saldo para a classe Conta. Dentro da classe Conta, digite:

setSa<ctrl + espaco>

Omesmo vale no caso de você querer reescrever um método. Dentro de ContaCorrente faça:

atua<ControlEspaco>

3) Vá na sua classe que tem o main e segure o CONTROL apertado enquanto você passa o mouse sobre oseu código. Repare que tudo virou hyperlink. Clique em um método que você está invocando na classe

Conta.

Você pode conseguir o mesmo efeito, de abrir o arquivo no qual o método foi declarado, de umamaneira

ainda mais prática: sem usar o mouse, quando o cursor estiver sobre o que você quer analisar, simples-

mente clique F3.

4) Dê um clique da direita em um arquivo no navigator. Escolha CompareWith -> Local History. O que éesta tela?

Capítulo 8 - Eclipse IDE - Exercícios: Eclipse - Página 112

Material do Treinamento Java e Orientação a Objetos

5) Use o Control + Shi� + F para formatar o seu código. Dessa maneira, ele vai arrumar a bagunça deespaçamento e enters do seu código.

6) (opcional) Crie no seu projeto a classe AtualizadorDeContas como no capítulo anterior.

7) (opcional) O que são os arquivos .project e .classpath? Leia o conteúdo deles.

8) (opcional) Clique da direita no projeto, propriedades. É uma das telas mais importantes do Eclipse, onde

você pode con�gurar diversas informações para o seu projeto, como compilador, versões, formatador e

outros.

Capítulo 8 - Eclipse IDE - Exercícios: Eclipse - Página 113

Material do Treinamento Java e Orientação a Objetos

8.9 Discussão em aula: Refactoring

Existe um menu no Eclipse chamado Refactor. Ele tem opções bastante interessantes para auxiliar na alte-ração de código para melhorar organização ou clareza. Por exemplo, uma de suas funcionalidades é tornar

possível mudar o nome de uma variável, método oumesmo classe de forma que uma alteração (em um lugar

só do sistema) atualize todas as outras vezes que usavam o nome antigo.

Usar bons nomes no seu código é um excelente começo paramantê-lo legível e fácil de dar manutenção! Mas

o assunto “Refatoração” não para por aí: quebrar métodos grandes em menores, dividir classes grandes em

algumas pequenas e mais concisas, melhorar o encapsulamento... todas essas são formas de refatoração. E

esse menu do Eclipse nos ajuda a fazer várias delas.

Capítulo 8 - Eclipse IDE - Discussão em aula: Refactoring - Página 114

Capítulo 9

Classes Abstratas

“Dá-se importância aos antepassados quando já não temos nenhum.”– François Chateaubriand

Ao término desse capítulo, você será capaz de utilizar classes abstratas, quando necessário.

9.1 Repetindo mais código?

Neste capítulo, aconselhamos que você passe a usar o Eclipse. Você já tem conhecimento su�ciente dos erros

de compilação do javac e agora pode aprender as facilidades que o Eclipse te traz ao ajudar você no códigocom os chamados quick �xes e quick assists.

Vamos recordar em como pode estar nossa classe Funcionario:

class Funcionario {

protected String nome;protected String cpf;protected double salario;

public double getBonificacao() {return this.salario * 1.2;

}

// outros métodos aqui

}

Considere o nosso ControleDeBonificacao:

Material do Treinamento Java e Orientação a Objetos

class ControleDeBonificacoes {

private double totalDeBonificacoes = 0;

public void registra(Funcionario f) {System.out.println("Adicionando bonificação do funcionario: " + f);this.totalDeBonificacoes += f.getBonificacao();

}

public double getTotalDeBonificacoes() {return this.totalDeBonificacoes;

}}

Nosso método registra recebe qualquer referência do tipo Funcionario, isto é, podem ser objetos do tipoFuncionario e qualquer de seus subtipos: Gerente, Diretor e, eventualmente, alguma nova subclasse quevenha ser escrita, sem prévio conhecimento do autor da ControleDeBonificacao.

Estamos utilizando aqui a classe Funcionario para o polimor�smo. Se não fosse ela, teríamos um grandeprejuízo: precisaríamos criar ummétodo registra para receber cada um dos tipos de Funcionario, um paraGerente, um para Diretor, etc. Repare que perder esse poder é muito pior do que a pequena vantagem quea herança traz em herdar código.

Porém, em alguns sistemas, como é o nosso caso, usamos uma classe com apenas esses intuitos: de economi-

zar um pouco código e ganhar polimor�smo para criar métodos mais genéricos, que se encaixem a diversos

objetos.

Faz sentido ter um objeto do tipo Funcionario? Essa pergunta é diferente de saber se faz sentido ter umareferência do tipo Funcionario: nesse caso, faz sim e é muito útil.

Referenciando Funcionario temos o polimor�smo de referência, já que podemos receber qualquer objetoque seja um Funcionario. Porém, dar new em Funcionario pode não fazer sentido, isto é, não queremosreceber um objeto do tipo Funcionario, mas sim que aquela referência seja ou um Gerente, ou um Diretor,etc. Algo mais concreto que um Funcionario.

ControleDeBonificacoes cdb = new ControleDeBonificacoes();Funcionario f = new Funcionario();cdb.adiciona(f); // faz sentido?

Vejamos um outro caso em que não faz sentido ter um objeto daquele tipo, apesar da classe existir: imagine

a classe Pessoa e duas �lhas, PessoaFisica e PessoaJuridica. Quando puxamos um relatório de nossosclientes (uma array de Pessoa por exemplo), queremos que cada um deles seja ou uma PessoaFisica, ouuma PessoaJuridica. A classe Pessoa, nesse caso, estaria sendo usada apenas para ganhar o polimor�smoe herdar algumas coisas: não faz sentido permitir instanciá-la.

Para resolver esses problemas, temos as classes abstratas.

Capítulo 9 - Classes Abstratas - Repetindo mais código? - Página 116

Material do Treinamento Java e Orientação a Objetos

9.2 Classe abstrata

O que, exatamente, vem a ser a nossa classe Funcionario? Nossa empresa tem apenas Diretores, Gerentes,Secretárias, etc. Ela é uma classe que apenas idealiza um tipo, de�ne apenas um rascunho.

Para o nosso sistema, é inadmissível que umobjeto seja apenas do tipo Funcionario (pode existir um sistemaem que faça sentido ter objetos do tipo Funcionario ou apenas Pessoa, mas, no nosso caso, não).

Usamos a palavra chave abstract para impedir que ela possa ser instanciada. Esse é o efeito direto de se usaro modi�cador abstract na declaração de uma classe:

abstract class Funcionario {

protected double salario;

public double getBonificacao() {return this.salario * 1.2;

}

// outros atributos e métodos comuns a todos Funcionarios

}

E, no meio de um código:

Funcionario f = new Funcionario(); // não compila!!!

O código acima não compila. O problema é instanciar a classe - criar referência, você pode. Se ela não

pode ser instanciada, para que serve? Serve para o polimor�smo e herança dos atributos e métodos, que são

recursos muito poderosos, como já vimos.

Vamos então herdar dessa classe, reescrevendo o método getBonificacao:

class Gerente extends Funcionario {

public double getBonificacao() {return this.salario * 1.4 + 1000;

}}

Capítulo 9 - Classes Abstratas - Classe abstrata - Página 117

Material do Treinamento Java e Orientação a Objetos

Mas qual é a real vantagem de uma classe abstrata? Poderíamos ter feito isto com uma herança comum. Por

enquanto, a única diferença é que não podemos instanciar umobjeto do tipo Funcionario, que já é de grandevalia, dando mais consistência ao sistema.

Fique claro que a nossa decisão de transformar Funcionario em uma classe abstrata dependeu do nosso do-mínio. Pode ser que, emumsistema comclasses similares, faça sentido que uma classe análoga a Funcionarioseja concreta.

9.3 Métodos abstratos

Se o método getBonificacao não fosse reescrito, ele seria herdado da classe mãe, fazendo com que devol-vesse o salário mais 20%.

Levando em consideração que cada funcionário em nosso sistema tem uma regra totalmente diferente para

ser boni�cado, faz algum sentido ter esse método na classe Funcionario? Será que existe uma boni�caçãopadrão para todo tipo de Funcionario? Parece que não, cada classe �lha terá ummétodo diferente de boni�-cação pois, de acordo com nosso sistema, não existe uma regra geral: queremos que cada pessoa que escreve

a classe de um Funcionario diferente (subclasses de Funcionario) reescreva o método getBonificacao deacordo com as suas regras.

Poderíamos, então, jogar fora esse método da classe Funcionario? O problema é que, se ele não existisse,não poderíamos chamar o método apenas com uma referência a um Funcionario, pois ninguém garanteque essa referência aponta para um objeto que possui esse método. Será que então devemos retornar um

código, como um número negativo? Isso não resolve o problema: se esquecermos de reescrever esse método,

teremos dados errados sendo utilizados como bônus.

Existe um recurso em Java que, em uma classe abstrata, podemos escrever que determinado método será

sempre escrito pelas classes �lhas. Isto é, ummétodo abstrato.

Capítulo 9 - Classes Abstratas - Métodos abstratos - Página 118

Material do Treinamento Java e Orientação a Objetos

Ele indica que todas as classes �lhas (concretas, isto é, que não forem abstratas) devem reescrever essemétodo

ou não compilarão. É como se você herdasse a responsabilidade de ter aquele método.

Como declarar um método abstrato

Às vezes, não �ca claro como declarar um método abstrato.

Basta escrever a palavra chave abstract na assinatura do mesmo e colocar um ponto e vírgulaem vez de abre e fecha chaves!

abstract class Funcionario {

abstract double getBonificacao();

// outros atributos e métodos

}

Repare que não colocamos o corpo do método e usamos a palavra chave abstract para de�nir o mesmo.Por que não colocar corpo algum? Porque esse método nunca vai ser chamado, sempre que alguém chamar

o método getBonificacao, vai cair em uma das suas �lhas, que realmente escreveram o método.

Qualquer classe que estender a classe Funcionario será obrigada a reescrever este método, tornando-o “con-creto”. Se não reescreverem esse método, um erro de compilação ocorrerá.

O método do ControleDeBonificacao estava assim:

public void registra(Funcionario f) {System.out.println("Adicionando bonificação do funcionario: " + f);this.totalDeBonificacoes += f.getBonificacao();

}

Como posso acessar o método getBonificacao se ele não existe na classe Funcionario?

Já que o método é abstrato, com certeza suas subclasses têm esse método, o que garante que essa invocaçãode método não vai falhar. Basta pensar que uma referência do tipo Funcionario nunca aponta para umobjeto que não tem o método getBonificacao, pois não é possível instanciar uma classe abstrata, apenas asconcretas. Ummétodo abstrato obriga a classe em que ele se encontra ser abstrata, o que garante a coerência

do código acima compilar.

9.4 Aumentando o exemplo

E se, no nosso exemplo de empresa, tivéssemos o seguinte diagrama de classes com os seguintes métodos:

Capítulo 9 - Classes Abstratas - Aumentando o exemplo - Página 119

Material do Treinamento Java e Orientação a Objetos

Ou seja, tenho a classe abstrata Funcionario, com o método abstrato getBonificacao; as classes Gerentee Presidente estendendo Funcionario e implementando o método getBonificacao; e, por �m, a classeDiretor, que estende Gerente, mas não implementa o método getBonificacao.

Essas classes vão compilar? Vão rodar?

A resposta é sim. E, além de tudo, farão exatamente o que nós queremos, pois, quando Gerente e Presidentepossuem os métodos perfeitamente implementados, a classe Diretor, que não possui o método implemen-tado, vai usar a implementação herdada de Gerente.

Capítulo 9 - Classes Abstratas - Aumentando o exemplo - Página 120

Material do Treinamento Java e Orientação a Objetos

E esse diagrama, no qual incluímos uma classe abstrata Secretaria sem o método getBonificacao, que éestendida por mais duas classes (SecretariaAdministrativa, SecretariaAgencia) que, por sua vez, imple-mentam o método getBonificacao, vai compilar? Vai rodar?

De novo, a resposta é sim, pois Secretaria é uma classe abstrata e, por isso, o Java tem certeza de que nin-guém vai conseguir instanciá-la e, muito menos, chamar o método getBonificacao dela. Lembrando que,nesse caso, não precisamos nem aomenos escrever ométodo abstrato getBonificacao na classe Secretaria.

Se eu não reescrever um método abstrato da minha classe mãe, o código não compilará. Mas posso, em vez

disso, declarar a classe como abstrata!

java.io

Classes abstratas não possuem nenhum segredo no aprendizado, mas quem está aprendendo

orientação a objetos pode ter uma enorme di�culdade para saber quando utilizá-las, o que é

muito normal.

Estudaremos o pacote java.io, que usa bastantes classes abstratas, sendo um exemplo real de uso

desse recurso, que vai melhorar o entendimento delas. (classe InputStream e suas �lhas)

9.5 Para saber mais...

• Uma classe que estende uma classe normal também pode ser abstrata! Ela não poderá ser instanciada,

mas sua classe pai sim!

• Uma classe abstrata não precisa necessariamente ter um método abstrato.

9.6 Exercícios: Classes Abstratas

1) Repare que a nossa classe Conta é uma excelente candidata para uma classe abstrata. Por quê? Quemétodos seriam interessantes candidatos a serem abstratos?

Transforme a classe Conta em abstrata, repare o que acontece no seu main já existente do TestaContas.

public abstract class Conta {// ...

}

2) Para que o código do main volte a compilar, troque o new Conta() por new ContaCorrente().

Se não podemos dar new em Conta, qual é a utilidade de ter ummétodo que recebe uma referência a Contacomo argumento? Aliás, posso ter isso?

Capítulo 9 - Classes Abstratas - Para saber mais... - Página 121

Material do Treinamento Java e Orientação a Objetos

3) Apenas para entendermelhor o abstract, comente ométodo atualiza() da ContaPoupanca, dessa formaele herdará o método diretamente de Conta.

Transforme o método atualiza() da classe Conta em abstrato. Repare que, ao colocar a palavra chaveabstract ao lado do método, o Eclipse rapidamente vai sugerir que você deve remover o corpo (body)do método com um quick �x:

Sua classe Conta deve �car parecida com:

public abstract class Conta {// atributos e métodos que já existiam

public abstract void atualiza(double taxaSelic);}

Qual é o problema com a classe ContaPoupanca?

4) Reescreva ométodo atualiza() na classe ContaPoupanca para que a classe possa compilar normalmente.O eclipse também sugere isso como um quick �x:

5) (opcional) Existe outra maneira de a classe ContaCorrente compilar se você não reescrever o métodoabstrato?

6) (opcional) Pra que ter o método atualiza na classe Conta se ele não faz nada? O que acontece se sim-plesmente apagarmos esse método da classe Conta e deixarmos o método atualiza nas �lhas?

7) (opcional) Posso chamar um método abstrato de dentro de um outro método da própria classe abstrata?

Um exemplo: o mostra do Funcionario pode invocar this.getBonificacao()?

Capítulo 9 - Classes Abstratas - Exercícios: Classes Abstratas - Página 122

Material do Treinamento Java e Orientação a Objetos

9.7 Desafios

1) Não podemos dar new em Conta, mas por que, então, podemos dar new em Conta[10], por exemplo?

Capítulo 9 - Classes Abstratas - Desa�os - Página 123

Capítulo 10

Interfaces

“Uma imagem vale mil palavras. Uma interface vale mil imagens.”– Ben Shneiderman

Ao término desse capítulo, você será capaz de:

• dizer o que é uma interface e as diferenças entre herança e implementação;

• escrever uma interface em Java;

• utilizá-las como um poderoso recurso para diminuir acoplamento entre as classes.

10.1 Aumentando nosso exemplo

Imagine que um Sistema de Controle do Banco pode ser acessado, além de pelos Gerentes, pelos Diretores

do Banco. Então, teríamos uma classe Diretor:

class Diretor extends Funcionario {

public boolean autentica(int senha) {// verifica aqui se a senha confere com a recebida como parametro

}

}

E a classe Gerente:

class Gerente extends Funcionario {

Material do Treinamento Java e Orientação a Objetos

public boolean autentica(int senha) {// verifica aqui se a senha confere com a recebida como parametro// no caso do gerente verifica também se o departamento dele// tem acesso

}

}

Repare que o método de autenticação de cada tipo de Funcionario pode variar muito. Mas vamos aos pro-blemas. Considere o SistemaInterno e seu controle: precisamos receber um Diretor ou Gerente comoargumento, veri�car se ele se autentica e colocá-lo dentro do sistema.

class SistemaInterno {

void login(Funcionario funcionario) {// invocar o método autentica?// não da! Nem todo Funcionario tem

}}

O SistemaInterno aceita qualquer tipo de Funcionario, tendo ele acesso ao sistema ou não, mas note quenem todo Funcionario possui o método autentica. Isso nos impede de chamar esse método com umareferência apenas a Funcionario (haveria um erro de compilação). O que fazer então?

class SistemaInterno {

void login(Funcionario funcionario) {funcionario.autentica(...); // não compila

}}

Uma possibilidade é criar dois métodos login no SistemaInterno: um para receber Diretor e outro parareceber Gerente. Já vimos que essa não é uma boa escolha. Por quê?

Capítulo 10 - Interfaces - Aumentando nosso exemplo - Página 125

Material do Treinamento Java e Orientação a Objetos

class SistemaInterno {

// design problemáticovoid login(Diretor funcionario) {

funcionario.autentica(...);}

// design problemáticovoid login(Gerente funcionario) {

funcionario.autentica(...);}

}

Cada vez que criarmos uma nova classe de Funcionario que é autenticável, precisaríamos adicionar umnovométodo de login no SistemaInterno.

Métodos com mesmo nome

Em Java, métodos podem ter o mesmo nome desde que não sejam ambíguos, isto é, que exista

uma maneira de distinguir no momento da chamada.

Isso se chama sobrecarga de método. (Overloading. Não confundir com overriding, que é umconceito muito mais poderoso).

Uma solução mais interessante seria criar uma classe no meio da árvore de herança,

FuncionarioAutenticavel:

class FuncionarioAutenticavel extends Funcionario {

public boolean autentica(int senha) {// faz autenticacao padrão

}

// outros atributos e métodos

}

As classes Diretor e Gerente passariam a estender de FuncionarioAutenticavel, e o SistemaInterno re-ceberia referências desse tipo, como a seguir:

class SistemaInterno {

void login(FuncionarioAutenticavel fa) {

Capítulo 10 - Interfaces - Aumentando nosso exemplo - Página 126

Material do Treinamento Java e Orientação a Objetos

int senha = //pega senha de um lugar, ou de um scanner de polegar

// aqui eu posso chamar o autentica!// Pois todo FuncionarioAutenticavel temboolean ok = fa.autentica(senha);

}}

Repare que FuncionarioAutenticavel é uma forte candidata a classe abstrata. Mais ainda, o métodoautentica poderia ser um método abstrato.

O uso de herança resolve esse caso, mas vamos a uma outra situação um pouco mais complexa: precisamos

que todos os clientes também tenham acesso ao SistemaInterno. O que fazer? Uma opção é criar outrométodo login em SistemaInterno: mas já descartamos essa anteriormente.

Uma outra, que é comum entre os novatos, é fazer uma herança sem sentido para resolver o problema,

por exemplo, fazer Cliente extends FuncionarioAutenticavel. Realmente, resolve o problema, mas trarádiversos outros. Clientede�nitivamentenão é FuncionarioAutenticavel. Se você �zer isso, o Cliente terá,por exemplo, um método getBonificacao, um atributo salario e outros membros que não fazem o menorsentido para esta classe! Não faça herança quando a relação não é estritamente “é um”.

Capítulo 10 - Interfaces - Aumentando nosso exemplo - Página 127

Material do Treinamento Java e Orientação a Objetos

Como resolver essa situação? Note que conhecer a sintaxe da linguagem não é o su�ciente, precisamos

estruturar/desenhar bem a nossa estrutura de classes.

10.2 Interfaces

Oque precisamos para resolver nosso problema? Arranjar uma forma de poder referenciar Diretor, Gerentee Cliente de uma mesma maneira, isto é, achar um fator comum.

Se existisse uma forma na qual essas classes garantissem a existência de um determinado método, através de

um contrato, resolveríamos o problema.

Toda classe de�ne 2 itens:

• o que uma classe faz (as assinaturas dos métodos)

• como uma classe faz essas tarefas (o corpo dos métodos e atributos privados)

Podemos criar um “contrato” que de�ne tudo o que uma classe deve fazer se quiser ter um determinado

status. Imagine:

contrato Autenticavel:

quem quiser ser Autenticavel precisa saber fazer:1.autenticar dada uma senha, devolvendo um booleano

Capítulo 10 - Interfaces - Interfaces - Página 128

Material do Treinamento Java e Orientação a Objetos

Quemquiser, pode “assinar” esse contrato, sendo assim obrigado a explicar como será feita essa autenticação.

A vantagem é que, se um Gerente assinar esse contrato, podemos nos referenciar a um Gerente como umAutenticavel.

Podemos criar esse contrato em Java!

interface Autenticavel {

boolean autentica(int senha);

}

Chama-se interface pois é a maneira pela qual poderemos conversar com um Autenticavel. Interface é amaneira através da qual conversamos com um objeto.

Lemos a interface da seguintemaneira: "quem desejar ser autenticável precisa saber autenticar dado um inteiroe retornando um booleano”. Ela é um contrato onde quem assina se responsabiliza por implementar essesmétodos (cumprir o contrato).

Uma interface pode de�nir uma série de métodos, mas nunca conter implementação deles. Ela só expõe oque o objeto deve fazer, e não como ele faz, nem o que ele tem. Como ele faz vai ser de�nido em umaimplementação dessa interface.

E o Gerentepode “assinar” o contrato, ou seja, implementar a interface. Nomomento emque ele implementaessa interface, ele precisa escrever os métodos pedidos pela interface (muito parecido com o efeito de herdar

métodos abstratos, aliás, métodos de uma interface são públicos e abstratos, sempre). Para implementar

usamos a palavra chave implements na classe:

class Gerente extends Funcionario implements Autenticavel {

private int senha;

// outros atributos e métodos

public boolean autentica(int senha) {if(this.senha != senha) {

return false;}// pode fazer outras possíveis verificações, como saber se esse// departamento do gerente tem acesso ao Sistema

return true;}

}

Capítulo 10 - Interfaces - Interfaces - Página 129

Material do Treinamento Java e Orientação a Objetos

O implements pode ser lido da seguinte maneira: “A classe Gerente se compromete a ser tratada comoAutenticavel, sendo obrigada a ter os métodos necessários, de�nidos neste contrato”.

A partir de agora, podemos tratar um Gerente como sendo um Autenticavel. Ganhamos mais po-limor�smo! Temos mais uma forma de referenciar a um Gerente. Quando crio uma variável dotipo Autenticavel, estou criando uma referência para qualquer objeto de uma classe que implementeAutenticavel, direta ou indiretamente:

Autenticavel a = new Gerente();// posso aqui chamar o método autentica!

Novamente, a utilização mais comum seria receber por argumento, como no nosso SistemaInterno:

class SistemaInterno {

void login(Autenticavel a) {int senha = // pega senha de um lugar, ou de um scanner de polegarboolean ok = a.autentica(senha);

// aqui eu posso chamar o autentica!// não necessariamente é um Funcionario!// Mais ainda, eu não sei que objeto a// referência "a" está apontando exatamente! Flexibilidade.

}

}

Pronto! E já podemos passar qualquer Autenticavel para o SistemaInterno. Então precisamos fazer comque o Diretor também implemente essa interface.

Capítulo 10 - Interfaces - Interfaces - Página 130

Material do Treinamento Java e Orientação a Objetos

class Diretor extends Funcionario implements Autenticavel {

// métodos e atributos, além de obrigatoriamente ter o autentica

}

Podemos passar um Diretor. No dia em que tivermos mais um funcionário com acesso ao sistema, bastaque ele implemente essa interface, para se encaixar no sistema.

Qualquer Autenticavel passado para o SistemaInterno está bom para nós. Repare que pouco importaquem o objeto referenciado realmente é, pois ele tem um método autentica que é o necessário para nossoSistemaInterno funcionar corretamente. Aliás, qualquer outra classe que futuramente implemente essainterface poderá ser passada como argumento aqui.

Autenticavel diretor = new Diretor();Autenticavel gerente = new Gerente();

Ou, se achamos que o Fornecedor precisa ter acesso, basta que ele implemente Autenticavel. Olhe só otamanho do desacoplamento: quem escreveu o SistemaInterno só precisa saber que ele é Autenticavel.

class SistemaInterno {

void login(Autenticavel a) {// não importa se ele é um gerente ou diretor// será que é um fornecedor?// Eu, o programador do SistemaInterno, não me preocupo// Invocarei o método autentica

}

}

Capítulo 10 - Interfaces - Interfaces - Página 131

Material do Treinamento Java e Orientação a Objetos

Não faz diferença se é um Diretor, Gerente, Cliente ou qualquer classe que venha por aí. Basta seguir ocontrato! Mais ainda, cada Autenticavel pode se autenticar de uma maneira completamente diferente deoutro.

Lembre-se: a interface de�ne que todos vão saber se autenticar (o que ele faz), enquanto a implementação

de�ne como exatamente vai ser feito (como ele faz).

A maneira como os objetos se comunicam num sistema orientado a objetos é muito mais importante do que

como eles executam. O que um objeto faz é mais importante do que como ele faz. Aqueles que seguemessa regra, terão sistemas mais fáceis de manter e modi�car. Como você já percebeu, esta é uma das ideias

principais que queremos passar e, provavelmente, a mais importante de todo esse curso.

Herança entre interfaces

Diferentemente das classes, uma interface pode herdar de mais de uma interface. É como um

contrato que depende que outros contratos sejam fechados antes deste valer. Você não herda

métodos e atributos, mas sim responsabilidades.

10.3 Dificuldade no aprendizado de interfaces

Interfaces representam uma barreira no aprendizado do Java: parece que estamos escrevendo um código que

não serve pra nada, já que teremos essa linha (a assinatura do método) escrita nas nossas classes implemen-

tadoras. Essa é uma maneira errada de se pensar. O objetivo do uso de uma interface é deixar seu código

mais �exível e possibilitar a mudança de implementação semmaiores traumas. Não é apenas um código deprototipação, um cabeçalho!

Os mais radicais dizem que toda classe deve ser “interfaceada”, isto é, só devemos nos referir a objetos através

de suas interfaces. Se determinada classe não tem uma interface, ela deveria ter. Os autores deste material

acham tal medida radical demais, porém o uso de interfaces em vez de herança é amplamente aconselhado.

Você pode encontrar mais informações sobre o assunto nos livros Design Patterns, Refactoring e E�ectiveJava.

No livro Design Patterns, logo no início, os autores citam 2 regras “de ouro”. Uma é “evite herança, pre�ra

composição” e a outra, “programe voltado a interface e não à implementação”.

Veremos o uso de interfaces no capítulo de coleções, o quemelhora o entendimento do assunto. O exemplo da

interface Comparable também é muito esclarecedor, onde enxergamos o reaproveitamento de código atravésdas interfaces, além do encapsulamento. Para o método Collections.sort(), pouco importa quem vaiser passado como argumento. Para ele, basta que a coleção seja de objetos comparáveis. Ele pode ordenar

Elefante, Conexao ou ContaCorrente, desde que implementem Comparable.

Capítulo 10 - Interfaces - Di�culdade no aprendizado de interfaces - Página 132

Material do Treinamento Java e Orientação a Objetos

10.4 Exemplo interessante: conexões com o banco de dados

Como fazer com que todas as chamadas para bancos de dados diferentes respeitem a mesma regra? Usando

interfaces!

Imagine uma interface Conexao contendo todos osmétodos necessários para a comunicação e troca de dadoscom um banco de dados. Cada banco de dados �ca encarregado de criar a sua implementação para essa

interface.

Quem for usar uma Conexao não precisa se importar com qual objeto exatamente está trabalhando, já que elevai cumprir o papel que toda Conexao deve ter. Não importa se é uma conexão com um Oracle ou MySQL.

Apesar do java.sql.Connection não trabalhar bem assim, a ideia é muito similar, porém as conexões vêmde uma factory chamada DriverManager.

Conexão a banco de dados está fora do escopo desse treinamento, mas é um dos primeiros tópicos abordados

no curso FJ-21, juntamente com DAO.

Um pouco mais...

• Posso substituir toda minha herança por interfaces? Qual é a vantagem e a desvantagem?

• Uma interface também pode declarar constantes (não atributos de objeto). Qual é a utili-

dade?

10.5 Exercícios: Interfaces

1) A sintaxe do uso de interfaces pode parecer muito estranha, à primeira vista.

Capítulo 10 - Interfaces - Exemplo interessante: conexões com o banco de dados - Página 133

Material do Treinamento Java e Orientação a Objetos

Vamos começar com um exercício para praticar a sintaxe. Crie um projeto interfaces e crie a interfaceAreaCalculavel:

interface AreaCalculavel {double calculaArea();

}

Queremos criar algumas classes que são AreaCalculavel:

class Quadrado implements AreaCalculavel {private int lado;

public Quadrado(int lado) {this.lado = lado;

}

public double calculaArea() {return this.lado * this.lado;

}}

class Retangulo implements AreaCalculavel {private int largura;private int altura;

public Retangulo(int largura, int altura) {this.largura = largura;this.altura = altura;

}

public double calculaArea() {return this.largura * this.altura;

}}

Repare que, aqui, se você tivesse usado herança, não iria ganhar muito, já que cada implementação é

totalmente diferente da outra: um Quadrado, um Retangulo e um Circulo têm atributos e métodos bemdiferentes.

Mas,mesmoque eles tivessem atributos em comum, utilizar interfaces é umamaneiramuitomais elegante

de modelar suas classes. Elas também trazem vantagens em não acoplar as classes. Uma vez que herança

através de classes traz muito acoplamento, muitos autores renomados dizem que, na maioria dos casos,

herança quebra o encapsulamento, pensamento com o qual a equipe da Caelum concorda plenamente.

Crie a seguinte classe de Teste. Repare no polimor�smo. Poderíamos passar esses objetos como argu-mento para alguém que aceitasse AreaCalculavel como argumento:

class Teste {

Capítulo 10 - Interfaces - Exercícios: Interfaces - Página 134

Material do Treinamento Java e Orientação a Objetos

public static void main(String[] args) {AreaCalculavel a = new Retangulo(3,2);System.out.println(a.calculaArea());

}}

Opcionalmente, crie a classe Circulo:

class Circulo implements AreaCalculavel {// ... atributos (raio) e métodos (calculaArea)

}

Utilize Math.PI * raio * raio para calcular a área.

2) Nosso banco precisa tributar dinheiro de alguns bens que nossos clientes possuem. Para isso, vamos criar

uma interface no nosso projeto banco já existente:

interface Tributavel {double calculaTributos();

}

Lemos essa interface da seguinte maneira: “todos que quiserem ser tributável precisam saber calculartributos, devolvendo um double”.

Alguns bens são tributáveis e outros não, ContaPoupanca não é tributável, já para ContaCorrente vocêprecisa pagar 1% da conta e o SeguroDeVida tem uma taxa �xa de 42 reais.

Aproveite o Eclipse! Quando você escrever implements Tributavel na classe ContaCorrente, o quick �xdo Eclipse vai sugerir que você reescreva o método; escolha essa opção e, depois, preencha o corpo do

método adequadamente:

class ContaCorrente extends Conta implements Tributavel {

// outros atributos e métodos

public double calculaTributos() {return this.getSaldo() * 0.01;

}}

Crie a classe SeguroDeVida, aproveitando novamente do Eclipse, para obter:

class SeguroDeVida implements Tributavel {public double calculaTributos() {

return 42;}

}

Capítulo 10 - Interfaces - Exercícios: Interfaces - Página 135

Material do Treinamento Java e Orientação a Objetos

Vamos criar uma classe TestaTributavel com ummétodo main para testar o nosso exemplo:

class TestaTributavel {

public static void main(String[] args) {ContaCorrente cc = new ContaCorrente();cc.deposita(100);System.out.println(cc.calculaTributos());

// testando polimorfismo:Tributavel t = cc;System.out.println(t.calculaTributos());

}}

Tente chamar o método getSaldo através da referência t, o que ocorre? Por quê?

A linha em que atribuímos cc a um Tributavel é apenas para você enxergar que é possível fazê-lo. Nessenosso caso, isso não tem uma utilidade. Essa possibilidade será útil para o próximo exercício.

3) (opcional) Crie um GerenciadorDeImpostoDeRenda, que recebe todos os tributáveis de uma pessoa esoma seus valores e inclua nele um método para devolver seu total:

class GerenciadorDeImpostoDeRenda {private double total;

void adiciona(Tributavel t) {System.out.println("Adicionando tributavel: " + t);

this.total += t.calculaTributos();}

public double getTotal() {return this.total;

}}

Capítulo 10 - Interfaces - Exercícios: Interfaces - Página 136

Material do Treinamento Java e Orientação a Objetos

Crie um main para instanciar diversas classes que implementam Tributavel e passar como argumentopara um GerenciadorDeImpostoDeRenda. Repare que você não pode passar qualquer tipo de conta parao método adiciona, apenas a que implementa Tributavel. Além disso, pode passar o SeguroDeVida.

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

GerenciadorDeImpostoDeRenda gerenciador =new GerenciadorDeImpostoDeRenda();

SeguroDeVida sv = new SeguroDeVida();gerenciador.adiciona(sv);

ContaCorrente cc = new ContaCorrente();cc.deposita(1000);gerenciador.adiciona(cc);

System.out.println(gerenciador.getTotal());}

}

Repare que, de dentro do GerenciadorDeImpostoDeRenda, você não pode acessar o método getSaldo,por exemplo, pois você não tem a garantia de que o Tributavel que vai ser passado como argumento temesse método. A única certeza que você tem é de que esse objeto tem os métodos declarados na interface

Tributavel.

É interessante enxergar que as interfaces (como aqui, no caso, Tributavel) costumam ligar classes muitodistintas, unindo-as por uma característica que elas tem em comum. No nosso exemplo, SeguroDeVida eContaCorrente são entidades completamente distintas, porém ambas possuem a característica de seremtributáveis.

Se amanhã o governo começar a tributar até mesmo PlanoDeCapitalizacao, basta que essa classeimplemente a interface Tributavel! Repare no grau de desacoplamento que temos: a classe

GerenciadorDeImpostoDeRenda nem imagina que vai trabalhar como PlanoDeCapitalizacao. Para ela, oúnico fato que importa é que o objeto respeite o contrato de um tributável, isso é, a interface Tributavel.Novamente: programe voltado à interface, não à implementação.

Quais os benefícios de manter o código com baixo acoplamento?

4) (opcional) Use o método printf para imprimir o saldo com exatamente duas casas decimais:

System.out.printf("O saldo é: %.2f", conta.getSaldo());

Capítulo 10 - Interfaces - Exercícios: Interfaces - Página 137

Material do Treinamento Java e Orientação a Objetos

10.6 Exercícios avançados opcionais

Atenção: caso você faça esse exercício, faça isso num projeto à parte conta-interface já que usaremos aConta como classe em exercícios futuros.

1) (Opcional) Transforme a classe Conta em uma interface.

public interface Conta {public double getSaldo();public void deposita(double valor);public void saca(double valor);public void atualiza(double taxaSelic);

}

Adapte ContaCorrente e ContaPoupanca para essa modi�cação:

class ContaCorrente implements Conta {// ...

}

class ContaPoupanca implements Conta {// ...

}

Algum código vai ter de ser copiado e colado? Isso é tão ruim?

2) (Opcional) Às vezes, é interessante criarmos uma interface que herda de outras interfaces: essas, são

chamadas subinterfaces. Essas, nada mais são do que um agrupamento de obrigações para a classe que a

implementar.

interface ContaTributavel extends Conta, Tributavel {}

Dessa maneira, quem for implementar essa nova interface precisa implementar todos os métodos herda-

dos das suas superinterfaces (e talvez ainda novos métodos declarados dentro dela):

class ContaCorrente implements ContaTributavel {// métodos

}

Conta c = new ContaCorrente();Tributavel t = new ContaCorrente();

Repare que o código pode parecer estranho, pois a interface não declara método algum, só herda os

métodos abstratos declarados nas outras interfaces.

Aomesmo tempoque uma interface pode herdar demais de umaoutra interface, classes só podempossuir

uma classe mãe (herança simples).

Capítulo 10 - Interfaces - Exercícios avançados opcionais - Página 138

Material do Treinamento Java e Orientação a Objetos

10.7 Discussão: favoreça composição em relação à herança

Discuta com o instrutor e seus colegas, alternativas à herança. Falaremos de herança versus composição e

porquê a herança é muitas vezes considerada malé�ca.

Numa entrevista, James Gosling, “pai do java”, fala sobre uma linguagem puramente de delegação e chega a

dizer:

Rather than subclassing, just use pure interfaces. It’s not so much that class inheritance is particularly bad. Itjust has problems.

(Tradução livre: "Em vez de fazer subclasses, use simplesmente interfaces. Não é que a herança de classes sejaparticularmente ruim. Ela só tem problemas.”)

http://www.artima.com/intv/gosling3P.html

No blog da Caelum há também um post sobre o assunto: http://blog.caelum.com.br/2006/10/14/

como-nao-aprender-orientacao-a-objetos-heranca/

Capítulo 10 - Interfaces - Discussão: favoreça composição em relação à herança - Página 139

Capítulo 11

Exceções e controle de erros

“Quem pensa pouco, erra muito"– Leonardo da Vinci

Ao término desse capítulo, você será capaz de:

• controlar erros e tomar decisões baseadas nos mesmos;

• criar novos tipos de erros para melhorar o tratamento deles em sua aplicação ou biblioteca;

• assegurar que um método funcionou como diz em seu “contrato”.

11.1 Motivação

Voltando às Contas que criamos no capítulo 6, o que aconteceria ao tentar chamar o método saca com umvalor fora do limite? O sistema mostraria uma mensagem de erro, mas quem chamou o método saca nãosaberá que isso aconteceu.

Como avisar aquele que chamou o método de que ele não conseguiu fazer aquilo que deveria?

Em Java, os métodos dizem qual o contrato que eles devem seguir. Se, ao tentar sacar, ele não consegue fazero que deveria, ele precisa, ao menos, avisar ao usuário que o saque não foi feito.

Veja no exemplo abaixo: estamos forçando uma Conta a ter um valor negativo, isto é, estar num estadoinconsistente de acordo com a nossa modelagem.

Conta minhaConta = new Conta();minhaConta.deposita(100);minhaConta.setLimite(100);

Material do Treinamento Java e Orientação a Objetos

minhaConta.saca(1000);// o saldo é -900? É 100? É 0? A chamada ao método saca funcionou?

Em sistemas de verdade, é muito comum que quem saiba tratar o erro é aquele que chamou o método e não

a própria classe! Portanto, nada mais natural do que a classe sinalizar que um erro ocorreu.

A soluçãomais simples utilizada antigamente é a demarcar o retorno de ummétodo como boolean e retornartrue, se tudo ocorreu da maneira planejada, ou false, caso contrário:

boolean saca(double quantidade) {// posso sacar até saldo+limiteif (quantidade > this.saldo + this.limite) {

System.out.println("Não posso sacar fora do limite!");return false;

} else {this.saldo = this.saldo - quantidade;return true;

}}

Um novo exemplo de chamada ao método acima:

Conta minhaConta = new Conta();minhaConta.deposita(100);minhaConta.setLimite(100);if (!minhaConta.saca(1000)) {

System.out.println("Não saquei");}

Repare que tivemos de lembrar de testar o retorno do método, mas não somos obrigados a fazer isso. Esque-

cer de testar o retorno desse método teria consequências drásticas: a máquina de autoatendimento poderia

vir a liberar a quantia desejada de dinheiro, mesmo que o sistema não tivesse conseguido efetuar o método

saca com sucesso, como no exemplo a seguir:

Conta minhaConta = new Conta();minhaConta.deposita(100);

// ...double valor = 5000;minhaConta.saca(valor); // vai retornar false, mas ninguém verifica!caixaEletronico.emite(valor);

Mesmo invocando o método e tratando o retorno de maneira correta, o que faríamos se fosse necessário

sinalizar quando o usuário passou um valor negativo como quantidade? Uma solução seria alterar o retorno

Capítulo 11 - Exceções e controle de erros - Motivação - Página 141

Material do Treinamento Java e Orientação a Objetos

de boolean para int e retornar o código do erro que ocorreu. Isso é considerado umamá prática (conhecidatambém como uso de “magic numbers”).

Além de você perder o retorno do método, o valor devolvido é “mágico” e só legível perante extensa docu-

mentação, além de não obrigar o programador a tratar esse retorno e, no caso de esquecer isso, seu programa

continuará rodando já num estado inconsistente.

Repare o que aconteceria se fosse necessário retornar um outro valor. O exemplo abaixo mostra um caso

onde, através do retorno, não será possível descobrir se ocorreu um erro ou não, pois o método retorna um

cliente.

public Cliente procuraCliente(int id) {if (idInvalido) {

// avisa o método que chamou este que ocorreu um erro} else {

Cliente cliente = new Cliente();cliente.setId(id);// cliente.setNome("nome do cliente");return cliente;

}}

Por esses e outros motivos, utilizamos um código diferente em Java para tratar aquilo que chamamos de

exceções: os casos onde acontece algo que, normalmente, não iria acontecer. O exemplo do argumento do

saque inválido ou do id inválido de um cliente é uma exceção à regra.

Exceção

Umaexceção representa uma situação que normalmente não ocorre e representa algo de estranho

ou inesperado no sistema.

11.2 Exercício para começar com os conceitos

Antes de resolvermos o nosso problema, vamos ver como a Java Virtual Machine age ao se deparar com

situações inesperadas, como divisão por zero ou acesso a um índice da array que não existe.

1) Para aprendermos os conceitos básicos das exceptions do Java, teste o seguinte código você mesmo:

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

System.out.println("inicio do main");metodo1();System.out.println("fim do main");

}

Capítulo 11 - Exceções e controle de erros - Exercício para começar com os conceitos - Página 142

Material do Treinamento Java e Orientação a Objetos

static void metodo1() {System.out.println("inicio do metodo1");metodo2();System.out.println("fim do metodo1");

}

static void metodo2() {System.out.println("inicio do metodo2");int[] array = new int[10];for (int i = 0; i <= 15; i++) {

array[i] = i;System.out.println(i);

}System.out.println("fim do metodo2");

}}

Repare ométodo main chamando metodo1 e esse, por sua vez, chamando o metodo2. Cada um desses mé-todos pode ter suas próprias variáveis locais, sendo que, por exemplo, o metodo1 não enxerga as variáveisdeclaradas dentro do main.

Como o Java (e muitas das outras linguagens) faz isso? Toda invocação demétodo é empilhada... em uma

estrutura de dados que isola a área de memória de cada um. Quando um método termina (retorna), ele

volta para o método que o invocou. Ele descobre isso através da pilha de execução (stack). Basta jogarfora um gomo da pilha (stackframe):

Porém, o nosso metodo2 propositadamente possui um enorme problema: está acessando um índice dearray indevido para esse caso; o índice estará fora dos limites da array quando chegar em 10!

Rode o código. Qual é a saída? O que isso representa? O que ela indica?

Capítulo 11 - Exceções e controle de erros - Exercício para começar com os conceitos - Página 143

Material do Treinamento Java e Orientação a Objetos

Essa é o conhecido rastro da pilha (stacktrace). É uma saída importantíssima para o programador - tantoque, em qualquer fórum ou lista de discussão, é comum os programadores enviarem, juntamente com a

descrição do problema, essa stacktrace.

Por que isso aconteceu? O sistema de exceções do Java funciona da seguinte maneira: quando uma ex-

ceção é lançada (throws), a JVM entra em estado de alerta e vai ver se o método atual toma algumaprecaução ao tentar executar esse trecho de código. Como podemos ver, o metodo2 não toma nenhumamedida diferente do que vimos até agora.

Como o metodo2 não está tratando esse problema, a JVM pára a execução dele anormalmente, sem es-perar ele terminar, e volta um stackframe pra baixo, onde será feita nova veri�cação: o metodo1 está seprecavendo de um problema chamado ArrayIndexOutOfBoundsException? Não... volta para o main,onde também não há proteção, então a JVMmorre (na verdade, quemmorre é apenas a Thread corrente,veremos mais para frente).

Obviamente, aqui estamos forçando esse caso, e não faria sentido tomarmos cuidado com ele. É fácil

arrumar um problema desses: basta percorrermos a array no máximo até o seu length.

Porém, apenas para entender o controle de �uxode uma Exception, vamos colocar o código que vai tentar(try) executar o bloco perigoso e, caso o problema seja do tipo ArrayIndexOutOfBoundsException, eleserá pego (caught). Repare que é interessante que cada exceção no Java tenha um tipo... ela pode teratributos e métodos.

2) Adicione um try/catch em volta do for, pegando ArrayIndexOutOfBoundsException. O que o códigoimprime?

try {for (int i = 0; i <= 15; i++) {

Capítulo 11 - Exceções e controle de erros - Exercício para começar com os conceitos - Página 144

Material do Treinamento Java e Orientação a Objetos

array[i] = i;System.out.println(i);

}} catch (ArrayIndexOutOfBoundsException e) {

System.out.println("erro: " + e);}

Em vez de fazer o try em torno do for inteiro, tente apenas com o bloco de dentro do for:

for (int i = 0; i <= 15; i++) {try {

array[i] = i;System.out.println(i);

} catch (ArrayIndexOutOfBoundsException e) {System.out.println("erro: " + e);

}}

Qual é a diferença?

Capítulo 11 - Exceções e controle de erros - Exercício para começar com os conceitos - Página 145

Material do Treinamento Java e Orientação a Objetos

Retire o try/catch e coloque ele em volta da chamada do metodo2.

System.out.println("inicio do metodo1");try {

metodo2();} catch (ArrayIndexOutOfBoundsException e) {

System.out.println("erro: " + e);}System.out.println("fim do metodo1");

Capítulo 11 - Exceções e controle de erros - Exercício para começar com os conceitos - Página 146

Material do Treinamento Java e Orientação a Objetos

Faça o mesmo, retirando o try/catch novamente e colocando em volta da chamada do metodo1. Rodeos códigos, o que acontece?

System.out.println("inicio do main");try {

metodo1();} catch (ArrayIndexOutOfBoundsException e) {

System.out.println("Erro : "+e);}System.out.println("fim do main");

Repare que, a partir domomento que uma exception foi catched (pega, tratada, handled), a execução voltaao normal a partir daquele ponto.

11.3 Exceções de Runtime mais comuns

Que tal tentar dividir um número por zero? Será que a JVM consegue fazer aquilo que nós de�nimos que

não existe?

public class TestandoADivisao {

public static void main(String args[]) {int i = 5571;i = i / 0;System.out.println("O resultado " + i);

}}

Tente executar o programa acima. O que acontece?

Capítulo 11 - Exceções e controle de erros - Exceções de Runtime mais comuns - Página 147

Material do Treinamento Java e Orientação a Objetos

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

Conta c = null;System.out.println("Saldo atual " + c.getSaldo());

}}

Tente executar este programa. O que acontece?

Repare que um ArrayIndexOutOfBoundsException ou um NullPointerException poderia ser facilmenteevitado com o for corretamente escrito ou com ifs que checariam os limites da array.

Outro caso em que também ocorre tal tipo de exceção é quando um cast errado é feito (veremos mais pra

frente). Em todos os casos, tais problemas provavelmente poderiam ser evitados pelo programador. É por

esse motivo que o java não te obriga a dar o try/catch nessas exceptions e chamamos essas exceções de un-checked. Em outras palavras, o compilador não checa se você está tratando essas exceções.

Erros

Os erros em Java são um tipo de exceção que também podem ser tratados. Eles representam

problemas namáquina virtual e não devem ser tratados em 99% dos casos, já que provavelmente

o melhor a se fazer é deixar a JVM encerrar (ou apenas a�read em questão).

11.4 Outro tipo de exceção: Checked Exceptions

Fica claro, com os exemplos de código acima, que não é necessário declarar que você está tentando fazer algo

onde um erro possa ocorrer. Os dois exemplos, com ou sem o try/catch, compilaram e rodaram. Em um,o erro terminou o programa e, no outro, foi possível tratá-lo.

Mas não é só esse tipo de exceção que existe em Java. Um outro tipo, obriga a quem chama o método ou

construtor a tratar essa exceção. Chamamos esse tipo de exceção de checked, pois o compilador checará seela está sendo devidamente tratada, diferente das anteriores, conhecidas como unchecked.

Capítulo 11 - Exceções e controle de erros - Outro tipo de exceção: Checked Exceptions - Página 148

Material do Treinamento Java e Orientação a Objetos

Um exemplo interessante é o de abrir um arquivo para leitura, onde pode ocorrer o erro do arquivo não

existir (veremos como trabalhar com arquivos em outro capítulo, não se preocupe com isto agora):

class Teste {public static void metodo() {

new java.io.FileInputStream("arquivo.txt");}

}

O código acima não compila e o compilador avisa que é necessário tratar o FileNotFoundException quepode ocorrer:

Para compilar e fazer o programa funcionar, temos duas maneiras que podemos tratar o problema. O pri-

meiro, é tratá-lo com o try e catch do mesmo jeito que usamos no exemplo anterior, com uma array:

public static void metodo() {

try {new java.io.FileInputStream("arquivo.txt");

} catch (java.io.FileNotFoundException e) {System.out.println("Nao foi possível abrir o arquivo para leitura");

}

}

A segunda forma de tratar esse erro, é delegar ele para quem chamou o nosso método, isto é, passar para a

frente.

public static void metodo() throws java.io.FileNotFoundException {

new java.io.FileInputStream("arquivo.txt");

}

No Eclipse é bem simples fazer tanto um try/catch como um throws:

Tente digitar esse código no eclipse:

Capítulo 11 - Exceções e controle de erros - Outro tipo de exceção: Checked Exceptions - Página 149

Material do Treinamento Java e Orientação a Objetos

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

new java.io.FileInputStream("arquivo.txt");}

}

O Eclipse vai reclamar :

E você tem duas opções:

1) Add throws declaration, que vai gerar:

public class TestaException {public static void main(String[] args) throws FileNotFoundException {

new java.io.FileInputStream("arquivo.txt");}

}

2) Surround with try/catch, que vai gerar:

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

try {new java.io.FileInputStream("arquivo.txt");

} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();

}}

}

No início, existe uma grande tentação de sempre passar o problema pra frente para outros o tratarem. Pode

ser que faça sentido, dependendo do caso, mas não até o main, por exemplo. Acontece que quem tenta

Capítulo 11 - Exceções e controle de erros - Outro tipo de exceção: Checked Exceptions - Página 150

Material do Treinamento Java e Orientação a Objetos

abrir um arquivo sabe como lidar com um problema na leitura. Quem chamou um método no começo do

programa pode não saber ou, pior ainda, tentar abrir cinco arquivos diferentes e não saber qual deles teve

um problema!

Não há uma regra para decidir em que momento do seu programa você vai tratar determinada exceção. Isso

vai depender de em que ponto você tem condições de tomar uma decisão em relação àquele erro. Enquanto

não for omomento, você provavelmente vai preferir delegar a responsabilidade para ométodo que te invocou.

Um outro problema comum é quando trabalhamos com banco de dados:

Boas práticas no tratamento de exceções

No blog da Caelum há um extenso artigo discutindo as boas práticas em relação ao tratamento

de exceções.

http://blog.caelum.com.br/2006/10/07/lidando-com-exceptions/

11.5 Um pouco da grande família Throwable

Uma pequena parte da Família�rowable:

11.6 Mais de um erro

É possível tratar mais de um erro quase que ao mesmo tempo:

Capítulo 11 - Exceções e controle de erros - Um pouco da grande família�rowable - Página 151

Material do Treinamento Java e Orientação a Objetos

1) Com o try e catch:

try {objeto.metodoQuePodeLancarIOeSQLException();

} catch (IOException e) {// ..

} catch (SQLException e) {// ..

}

2) Com o throws:

public void abre(String arquivo) throws IOException, SQLException {// ..

}

3) Você pode, também, escolher tratar algumas exceções e declarar as outras no throws:

public void abre(String arquivo) throws IOException {try {

objeto.metodoQuePodeLancarIOeSQLException();} catch (SQLException e) {

// ..}

}

É desnecessário declarar no throws as exceptions que são unchecked, porém é permitido e às vezes, facilita aleitura e a documentação do seu código.

11.7 Lançando exceções

Lembre-se do método saca da nossa classe Conta. Ele devolve um boolean caso consiga ou não sacar:

boolean saca(double valor) {if (this.saldo < valor) {

return false;} else {

this.saldo-=valor;return true;

}}

Podemos, também, lançar uma Exception, o que é extremamente útil. Dessa maneira, resolvemos o pro-blema de alguém poder esquecer de fazer um if no retorno de um método.

Capítulo 11 - Exceções e controle de erros - Lançando exceções - Página 152

Material do Treinamento Java e Orientação a Objetos

A palavra chave throw, que está no imperativo, lança uma Exception. Isto é bem diferente de throws, queestá no presente do indicativo, e que apenas avisa da possibilidade daquele método lançá-la, obrigando o

outro método que vá utilizar deste de se preocupar com essa exceção em questão.

void saca(double valor) {if (this.saldo < valor) {

throw new RuntimeException();} else {

this.saldo-=valor;}

}

Nonosso caso, lança uma do tipo unchecked. RuntimeException é a exceptionmãe de todas as exceptions un-checked. A desvantagem, aqui, é que ela é muito genérica; quem receber esse erro não sabe dizer exatamentequal foi o problema. Podemos então usar uma Exception mais especí�ca:

void saca(double valor) {if (this.saldo < valor) {

throw new IllegalArgumentException();} else {

this.saldo-=valor;}

}

IllegalArgumentException diz um pouco mais: algo foi passado como argumento e seu método não gos-tou. Ela é uma Exception unchecked pois estende de RuntimeException e já faz parte da biblioteca do java.(IllegalArgumentException é a melhor escolha quando um argumento sempre é inválido como, por exem-plo, números negativos, referências nulas, etc).

Para pegar esse erro, não usaremos um if/else e sim um try/catch, porque faz mais sentido já que a faltade saldo é uma exceção:

Conta cc = new ContaCorrente();cc.deposita(100);

try {cc.saca(100);

} catch (IllegalArgumentException e) {System.out.println("Saldo Insuficiente");

}

Podíamos melhorar ainda mais e passar para o construtor da IllegalArgumentException o motivo da ex-ceção:

Capítulo 11 - Exceções e controle de erros - Lançando exceções - Página 153

Material do Treinamento Java e Orientação a Objetos

void saca(double valor) {if (this.saldo < valor) {

throw new IllegalArgumentException("Saldo insuficiente");} else {

this.saldo-=valor;}

}

O método getMessage() de�nido na classe Throwable (mãe de todos os tipos de erros e exceptions) vairetornar a mensagem que passamos ao construtor da IllegalArgumentException.

try {cc.saca(100);

} catch (IllegalArgumentException e) {System.out.println(e.getMessage());

}

11.8 O que colocar dentro do try?

Imagine que vamos sacar dinheiro de diversas contas:

Conta cc = new ContaCorrente();cc.deposita(100);

Conta cp = new ContaPoupanca();cp.deposita(100);

// sacando das contas:

cc.saca(50);System.out.println("consegui sacar da corrente!");

cp.saca(50);System.out.println("consegui sacar da poupança!");

Podemos escolher vários lugares para colocar try/catch:

try {cc.saca(50);

} catch (IllegalArgumentException e) {System.out.println(e.getMessage());

}System.out.println("consegui sacar da corrente!");

Capítulo 11 - Exceções e controle de erros - O que colocar dentro do try? - Página 154

Material do Treinamento Java e Orientação a Objetos

try {cp.saca(50);

} catch (IllegalArgumentException e) {System.out.println(e.getMessage());

}System.out.println("consegui sacar da poupança!");

Essa não parece uma opção boa, pois a mensagem "consegui sacar” será impressa mesmo que o catch sejaacionado. Sempre que temos algo que depende da linha de cima para ser correto, devemos agrupá-lo no try:

try {cc.saca(50);System.out.println("consegui sacar da corrente!");

} catch (IllegalArgumentException e) {System.out.println(e.getMessage());

}

try {cp.saca(50);System.out.println("consegui sacar da poupança!");

} catch (IllegalArgumentException e) {System.out.println(e.getMessage());

}

Mas há ainda uma outra opção: imagine que, para o nosso sistema, uma falha ao sacar da conta poupança

deve parar o processo de saques e nem tentar sacar da conta corrente. Para isso, agruparíamos mais ainda:

try {cc.saca(50);System.out.println("consegui sacar da corrente!");cp.saca(50);System.out.println("consegui sacar da poupança!");

} catch (IllegalArgumentException e) {System.out.println(e.getMessage());

}

O que você vai colocar dentro do try in�uencia muito a execução do programa! Pense direito nas linhasque dependem uma da outra para a execução correta da sua lógica de negócios.

11.9 Criando seu próprio tipo de exceção

É bem comum criar uma própria classe de exceção para controlar melhor o uso de suas exceções. Dessa

maneira, podemos passar valores especí�cos para ela carregar, que sejam úteis de alguma forma. Vamos

Capítulo 11 - Exceções e controle de erros - Criando seu próprio tipo de exceção - Página 155

Material do Treinamento Java e Orientação a Objetos

criar a nossa:

Voltamos para o exemplo das Contas, vamos criar a nossa Exceção de SaldoInsuficienteException:

public class SaldoInsuficienteException extends RuntimeException {

SaldoInsuficienteException(String message) {super(message);

}}

Em vez de lançar um IllegalArgumentException, vamos lançar nossa própria exception, com uma mensa-gem que dirá “Saldo Insu�ciente":

void saca(double valor) {if (this.saldo < valor) {

throw new SaldoInsuficienteException("Saldo Insuficiente," +"tente um valor menor");

} else {this.saldo-=valor;

}}

E, para testar, crie uma classe que deposite um valor e tente sacar um valor maior:

public static void main(String[] args) {Conta cc = new ContaCorrente();cc.deposita(10);

try {cc.saca(100);

} catch (SaldoInsuficienteException e) {System.out.println(e.getMessage());

}}

Podemos transformar essa Exception de unchecked para checked, obrigando a quem chama esse método adar try-catch, ou throws:

public class SaldoInsuficienteException extends Exception {

SaldoInsuficienteException(String message) {super(message);

}}

Capítulo 11 - Exceções e controle de erros - Criando seu próprio tipo de exceção - Página 156

Material do Treinamento Java e Orientação a Objetos

11.10 Para saber mais: finally

Os blocos try e catch podem conter uma terceira cláusula chamada finally que indica o que deve ser feitoapós o término do bloco try ou de um catch qualquer.

É interessante colocar algo que é imprescindível de ser executado, caso o que você queria fazer tenha dado

certo, ou não. O caso mais comum é o de liberar um recurso no �nally, como um arquivo ou conexão com

banco de dados, para que possamos ter a certeza de que aquele arquivo (ou conexão) vá ser fechado, mesmo

que algo tenha falhado no decorrer do código.

No exemplo a seguir, o bloco finally será sempre executado, independentemente de tudo ocorrer bem oude acontecer algum problema:

try {// bloco try

} catch (IOException ex) {// bloco catch 1

} catch (SQLException sqlex) {// bloco catch 2

} finally {// bloco que será sempre executado, independente// se houve ou não exception e se ela foi tratada ou não

}

Há também, no Java 7, um recurso poderoso conhecido como try-with-resources, que permite utilizar a se-mântica do �nally de uma maneira bem mais simples, como veremos no capítulo

11.11 Exercícios: Exceções

1) Na classe Conta, modi�que o método deposita(double x): Ele deve lançar uma exception chamadaIllegalArgumentException, que já faz parte da biblioteca do java, sempre que o valor passado comoargumento for inválido (por exemplo, quando for negativo).

void deposita(double valor) {if (valor < 0) {

throw new IllegalArgumentException();} else {

this.saldo += valor;}

}

2) Crie uma classe TestaDeposita com o método main. Crie uma ContaPoupanca e tente depositar valoresinválidos:

Capítulo 11 - Exceções e controle de erros - Para saber mais: �nally - Página 157

Material do Treinamento Java e Orientação a Objetos

public static void main(String[] args) {Conta cp = new ContaPoupanca();cp.deposita(-100);

}

O que acontece? Uma IllegalArgumentException é lançada uma vez que tentamos depositar um valorinválido. Adicione o try/catch para tratar o erro:

public static void main(String[] args) {Conta cp = new ContaPoupanca();

try {cp.deposita(-100);

} catch (IllegalArgumentException e) {System.out.println("Você tentou depositar um valor inválido");

}}

Atenção: se a sua classe ContaCorrente está reescrevendo o método deposita e não utiliza dosuper.deposita, ela não lançará a exception no caso do valor negativo! Você pode resolver isso utili-zando o super.deposita, ou fazendo apenas o teste com ContaPoupanca.

3) Ao lançar a IllegalArgumentException, passe via construtor uma mensagem a ser exibida. Lembre quea String recebida como parâmetro é acessível depois via o método getMessage() herdado por todas asExceptions.

void deposita(double valor) {if (valor < 0) {

throw new IllegalArgumentException("Você tentou depositar" +" um valor negativo");

} else {this.saldo += valor - 0.10;

}}

4) Altere sua classe TestaDeposita para exibir a mensagem da exceção através da chamada do

getMessage():

public static void main(String[] args) {Conta cp = new ContaPoupanca();

try {cp.deposita(-100);

} catch (IllegalArgumentException e) {System.out.println(e.getMessage());

}}

Capítulo 11 - Exceções e controle de erros - Exercícios: Exceções - Página 158

Material do Treinamento Java e Orientação a Objetos

5) Crie sua própria Exception, ValorInvalidoException. Para isso, você precisa criar uma classe com essenome que estenda de RuntimeException.

class ValorInvalidoException extends RuntimeException {

}

Lance-a em vez de IllegalArgumentException.

Atenção: nem sempre é interessante criarmos um novo tipo de exception! Depende do caso. Neste aqui,

seria melhor ainda utilizarmos IllegalArgumentException. A boa prática diz que devemos preferir usaras já existentes do Java sempre que possível.

6) (opcional) Coloque um construtor na classe ValorInvalidoException que receba valor inválido que eletentou passar (isto é, ele vai receber um double valor).

Quando estendemos uma classe, não herdamos seus construtores, mas podemos acessá-los através da

palavra chave super de dentro de um construtor. As exceções do Java possuem uma série de constru-tores úteis para poder populá-las já com uma mensagem de erro. Então vamos criar um construtor em

ValorInvalidoException que delegue para o construtor de sua mãe. Essa vai guardar essa mensagempara poder mostrá-la ao ser invocado o método getMessage:

class ValorInvalidoException extends RuntimeException {

ValorInvalidoException(double valor) {super("Valor invalido: " + valor);

}

}

Dessa maneira, na hora de dar o throw new ValorInvalidoException você vai precisar passar esse valorcomo argumento:

if (valor < 0) {throw new ValorInvalidoException(valor);

}

Atenção! Você pode se aproveitar do Eclipse para isso: comece já passando o valor como argumento parao construtor da exception, e o eclipse vai reclamar que não existe tal construtor. O quick �x vai sugerir

que ele seja construindo, poupando-lhe tempo!

7) (opcional) Declare a classe ValorInvalidoException como �lha direta de Exception em vez de

RuntimeException. Ela passa a ser checked. O que isso resulta?

Você vai precisar avisar que o seu método deposita() throws ValorInvalidoException, pois ela é umachecked exception. Além disso, quem chama essemétodo vai precisar tomar uma decisão entre try-catchou throws. Faça uso do quick �x do Eclipse novamente!

Depois, retorne a exception para unchecked, isto é, para ser �lha de RuntimeException, pois iremosutilizá-la assim em exercícios dos capítulos posteriores.

Capítulo 11 - Exceções e controle de erros - Exercícios: Exceções - Página 159

Material do Treinamento Java e Orientação a Objetos

11.12 Desafios

1) O que acontece se acabar a memória da java virtual machine? Como forçar isso?

11.13 Discussão em aula: catch e throws em Exception

Existe uma péssima prática de programação em java que é a de escrever o catch e o throws com Exception.

Existem códigos que sempre usam Exception pois isso cuida de todos os possíveis erros. O maior problemadisso é generalizar o erro. Se alguém joga algo do tipo Exception para quem o chamou, quem recebe nãosabe qual o tipo especí�co de erro ocorreu e não vai saber como tratar o mesmo.

Sim, há casos onde o tratamento demais de uma exception pode ser feito de umamesmamaneira. Por exem-

plo, se queremos terminar a aplicação tanto no caso de IOException quanto em SQLException. Se �zermoscatch(Exception e) para pegar esses dois casos, teremos um problema: a aplicação vai parar mesmo queoutra exceção seja lançada. A solução correta seria ter dois catches, mas aí teríamos código repetido. Para

evitar o código repetido, podemos usar o multi-catch do Java 7, que permite ummesmo catch cuidar de mais

de 1 exceção, através da sintaxe catch(IOException | SQLException e) { ... } .

Capítulo 11 - Exceções e controle de erros - Desa�os - Página 160

Capítulo 12

Pacotes - Organizando suas classes e bibliotecas

“Uma discussão prolongada signi�ca que ambas as partes estão erradas”– Voltaire

Ao término desse capítulo, você será capaz de:

• separar suas classes em pacotes;

• preparar arquivos simples para distribuição.

12.1 Organização

Quando um programador utiliza as classes feitas por outro, surge um problema clássico: como escrever duas

classes com o mesmo nome?

Por exemplo: pode ser que a minha classe de Data funcione de um certo jeito, e a classe Data de um colega,de outro jeito. Pode ser que a classe de Data de uma biblioteca funcione ainda de uma terceira maneiradiferente.

Como permitir que tudo isso realmente funcione? Como controlar quem quer usar qual classe de Data?

Pensando um pouco mais, notamos a existência de um outro problema e da própria solução: o sistema

operacional não permite a existência de dois arquivos com o mesmo nome sob o mesmo diretório, portanto

precisamos organizar nossas classes em diretórios diferentes.

Os diretórios estão diretamente relacionados aos chamados pacotes e costumam agrupar classes de funcio-nalidades similares ou relacionadas.

Por exemplo, no pacote java.util temos as classes Date, SimpleDateFormat e GregorianCalendar; todaselas trabalham com datas de formas diferentes.

Material do Treinamento Java e Orientação a Objetos

12.2 Diretórios

Se a classe Cliente está no pacote banco, ela deverá estar no diretório com o mesmo nome: banco. Se ela selocaliza no pacote br.com.caelum.banco, signi�ca que está no diretório br/com/caelum/banco.

A classe Cliente, que se localiza nesse último diretório mencionado, deve ser escrita da seguinte forma:

package br.com.caelum.banco;

class Cliente {// ...

}

Fica fácil notar que a palavra chave package indica qual o pacote/diretório contém esta classe.

Um pacote pode conter nenhum ou mais subpacotes e/ou classes dentro dele.

Padrão da nomenclatura dos pacotes

O padrão da sun para dar nome aos pacotes é relativo ao nome da empresa que desenvolveu a

classe:

br.com.nomedaempresa.nomedoprojeto.subpacotebr.com.nomedaempresa.nomedoprojeto.subpacote2br.com.nomedaempresa.nomedoprojeto.subpacote2.subpacote3

Os pacotes só possuem letras minúsculas, não importa quantas palavras estejam contidas nele.

Esse padrão existe para evitar ao máximo o con�ito de pacotes de empresas diferentes.

As classes do pacote padrão de bibliotecas não seguem essa nomenclatura, que foi dada para

bibliotecas de terceiros.

Capítulo 12 - Pacotes - Organizando suas classes e bibliotecas - Diretórios - Página 162

Material do Treinamento Java e Orientação a Objetos

12.3 Import

Para usar uma classe do mesmo pacote, basta fazer referência a ela como foi feito até agora simples-

mente escrevendo o próprio nome da classe. Se quisermos que a classe Banco �que dentro do pacotebr.com.caelum.banco, ela deve ser declarada assim:

package br.com.caelum.banco;

class Banco {String nome;Cliente clientes[];

}

Para a classe Cliente �car no mesmo pacote, seguimos a mesma fórmula:

package br.com.caelum.banco;

class Cliente {String nome;String endereco;

}

A novidade chega ao tentar utilizar a classe Banco (ou Cliente) em uma outra classe que esteja fora dessepacote, por exemplo, no pacote br.com.caelum.util:

package br.com.caelum.banco.util;

class TesteDoBanco {

public static void main(String args[]) {br.com.caelum.banco.Banco meuBanco = new br.com.caelum.banco.Banco();meuBanco.nome = "Banco do Brasil";System.out.println(meuBanco.nome);

}

}

Repare que precisamos referenciar a classe Banco com todo o nome do pacote na sua frente. Esse é o conhe-cido Fully Quali�ed Name de uma classe. Em outras palavras, esse é o verdadeiro nome de uma classe, porisso duas classes com o mesmo nome em pacotes diferentes não con�itam.

Mesmo assim, ao tentar compilar a classe anterior, surge um erro reclamando que a classe Banco não estávisível.

Capítulo 12 - Pacotes - Organizando suas classes e bibliotecas - Import - Página 163

Material do Treinamento Java e Orientação a Objetos

Acontece que as classes só são visíveis para outras no mesmo pacote e, para permitir que a classeTesteDoBanco veja e acesse a classe Banco em outro pacote, precisamos alterar essa última e transformá-laem pública:

package br.com.caelum.banco;

public class Banco {String nome;Cliente clientes[] = new Cliente[2];

}

A palavra chave public libera o acesso para classes de outros pacotes. Do mesmo jeito que o compiladorreclamou que a classe não estava visível, ele reclama que o atributo/variável membro também não está. É

fácil deduzir como resolver o problema: utilizando novamente o modi�cador public:

package br.com.caelum.banco;

public class Banco {public String nome;public Cliente clientes[] = new Cliente[2];

}

Podemos testar nosso exemplo anterior, lembrando que utilizar atributos como público não traz encapsula-

mento e está aqui como ilustração.

Voltando ao código do TesteDoBanco, é necessário escrever todo o pacote para identi�car qual classe quere-mos usar? O exemplo que usamos �cou bem complicado de ler:

br.com.caelum.banco.Banco meuBanco = new br.com.caelum.banco.Banco();

Existe uma maneira mais simples de se referenciar a classe Banco: basta importá-la do pacotebr.com.caelum.banco:

package br.com.caelum.banco.util;

// para podermos referenciar// a Banco diretamenteimport br.com.caelum.banco.Banco;

class TesteDoBanco {

public static void main(String args[]) {Banco meuBanco = new Banco();meuBanco.nome = "Banco do Brasil";

Capítulo 12 - Pacotes - Organizando suas classes e bibliotecas - Import - Página 164

Material do Treinamento Java e Orientação a Objetos

}

}

Isso faz com que não precisemos nos referenciar utilizando o fully quali�ed name, podendo utilizar Bancodentro do nosso código em vez de escrever o longo br.com.caelum.banco.Banco.

package, import, class

É muito importante manter a ordem! Primeiro, aparece uma (ou nenhuma) vez o package; de-pois, pode aparecer um ou mais imports; e, por último, as declarações de classes.

import x.y.z.*;

Épossível “importar umpacote inteiro” (todas as classes do pacote, exceto os subpacotes) atravésdo coringa *:

import java.util.*;

Importar todas as classes de um pacote não implica em perda de performance em tempo de

execução, mas pode trazer problemas com classes de mesmo nome! Além disso, importar de um

em um é considerado boa prática, pois facilita a leitura para outros programadores. Uma IDE

como o Eclipse já vai fazer isso por você, assim como a organização em diretórios.

12.4 Acesso aos atributos, construtores e métodos

Osmodi�cadores de acesso existentes em Java são quatro, e até o momento já vimos três, mas só explicamos

dois.

• public - Todos podem acessar aquilo que for de�nido como public. Classes, atributos, construtorese métodos podem ser public.

• protected - Aquilo que é protected pode ser acessado por todas as classes do mesmo pacote e portodas as classes que o estendam, mesmo que essas não estejam no mesmo pacote. Somente atributos,

construtores e métodos podem ser protected.

• padrão (semnenhummodi�cador) - Se nenhummodi�cador for utilizado, todas as classes domesmopacote têm acesso ao atributo, construtor, método ou classe.

• private - A única classe capaz de acessar os atributos, construtores e métodos privados é a própriaclasse. Classes, como conhecemos, não podem ser private, mas atributos, construtores e métodos

Capítulo 12 - Pacotes - Organizando suas classes e bibliotecas - Acesso aos atributos, construtores e métodos - Página 165

Material do Treinamento Java e Orientação a Objetos

sim.

Classes públicas

Para melhor organizar seu código, o Java não permite mais de uma classe pública por arquivo e

o arquivo deve ser NomeDaClasse.java.

Uma vez que outros programadores irão utilizar essa classe, quando precisarem olhar o código

da mesma, �ca mais fácil encontrá-la sabendo que ela está no arquivo de mesmo nome.

Classes aninhadas podem ser protected ou private, mas esse é um tópico avançado que nãoserá estudado nesse momento.

12.5 Usando o Eclipse com pacotes

Você pode usar a perspectiva Java do Eclipse. A view principal de navegação é o Package Explorer, que agrupaclasses pelos pacotes em vez de diretórios (você pode usá-la em conjunto com a Navigator, basta tambémabri-la peloWindow/Show View/Package Explorer).

Antes de movermos nossas classes, declare-as como públicas e coloque-as em seus respectivos arquivos: um

Capítulo 12 - Pacotes - Organizando suas classes e bibliotecas - Usando o Eclipse com pacotes - Página 166

Material do Treinamento Java e Orientação a Objetos

arquivo para cada classe.

Você pode mover uma classe de pacote arrastando-a para o destino desejado. Repare que o Eclipse já declara

packages e imports necessários:

No Eclipse nunca precisamos declarar um import, pois ele sempre vai sugerir isso quando usarmos oCtrl+Espaço no nome de uma classe.

Você também pode usar o Ctrl+1 no caso da declaração de pacote possuir algum erro.

12.6 Exercícios: Pacotes

Atenção: utilize os recursos do Eclipse para realizar essas mudanças. Use a view package-explorer, que vaiauxiliar bastante a manipulação dos arquivos e diretórios. Também utilize os quick �xes quando o Eclipse

reclamar dos diversos problemas de compilação que aparecerão. É possível fazer esse exercício inteiro semmodi�car uma linha de código manualmente. Aproveite para praticar e descobrir o Eclipse, evite usá-loapenas como um editor de texto.

Por exemplo, com o Eclipse nunca precisamos nos preocupar com os imports: ao usar o auto complete, ele

já joga o import lá em cima. E, se você não fez isso, ele sugere colocar o import.

1) Clique da direita no src do seu projeto e escolhendo New/Package, ponha o seu sistema de Contas parautilizar pacotes. Respeite a convenção de código da Sun, por exemplo:

Capítulo 12 - Pacotes - Organizando suas classes e bibliotecas - Exercícios: Pacotes - Página 167

Material do Treinamento Java e Orientação a Objetos

br.com.empresa.banco: colocar classes com o método main aqui (os Testes)

br.com.empresa.banco.conta : colocar Conta, suas �lhas e exceptions aqui

br.com.empresa.banco.sistema : colocar AtualizadorDeContas aqui

Antes de corrigir qualquer erro de compilação, primeiro mova todas as suas classes, sem deixar nenhuma

no pacote default.

2) Caso necessário, coloque cada classe em seu respectivo arquivo .java. Faça isso independente de ela serpública (é uma boa prática).

3) O código não vai compilar prontamente, pois muitos métodos que declaramos são package-privatequando, na verdade, precisaríamos que eles fossem public.

O mesmo vale para as classes: algumas delas precisarão ser públicas.

Use o recurso de quick �x do Eclipse aqui: ele mesmo vai sugerir que o modi�cador de acesso deve ser

público. Para isso, clique no quick �x que aparecerá no erro do import e das invocações de métodos.

4) Abra a view Navigator para ver como�cou os arquivos no sistema de arquivos do seu sistema operacional.Para isso, use o menuWindow, Show View.

Capítulo 12 - Pacotes - Organizando suas classes e bibliotecas - Exercícios: Pacotes - Página 168

Capítulo 13

Ferramentas: jar e javadoc

“Perder tempo em aprender coisas que não interessam, priva-nos de descobrir coisas interessantes”– Carlos Drummond de Andrade

Ao término desse capítulo, você será capaz de:

• criar o JAR do seu aplicativo;

• colocar um JAR no build path do seu projeto;

• ler um javadoc;

• criar o javadoc do seu aplicativo.

13.1 Arquivos, bibliotecas e versões

Assim que um programa �ca pronto, é meio complicado enviar dezenas ou centenas de classes para cada

cliente que quer utilizá-lo.

O jeito mais simples de trabalhar com um conjunto de classes é compactá-los em um arquivo só. O formato

de compactação padrão é o ZIP com a extensão do arquivo compactado JAR.

O arquivo .jar

O arquivo jar ou Java ARchive, possui um conjunto de classes (e arquivos de con�gurações)compactados, no estilo de um arquivo zip. O arquivo jar pode ser criado com qualquer com-pactador zip disponível no mercado, inclusive o programa jar que vem junto com o JDK.

Material do Treinamento Java e Orientação a Objetos

Para criar um arquivo jar do nosso programa de banco, basta ir ao diretório onde estão contidas as

classes e usar o comando a seguir para criar o arquivo banco.jar com todas as classes dos pacotesbr.com.caelum.util e br.com.caelum.banco:

jar -cvf banco.jar br/com/caelum/util/*.class br/com/caelum/banco/*.class

Para usar esse arquivo banco.jar para rodar o TesteDoBanco basta rodar o java com o arquivo jar comoargumento:

java -classpath banco.jar br.com.caelum.util.TesteDoBanco

Para adicionar mais arquivos .jar, que podem ser bibliotecas, ao programa basta rodar o java da seguintemaneira:

java -classpath biblioteca1.jar;biblioteca2.jar NomeDaClasse

Vale lembrar que o ponto e vírgula utilizado só é válido em ambiente Windows. Em Linux, Mac e outros

Unix, é o dois pontos (varia de acordo com o sistema operacional).

Há também um arquivo de manifesto que contém informações do seu jar como, por exemplo, qual classe

ele vai rodar quando o jar for chamado. Mas não se preocupe pois, com o Eclipse, esse arquivo é gerado

automaticamente.

Bibliotecas

Diversas bibliotecas podem ser controladas de acordo com a versão por estarem sempre

compactadas em um arquivo .jar. Basta veri�car o nome da biblioteca (por exemplo

log4j-1.2.13.jar) para descobrir a versão dela.

Então é possível rodar dois programas ao mesmo tempo, cada um utilizando uma versão da

biblioteca através do parâmetro -classpath do java.

Criando um .jar automaticamente

Existemdiversas ferramentas que servempara automatizar o processo de deploy, que consiste em

compilar, gerar documentação, bibliotecas etc. As duas mais famosas são o ANT e oMAVEN,ambos são projetos do grupo Apache.

O Eclipse pode gerar facilmente um jar, porém, se o seu build é complexo e precisa preparar e

copiar uma série de recursos, as ferramentas indicadas acima possuem so�sticadas maneiras de

rodar um script batch.

Capítulo 13 - Ferramentas: jar e javadoc - Arquivos, bibliotecas e versões - Página 170

Material do Treinamento Java e Orientação a Objetos

13.2 Gerando o JAR pelo Eclipse

Neste exemplo, vamos gerar o arquivo JAR do nosso projeto a partir do Eclipse:

1) Clique com o botão direito em cima do nome do seu projeto e selecione a opção Export.

2) Na tela Export (como mostra a �gura abaixo), selecione a opção “JAR �le” e aperte o botão “Next”.

Capítulo 13 - Ferramentas: jar e javadoc - Gerando o JAR pelo Eclipse - Página 171

Material do Treinamento Java e Orientação a Objetos

3) Na opção “JAR �le:”, selecione o local que você deseja salvar o arquivo JAR. E aperte “Next”.

Capítulo 13 - Ferramentas: jar e javadoc - Gerando o JAR pelo Eclipse - Página 172

Material do Treinamento Java e Orientação a Objetos

4) Na próxima tela, simplesmente clique em next, pois não há nenhuma con�guração a ser feita.

5) Na tela abaixo, na opção “select the class of the application entry point”, você deve escolher qual classe

será a classe que vai rodar automaticamente quando você executar o JAR.

6) Entre na linha de comando: java -jar banco.jar

É comum dar um nome mais signi�cativo aos JARs, incluindo nome da empresa, do projeto e versão, como

caelum-banco-1.0.jar.

13.3 Javadoc

Como vamos saber o que cada classe tem no Java? Quais são seus métodos, o que eles fazem?

Aqui na Caelum, você pode acessar a documentação digitando na barra de endereço do Browser:

/caelum/docs/api/index.html

E, a partir da Internet, você pode acessar através do link: http://docs.oracle.com/javase/7/docs/api/

Capítulo 13 - Ferramentas: jar e javadoc - Javadoc - Página 173

Material do Treinamento Java e Orientação a Objetos

No site da Sun, você pode (e deve) baixar a documentação das bibliotecas do Java, frequentemente referida

como “javadoc” ou API (sendo na verdade a documentação da API).

Nesta documentação, no quadro superior esquerdo, você encontra os pacotes e, no inferior esquerdo, está a

listagem das classes e interfaces do respectivo pacote (ou de todos, caso nenhum tenha sido especi�cado).

Clicando-se em uma classe ou interface, o quadro da direita passa a detalhar todos atributos e métodos.

Repare que métodos e atributos privados não estão aí. O importante é documentar o que sua classe faz,

e não como ela faz: detalhes de implementação, como atributos e métodos privados, não interessam ao

desenvolvedor que usará a sua biblioteca (ou, ao menos, não deveriam interessar).

Você também consegue gerar esse javadoc a partir da linha de comando, com o comando: javadoc.

13.4 Gerando o Javadoc

Para gerar o Javadoc a partir do Eclipse é muito simples, siga os passos abaixo:

1) Na barra de menu, selecione o menu Project, depois a opção “Generate Javadoc...”. (apenas disponível se

estiver na perspectiva Java, mas você pode acessar o mesmo wizard pelo export do projeto).

Capítulo 13 - Ferramentas: jar e javadoc - Gerando o Javadoc - Página 174

Material do Treinamento Java e Orientação a Objetos

2) Em seguida, aparecerão as opções para gerar a documentação do seu sistema, selecione todas as clas-

ses do seu sistema e deixe as outras opções como estão. Não esqueça de marcar o caminho da opção

“Destination”, pois é lá que estará sua documentação.

Capítulo 13 - Ferramentas: jar e javadoc - Gerando o Javadoc - Página 175

Material do Treinamento Java e Orientação a Objetos

3) Abra a documentação através do caminho que você marcou e abra o arquivo index.html, que vai chamar

uma página semelhante a essa da �gura abaixo.

Capítulo 13 - Ferramentas: jar e javadoc - Gerando o Javadoc - Página 176

Material do Treinamento Java e Orientação a Objetos

Para colocarmos comentários na documentação, devemos adicionar ao código, sob forma de comentário,

abrindo o texto com /** e fechando com */ e, nas outras linhas, apenas colocando *. Também podemosde�nir outras informações neste texto, como: autor, versão, parâmetros, retorno, etc. Adicione alguns

comentários ao seu projeto como abaixo:

/*** Classe responsável por moldar as Contas do Banco** @author Manoel Santos da Silva*/

public abstract class Conta{...

}

Ou adicione alguns comentários em algum método seu:

/*** Metodo que incrementa o saldo.* @param valor*/

Capítulo 13 - Ferramentas: jar e javadoc - Gerando o Javadoc - Página 177

Material do Treinamento Java e Orientação a Objetos

public void deposita(double valor) {...

}

Veja como �cou:

13.5 Exercícios: Jar e Javadoc

1) Gere um jar do seu sistema com o arquivo de manifesto. Execute-o com java -jar:

java -jar caelum-banco-1.0.jar

Se o Windows ou o Linux foi con�gurado para trabalhar com a extensão .jar, basta você dar um duploclique no arquivo, que ele será “executado” (o arquivo de manifesto será lido para que ele possa descobrir

qual é a classe com main que o Java deve processar).

2) Gere o javadoc do seu sistema. Para isso, vá ao menu Project, depois a opçãoGenerate Javadoc... se estiverna perspectiva Java, ou então de um clique com o botão direito no seu projeto, escolha Export e depoisjavadoc e siga o procedimento descrito na última seção deste capítulo.

Capítulo 13 - Ferramentas: jar e javadoc - Exercícios: Jar e Javadoc - Página 178

Material do Treinamento Java e Orientação a Objetos

Interface versus implementação novamente!

Repare que a documentação gerada não mostra o conteúdo dos métodos, nem atributos e méto-

dos privados! Isso faz parte da implementação, e o que importa para quem usa uma biblioteca é

a interface: o que ela faz.

Capítulo 13 - Ferramentas: jar e javadoc - Exercícios: Jar e Javadoc - Página 179

Capítulo 14

O pacote java.lang

“Nossas cabeças são redondas para que os pensamentos possam mudar de direção.”– Francis Piacaba

Ao término desse capítulo, você será capaz de:

• utilizar as principais classes do pacote java.lang e ler a documentação padrão de projetos java;

• usar a classe System para obter informações do sistema;

• utilizar a classe String de uma maneira e�ciente e conhecer seus detalhes;

• usar as classes wrappers (como Integer) e boxing;

• utilizar os métodos herdados de Object para generalizar seu conceito de objetos.

14.1 Pacote java.lang

Já usamos, por diversas vezes, as classes String e System. Vimos o sistema de pacotes do Java e nuncaprecisamos dar um import nessas classes. Isso ocorre porque elas estão dentro do pacote java.lang, que éautomaticamente importado para você. É o único pacote com esta característica.

Vamos ver um pouco de suas principais classes.

14.2 Um pouco sobre a classe System

A classe System possui uma série de atributos e métodos estáticos. Já usamos o atributo System.out, paraimprimir.

Material do Treinamento Java e Orientação a Objetos

Olhando a documentação, você vai perceber que o atributo out é do tipo PrintStream do pacotejava.io. Veremos sobre essa classe no próximo capítulo. Já podemos perceber que poderíamos quebraro System.out.println em duas linhas:

PrintStream saida = System.out;saida.println("ola mundo!");

Ela também possui o atributo in, que lê da entrada padrão, porém só consegue captar bytes:

int i = System.in.read();

O código acima deve estar dentro de um bloco de try e catch, pois pode lançar uma exceção IOException.É útil �car lendo de byte em byte? Trabalharemosmais com a entrada padrão também no próximo capítulo.

O System conta tambémcomummétodo que simplesmente desliga a virtualmachine, retornando umcódigode erro para o sistema operacional, é o exit.

System.exit(0);

Veremos também um pouco mais sobre a classe System no próximo capítulo e no de Threads. Consulte adocumentação do Java e veja outros métodos úteis da System.

A classe Runtime

A classe Runtime possui um método para fazer uma chamada ao sistema operacional e rodaralgum programa:

Runtime rt = Runtime.getRuntime();Process p = rt.exec("dir");

Isto deve ser evitado ao máximo, já que gera uma dependência da sua aplicação com o sistema

operacional em questão, perdendo a portabilidade entre plataformas. Em muitos casos, isso

pode ser substituído por chamadas às bibliotecas do Java. Nesse caso, por exemplo, você tem

um método list na classe File do pacote de entrada e saída, que veremos posteriormente.O método exec te retorna um Process, onde você é capaz de pegar a saída do programa, enviardados para a entrada, entre outros.

14.3 java.lang.Object

Sempre quando declaramos uma classe, essa classe é obrigada a herdar de outra. Isto é, para toda classe quedeclararmos, existe uma superclasse. Porém, criamos diversas classes sem herdar de ninguém:

Capítulo 14 - O pacote java.lang - java.lang.Object - Página 181

Material do Treinamento Java e Orientação a Objetos

class MinhaClasse {

}

Quando o Java não encontra a palavra chave extends, ele considera que você está herdando da classe Object,que também se encontra dentro do pacote java.lang. Você até mesmo pode escrever essa herança, que é omesmo:

class MinhaClasse extends Object {

}

Todas as classes, sem exceção, herdam de Object, seja direta ou indiretamente, pois ela é a mãe, vó, bisavó,etc de qualquer classe.

Podemos também a�rmar que qualquer objeto em Java é um Object, podendo ser referenciado como tal.Então, qualquer objeto possui todos os métodos declarados na classe Object e veremos alguns deles logoapós o casting.

14.4 Casting de referências

A habilidade de poder se referir a qualquer objeto como Object nos traz muitas vantagens. Podemos criarum método que recebe um Object como argumento, isto é, qualquer objeto! Melhor, podemos armazenarqualquer objeto:

public class GuardadorDeObjetos {private Object[] arrayDeObjetos = new Object[100];private int posicao = 0;

public void adicionaObjeto(Object object) {this.arrayDeObjetos[this.posicao] = object;this.posicao++;

}

public Object pegaObjeto(int indice) {return this.arrayDeObjetos[indice];

}}

Mas, e nomomento que retirarmos uma referência a esse objeto, como vamos acessar os métodos e atributos

desse objeto? Se estamos referenciando-o como Object, não podemos acessá-lo como sendo Conta. Veja oexemplo a seguir:

Capítulo 14 - O pacote java.lang - Casting de referências - Página 182

Material do Treinamento Java e Orientação a Objetos

GuardadorDeObjetos guardador = new GuardadorDeObjetos();Conta conta = new Conta();guardador.adicionaObjeto(conta);

// ...

// pega a conta referenciado como objetoObject object = guardador.pegaObjeto(0);

// será que posso invocar getSaldo em Object? :object.getSaldo();

Poderíamos então atribuir essa referência de Object para Conta para depois invocar o getSaldo()? Tente-mos:

Conta contaResgatada = object;

Nós temos certeza de que esse Object se refere a uma Conta, já que fomos nós que o adicionamos na classeque guarda objetos. Mas o compilador Java não tem garantias sobre isso! Essa linha acima não compila, pois

nem todo Object é uma Conta.

Para realizar essa atribuição, para isso devemos “avisar” o compilador Java que realmente queremos fazer

isso, sabendo do risco que corremos. Fazemos o casting de referências, parecido com de tipos primitivos:

Conta contaResgatada = (Conta) object;

O código passa a compilar, mas será que roda? Esse código roda sem nenhum problema, pois em tempo

de execução a JVM veri�cará se essa referência realmente é para um objeto de tipo Conta, e está! Se nãoestivesse, uma exceção do tipo ClassCastException seria lançada.

Poderíamos fazer o mesmo com Funcionario e Gerente. Tendo uma referência para um Funcionarioque temos certeza ser um Gerente, podemos fazer a atribuição, desde que o casting exista, pois nem todoFuncionario é um Gerente.

Funcionario funcionario = new Gerente();

// ... e depois

Gerente gerente = funcionario; // não compila!// nem todo Funcionario é um Gerente

O correto então seria:

Gerente gerente = (Gerente) funcionario;

Capítulo 14 - O pacote java.lang - Casting de referências - Página 183

Material do Treinamento Java e Orientação a Objetos

Vamos misturar um pouco:

Object object = new Conta();

// ... e depois

Gerente gerente = (Gerente) object;

Esse código compila? Roda?

Compila, pois existe a chance de um Object ser um Gerente. Porém não roda, ele vai lançar uma Exception(ClassCastException) em tempo de execução. É importante diferenciar tempo de compilação e tempo deexecução.

Neste exemplo, nós garantimos ao java que nosso Objeto object era um Gerente com o casting, por issocompilou, mas na hora de rodar, quando ele foi receber um Gerente, ele recebeu uma Conta, daí ele reclamoulançando ClassCastException!

14.5 Métodos do java.lang.Object: equals e toString

O primeiro método interessante é o toString. As classes podem reescrever esse método para mostrar umamensagem, uma String, que o represente. Você pode usá-lo assim:

Conta c = new Conta();System.out.println(c.toString());

Ométodo toString do Object retorna o nome da classe @ um número de identidade:

Conta@34f5d74a

Mas isso não é interessante para nós. Então podemos reescrevê-lo:

class Conta {private double saldo;// outros atributos...

public Conta(double saldo) {this.saldo = saldo;

}

public String toString() {return "Uma conta com valor: " + this.saldo;

}}

Capítulo 14 - O pacote java.lang - Métodos do java.lang.Object: equals e toString - Página 184

Material do Treinamento Java e Orientação a Objetos

Chamando o toString:

Conta c = new Conta(100);System.out.println(c.toString()); //imprime: Uma conta com valor: 100.

E o melhor, se for apenas para jogar na tela, você nem precisa chamar o toString! Ele já é chamado paravocê:

Conta c = new Conta(100);System.out.println(c); // O toString é chamado pela classe PrintStream

Gera o mesmo resultado!

Você ainda pode concatenar Strings em Java com o operador +. Se o Java encontra um objeto no meio daconcatenação, ele também chama o toString dele.

Conta c = new Conta(100);System.out.println("descrição: " + c);

O outro método muito importante é o equals. Quando comparamos duas variáveis referência no Java, o ==veri�ca se as duas referem-se ao mesmo objeto:

Conta c1 = new Conta(100);Conta c2 = new Conta(100);if (c1 != c2) {

System.out.println("objetos referenciados são diferentes!");}

E, nesse caso, realmente são diferentes.

Mas, e se fosse preciso comparar os atributos? Quais atributos ele deveria comparar? O Java por si só não faz

isso,mas existe ummétodona classe Objectque pode ser reescrito para criarmos esse critério de comparação.Esse método é o equals.

O equals recebe um Object como argumento e deve veri�car se ele mesmo é igual ao Object recebido pararetornar um boolean. Se você não reescrever esse método, o comportamento herdado é fazer um == com oobjeto recebido como argumento.

public class Conta {private double saldo;// outros atributos...

public Conta(double saldo) {this.saldo = saldo;

Capítulo 14 - O pacote java.lang - Métodos do java.lang.Object: equals e toString - Página 185

Material do Treinamento Java e Orientação a Objetos

}

public boolean equals(Object object) {Conta outraConta = (Conta) object;if (this.saldo == outraConta.saldo) {

return true;}return false;

}

public String toString() {return "Uma conta com valor: " + this.saldo;

}}

Um exemplo clássico do uso do equals é para datas. Se você criar duas datas, isto é, dois objetos diferentes,contendo 31/10/1979, ao comparar com o == receberá false, pois são referências para objetos diferentes.Seria correto, então, reescrever este método, fazendo as comparações dos atributos, e o usuário passaria a

invocar equals em vez de comparar com ==.

Você poderia criar um método com outro nome em vez de reescrever equals que recebe Object, mas eleé importante pois muitas bibliotecas o chamam através do polimor�smo, como veremos no capítulo do

java.util.

O método hashCode() anda de mãos dadas com o método equals() e é de fundamental entendimento nocaso de você utilizar suas classes com estruturas de dados que usam tabelas de espalhamento. Também

falaremos dele no capítulo de java.util.

Capítulo 14 - O pacote java.lang - Métodos do java.lang.Object: equals e toString - Página 186

Material do Treinamento Java e Orientação a Objetos

Regras para a reescrita do método equals

Pelo contrato de�nido pela classe Object devemos retornar false também no caso do objetopassado não ser de tipo compatível com a sua classe. Então antes de fazer o casting devemos

veri�car isso, e para tal usamos a palavra chave instanceof, ou teríamos uma exception sendolançada.

Além disso, podemos resumir nosso equals de tal forma a não usar um if:

public boolean equals(Object object) {if (!(object instanceof Conta))

return false;Conta outraConta = (Conta) object;return this.saldo == outraConta.saldo;

}

14.6 Integer e classes wrappers (box)

Uma pergunta bem simples que surge na cabeça de todo programador ao aprender uma nova linguagem é:

“Como transformar um número em String e vice-versa?”.

Cuidado! Usamos aqui o termo “transformar”, porém o que ocorre não é uma transformação entre os tipos e

sim uma forma de conseguirmos uma String dado um int e vice-versa. O jeito mais simples de transformarum número em String é concatená-lo da seguinte maneira:

int i = 100;String s = "" + i;System.out.println(s);

double d = 1.2;String s2 = "" + d;System.out.println(s2);

Para formatar o número de umamaneira diferente, com vírgula e número de casas decimais devemos utilizar

outras classes de ajuda (NumberFormat, Formatter).

Para transformar uma String em número, utilizamos as classes de ajuda para os tipos primitivos correspon-dentes. Por exemplo, para transformar a String s em um número inteiro utilizamos o método estático daclasse Integer:

Capítulo 14 - O pacote java.lang - Integer e classes wrappers (box) - Página 187

Material do Treinamento Java e Orientação a Objetos

String s = "101";int i = Integer.parseInt(s);

As classes Double, Short, Long, Float etc contêm omesmo tipo demétodo, como parseDouble e parseFloatque retornam um double e float respectivamente.

Essas classes também são muito utilizadas para fazer o wrapping (embrulho) de tipos primitivos como ob-jetos, pois referências e tipos primitivos são incompatíveis. Imagine que precisamos passar como argumento

um inteiro para o nosso guardador de objetos. Um inteiro não é um Object, como fazer?

int i = 5;Integer x = new Integer(i);guardador.adiciona(x);

E, dado um Integer, podemos pegar o int que está dentro dele (desembrulhá-lo):

int i = 5;Integer x = new Integer(i);int numeroDeVolta = x.intValue();

14.7 Autoboxing no Java 5.0

Esse processo de wrapping e unwrapping é entediante. O Java 5.0 em diante traz um recurso chamado de

autoboxing, que faz isso sozinho para você, custando legibilidade:

Integer x = 5;int y = x;

No Java 1.4 esse código é inválido. No Java 5.0 em diante ele compila perfeitamente. É importante ressaltar

que isso não quer dizer que tipos primitivos e referências sejam do mesmo tipo, isso é simplesmente um

“açúcar sintático” (syntax sugar) para facilitar a codi�cação.

Você pode fazer todos os tipos de operações matemáticas com os wrappers, porém corre o risco de tomar

um NullPointerException.

Você pode fazer o autoboxing diretamente para Object também, possibilitando passar um tipo primitivopara um método que receber Object como argumento:

Object o = 5;

Capítulo 14 - O pacote java.lang - Autoboxing no Java 5.0 - Página 188

Material do Treinamento Java e Orientação a Objetos

14.8 java.lang.String

String é uma classe em Java. Variáveis do tipo String guardam referências a objetos, e não um valor, comoacontece com os tipos primitivos.

Aliás, podemos criar uma String utilizando o new:

String x = new String("fj11");String y = new String("fj11");

Criamos aqui, dois objetos diferentes. O que acontece quando comparamos essas duas referências utilizando

o ==?

if (x == y) {System.out.println("referência para o mesmo objeto");

}else {

System.out.println("referências para objetos diferentes!");}

Temos aqui dois objetos diferentes! E, então, como faríamos para veri�car se o conteúdo do objeto é o

mesmo? Utilizamos o método equals, que foi reescrito pela String, para fazer a comparação de char emchar.

if (x.equals(y)) {System.out.println("consideramos iguais no critério de igualdade");

}else {

System.out.println("consideramos diferentes no critério de igualdade");}

Aqui, a comparação retorna verdadeiro. Por quê? Pois quem implementou a classe String decidiu que esteseria o melhor critério de comparação. Você pode descobrir os critérios de igualdade de cada classe pela

documentação.

Podemos também concatenar Strings usando o +. Podemos concatenar Strings com qualquer objeto, atémesmo números:

int total = 5;System.out.println("o total gasto é: " + total);

Ocompilador utilizará osmétodos apropriados da classe String e das classeswrappers para realizar tal tarefa.

A classe String conta também com um método split, que divide a String em um array de Strings, dadodeterminado critério.

Capítulo 14 - O pacote java.lang - java.lang.String - Página 189

Material do Treinamento Java e Orientação a Objetos

String frase = "java é demais";String palavras[] = frase.split(" ");

Se quisermos comparar duas Strings, utilizamos o método compareTo, que recebe uma String como argu-mento e devolve um inteiro indicando se a String vem antes, é igual ou vem depois da String recebida. Seforem iguais, é devolvido 0; se for anterior à String do argumento, devolve um inteiro negativo; e, se forposterior, um inteiro positivo.

Fato importante: uma String é imutável. O java cria um pool de Strings para usar como cache e, se a Stringnão fosse imutável, mudando o valor de uma String afetaria todas as Strings de outras classes que tivessemo mesmo valor.

Repare no código abaixo:

String palavra = "fj11";palavra.toUpperCase();System.out.println(palavra);

Pode parecer estranho, mas ele imprime “911” emminúsculo. Todométodo que parece alterar o valor de uma

String, na verdade, cria uma nova String com as mudanças solicitadas e a retorna! Tanto que esse métodonão é void. O código realmente útil �caria assim:

String palavra = "fj11";String outra = palavra.toUpperCase();System.out.println(outra);

Ou você pode eliminar a criação de outra variável temporária, se achar conveniente:

String palavra = "fj11";palavra = palavra.toUpperCase();System.out.println(palavra);

Isso funciona da mesma forma para todos os métodos que parecem alterar o conteúdo de uma String.

Se você ainda quiser trocar o número 1 para 2, faríamos:

String palavra = "fj11";palavra = palavra.toUpperCase();palavra = palavra.replace("1", "2");System.out.println(palavra);

Ou ainda podemos concatenar as invocações de método, já que uma String é devolvida a cada invocação:

Capítulo 14 - O pacote java.lang - java.lang.String - Página 190

Material do Treinamento Java e Orientação a Objetos

String palavra = "fj11";palavra = palavra.toUpperCase().replace("1", "2");System.out.println(palavra);

O funcionamento do pool interno de Strings do Java tem uma série de detalhes e você pode encontrar mais

informações sobre isto na documentação da classe String e no seu método intern().

Outros métodos da classe String

Existem diversos métodos da classe String que são extremamente importantes. Recomendamossempre consultar o javadoc relativo a essa classe para aprender cada vez mais sobre a mesma.

Por exemplo, ométodo charAt(i), retorna o caractere existente na posição i da String, ométodolength retorna o número de caracteres na mesma e o método substring que recebe um int edevolve a SubString a partir da posição passada por aquele int.

O indexOf recebe um char ou uma String e devolve o índice em que aparece pela primeira vezna String principal (há também o lastIndexOf que devolve o índice da última ocorrência).

O toUpperCase e o toLowerCase devolvem uma nova String toda em maiúscula e toda em mi-núscula, respectivamente.

A partir do Java 6, temos ainda o método isEmpty, que devolve true se a String for vazia oufalse caso contrário.

Alguns métodos úteis para buscas são o contains e o matches.

Há muitos outros métodos, recomendamos que você sempre consulte o javadoc da classe.

java.lang StringBuffer e StringBuilder

Como a classe String é imutável, trabalhar com uma mesma String diversas vezes pode ter umefeito colateral: gerar inúmeras Strings temporárias. Isto prejudica a performance da aplicaçãoconsideravelmente.

No caso de você trabalharmuito comamanipulação de umamesma String (por exemplo, dentrode um laço), o ideal é utilizar a classe StringBuffer. A classe StringBuffer representa umasequência de caracteres. Diferentemente da String, ela é mutável, e não possui aquele pool.

A classe StringBuilder tem exatamente os mesmos métodos, com a diferença dela não serthread-safe. Veremos sobre este conceito no capítulo de�reads.

Capítulo 14 - O pacote java.lang - java.lang.String - Página 191

Material do Treinamento Java e Orientação a Objetos

14.9 java.lang.Math

Na classe Math, existe uma série demétodos estáticos que fazem operações comnúmeros como, por exemplo,arredondar(round), tirar o valor absoluto (abs), tirar a raiz(sqrt), calcular o seno(sin) e outros.

double d = 4.6;long i = Math.round(d);

int x = -4;int y = Math.abs(x);

Consulte a documentação para ver a grande quantidade de métodos diferentes.

No Java 5.0, podemos tirar proveito do import static aqui:

import static java.lang.Math.*;

Isso elimina a necessidade de usar o nome da classe, sob o custo de legibilidade:

double d = 4.6;long i = round(d);int x = -4;int y = abs(x);

14.10 Exercícios: java.lang

Aqui faremos diversos testes, além demodi�car a classe Conta. Você pode fazer todos esses exercícios dentrodo próprio projeto banco.

1) Teste os exemplos desse capítulo, para ver que uma String é imutável. Por exemplo:

public class TestaString {

public static void main(String[] args) {String s = "fj11";s.replaceAll("1", "2");System.out.println(s);

}

}

Como fazer para ele imprimir 922?

Capítulo 14 - O pacote java.lang - java.lang.Math - Página 192

Material do Treinamento Java e Orientação a Objetos

2) Como fazer para saber se uma String se encontra dentro de outra? E para tirar os espaços em branco deuma String? E para saber se uma String está vazia? E para saber quantos caracteres tem uma String?

Tome como hábito sempre pesquisar o javadoc! Conhecer a API, aos poucos, é fundamental para que

você não precise reescrever a roda!

3) Crie uma classe TestaInteger e vamos fazer comparações com Integers dentro do main:

Integer x1 = new Integer(10);Integer x2 = new Integer(10);

if (x1 == x2) {System.out.println("igual");

} else {System.out.println("diferente");

}

E se testarmos com o equals?

O que podemos concluir? Como veri�car se a classe Integer também reescreve o método toString?

A maioria das classes do Java que são muito utilizadas terão seus métodos equals e toString reescritosconvenientemente.

Aproveite e faça um teste com o método estático parseInt, recebendo uma String válida e uma inválida(com caracteres alfabéticos), e veja o que acontece!

4) Utilize-se da documentação do Java e descubra de que classe é o objeto referenciado pelo atributo out daSystem.

Repare que, com o devido import, poderíamos escrever:

// falta a declaração da saídasaida = System.out;saida.println("ola");

A variável saida precisa ser declarada de que tipo? É isso que você precisa descobrir. Se você digitar essecódigo no Eclipse, ele vai te sugerir um quick�x e declarará a variável para você.

Estudaremos essa classe no capítulo seguinte.

5) Crie e imprima uma referência para Conta (ContaCorrente ou ContaPoupanca, no caso de sua Conta serabstrata):

Conta conta = new ContaCorrente():System.out.println(conta);

O que acontece?

6) Reescreva o método toString da sua classe Conta fazendo com que uma mensagem mais propícia sejadevolvida. Lembre-se de aproveitar dos recursos do Eclipse para isto: digitando apenas o começo do nome

Capítulo 14 - O pacote java.lang - Exercícios: java.lang - Página 193

Material do Treinamento Java e Orientação a Objetos

do método a ser reescrito e pressionando Ctrl+espaço, ele vai sugerir reescrever o método, poupandovocê do trabalho de escrever a assinatura do mesmo, e de cometer algum engano.

public abstract class Conta {

private double saldo;

public String toString() {return "esse objeto é uma conta com saldo R$" + this.saldo;

}

// restante da classe

}

Imprima novamente uma referência a Conta. O que aconteceu?

7) Reescreva o método equals da classe Conta para que duas contas com o mesmo número de conta sejamconsideradas iguais. Para isso, você vai precisar de um atributo numero. Esboço:

abstract class Conta {private int numero;

public boolean equals(Object obj) {Conta outraConta = (Conta) obj;

return this.numero == outraConta.numero;}

// coloque getter e setter para numero, usando Eclipse!}

Você pode usar oCtrl+espaço do eclipse para escrever o esqueleto dométodo equals, basta digitar dentroda classe equ e pressionar Ctrl+espaço.

Crie uma classe TestaComparacaoConta, e dentro do main compare duas instâncias de ContaCorrentecom ==, depois com equals, sendo que as instâncias são diferentes mas possuem o mesmo numero deconta (use o setNumero).

8) Um double não está sendo su�ciente para guardar a quantidade de casas necessárias em uma aplicação.Preciso guardar um número decimal muito grande! O que poderia usar? (consulte a documentação, tente

adivinhar onde você pode encontrar algo desse tipo pelos nomes dos pacotes, veja como é intuitivo).

O double também tem problemas de precisão ao fazer contas, por causa de arredondamentos da aritmé-tica de ponto �utuante de�nido pela IEEE 754:

http://en.wikipedia.org/wiki/IEEE_754

Capítulo 14 - O pacote java.lang - Exercícios: java.lang - Página 194

Material do Treinamento Java e Orientação a Objetos

Ele não deve ser usado se você precisa realmente de muita precisão (casos que envolvam dinheiro, por

exemplo).

Lembre-se: no Java há muito já pronto. Seja na biblioteca padrão, seja em bibliotecas open source que

você pode encontrar pela internet.

9) (opcional) Faça com que o equals da sua classe Conta também leve em consideração a String do nomedo cliente a qual ela pertence. Se sua Conta não possuir o atributo nome, crie-o. Teste se o método criadoestá funcionando corretamente.

10) (opcional) Crie a classe GuardadorDeObjetos como visto nesse capítulo. Crie uma classe TestaGuardadore dentro do main crie uma ContaCorrente e adicione-a em um GuardadorDeObjetos. Depois teste pegaressa referência como ContaPoupanca, usando casting. Repare na exception que é lançada:

GuardadorDeObjetos guardador = new GuardadorDeObjetos();ContaCorrente cc = new ContaCorrente();guardador.adicionaObjeto(cc);

// vai precisar do casting para compilar!// use Ctrl+1 para o Eclipse gerar para vocêContaPoupanca cp = guardador.pega(0);

Teste também o autoboxing do Java 5.0, passando um inteiro para nosso guardador.

11) (opcional) Escreva um método que usa os métodos charAt e length de uma String para imprimir amesma caractere a caractere, com cada caractere em uma linha diferente.

12) (opcional) Reescreva o método do exercício anterior, mas imprima a String de trás para a frente. Teste-apara "Socorram-me, subi no ônibus em Marrocos” e "Anotaram a data da maratona”.

13) (opcional) Dada uma frase, reescreva essa frase com as palavras na ordem invertida. "Socorram-me, subino ônibus em Marrocos” deve retornar "Marrocos em ônibus no subi Socorram-me,”. Utilize o métodosplit da String para te auxiliar.

14) (opcional) Pesquise a classe StringBuilder (ou StringBu�er no Java 1.4). Ela é mutável. Por que usá-laem vez da String? Quando usá-la? Repare que ela tem um método reverse e outros bem úteis!

14.11 Desafio

1) Converta uma String para um número sem usar as bibliotecas do java que já fazem isso. Isso é, umaString x = "762" deve gerar um int i = 762.

Para ajudar, saiba que um char pode ser “transformado” em int com o mesmo valor numérico fazendo:

char c = '3';int i = c - '0'; // i vale 3!

Capítulo 14 - O pacote java.lang - Desa�o - Página 195

Material do Treinamento Java e Orientação a Objetos

Aqui estamos nos aproveitando do conhecimento da tabela unicode: os números de 0 a 9 estão em sequên-

cia! Você poderia usar o método estático Character.getNumericValue(char) em vez disso.

14.12 Discussão em aula: O que você precisa fazer em Java?

Qual é a sua necessidade como Java? Precisa fazer algoritmos de redes neurais? Gerar grá�cos 3D? Relatórios

em PDF? Gerar código de barra? Gerar boletos? Validar CPF? Mexer com um arquivo do Excel?

O instrutor vai mostrar que para a maioria absoluta das suas necessidades, alguém já fez uma biblioteca e a

disponibilizou.

Capítulo 14 - O pacote java.lang - Discussão em aula: O que você precisa fazer em Java? - Página 196

Capítulo 15

Pacote java.io

“A benevolência é sobretudo um vício do orgulho e não uma virtude da alma.”– Doantien Alphonse François (Marquês de Sade)

Ao término desse capítulo, você será capaz de:

• ler e escrever bytes, caracteres e Strings de/para a entrada e saída padrão;

• ler e escrever bytes, caracteres e Strings de/para arquivos;

• utilizar bu�ers para agilizar a leitura e escrita através de �uxos;

• usar Scanner e PrintStream.

15.1 Conhecendo uma API

Vamos passar a conhecer APIs do Java. java.io e java.util possuem as classes que você mais comumentevai usar, não importando se seu aplicativo é desktop, web, ou mesmo para celulares.

Apesar de ser importante conhecer nomes e métodos das classes mais utilizadas, o interessante aqui é que

você enxergue que todos os conceitos previamente estudados são aplicados a toda hora nas classes da bibli-

oteca padrão.

Não se preocupe em decorar nomes. Atenha-se em entender como essas classes estão relacionadas e como

elas estão tirando proveito do uso de interfaces, polimor�smo, classes abstratas e encapsulamento. Lembre-se

de estar com a documentação (javadoc) aberta durante o contato com esses pacotes.

Veremos também threads e sockets em capítulos posteriores, que ajudarão a condensar nosso conhecimento,

tendo emvista que no exercício de sockets utilizaremos todos conceitos aprendidos, juntamente comas várias

APIs.

Material do Treinamento Java e Orientação a Objetos

15.2 Orientação a objetos no java.io

Assim como todo o resto das bibliotecas em Java, a parte de controle de entrada e saída de dados (conhecido

como io) é orientada a objetos e usa os principais conceitos mostrados até agora: interfaces, classes abstratase polimor�smo.

A ideia atrás do polimor�smo no pacote java.io é de utilizar �uxos de entrada (InputStream) e de saída(OutputStream) para toda e qualquer operação, seja ela relativa a um arquivo, a um campo blob do bancode dados, a uma conexão remota via sockets, ou até mesmo às entrada e saída padrão de um programa(normalmente o teclado e o console).

As classes abstratas InputStream e OutputStream de�nem, respectivamente, o comportamento padrão dos�uxos em Java: em um �uxo de entrada, é possível ler bytes e, no �uxo de saída, escrever bytes.

A grande vantagemdessa abstração pode sermostrada emummétodoqualquer que utiliza um OutputStreamrecebido como argumento para escrever em um �uxo de saída. Para onde o método está escrevendo? Não

se sabe e não importa: quando o sistema precisar escrever em um arquivo ou em uma socket, basta chamar

o mesmo método, já que ele aceita qualquer �lha de OutputStream!

15.3 InputStream, InputStreamReader e BufferedReader

Para ler um byte de um arquivo, vamos usar o leitor de arquivo, o FileInputStream. Para um

FileInputStream conseguir ler um byte, ele precisa saber de onde ele deverá ler. Essa informação é tãoimportante que quem escreveu essa classe obriga você a passar o nome do arquivo pelo construtor: sem isso

o objeto não pode ser construído.

1 class TestaEntrada {2 public static void main(String[] args) throws IOException {3 InputStream is = new FileInputStream("arquivo.txt");4 int b = is.read();5 }6 }

A classe InputStream é abstrata e FileInputStream uma de suas �lhas concretas. FileInputStream vaiprocurar o arquivo no diretório em que a JVM fora invocada (no caso do Eclipse, vai ser a partir de dentro

do diretório do projeto). Alternativamente você pode usar um caminho absoluto.

Quando trabalhamos com java.io, diversos métodos lançam IOException, que é uma exception do tipochecked - o que nos obriga a tratá-la ou declará-la. Nos exemplos aqui, estamos declarando IOExceptionatravés da clausula throws do main apenas para facilitar o exemplo. Caso a exception ocorra, a JVM vaiparar, mostrando a stacktrace. Esta não é uma boa prática em uma aplicação real: trate suas exceptions para

sua aplicação poder abortar elegantemente.

Capítulo 15 - Pacote java.io - Orientação a objetos no java.io - Página 198

Material do Treinamento Java e Orientação a Objetos

InputStream tem diversas outras �lhas, como ObjectInputStream, AudioInputStream,ByteArrayInputStream, entre outras.

Para recuperar um caractere, precisamos traduzir os bytes com o encoding dado para o respectivo código

unicode, isso pode usar um ou mais bytes. Escrever esse decodi�cador é muito complicado, quem faz isso

por você é a classe InputStreamReader.

1 class TestaEntrada {2 public static void main(String[] args) throws IOException {3 InputStream is = new FileInputStream("arquivo.txt");4 InputStreamReader isr = new InputStreamReader(is);5 int c = isr.read();6 }7 }

O construtor de InputStreamReader pode receber o encoding a ser utilizado como parâmetro, se desejado,tal como UTF-8 ou ISO-8859-1.

Encodings

Devido a grande quantidade de aplicativos internacionalizados de hoje em dia, é imprescindível

que um bom programador entenda bem o que são os character encodings e o Unicode. O blog

da Caelum possui um bom artigo a respeito:

http://blog.caelum.com.br/2006/10/22/entendendo-unicode-e-os-character-encodings/

InputStreamReader é �lha da classe abstrata Reader, que possui diversas outras �lhas - são classes que ma-nipulam chars.

Apesar da classe abstrata Reader já ajudar no trabalho de manipulação de caracteres, ainda seria difícil pegaruma String. A classe BufferedReader é um Reader que recebe outro Reader pelo construtor e concatena osdiversos chars para formar uma String através do método readLine:

1 class TestaEntrada {2 public static void main(String[] args) throws IOException {3 InputStream is = new FileInputStream("arquivo.txt");4 InputStreamReader isr = new InputStreamReader(is);5 BufferedReader br = new BufferedReader(isr);6 String s = br.readLine();7 }8 }

Como o próprio nome diz, essa classe lê do Reader por pedaços (usando o bu�er) para evitar realizar muitaschamadas ao sistema operacional. Você pode até con�gurar o tamanho do bu�er pelo construtor.

Capítulo 15 - Pacote java.io - InputStream, InputStreamReader e Bu�eredReader - Página 199

Material do Treinamento Java e Orientação a Objetos

É essa a composição de classes que está acontecendo:

Esse padrão de composição é bastante utilizado e conhecido. É oDecorator Pattern.

Aqui, lemos apenas a primeira linha do arquivo. O método readLine devolve a linha que foi lida e mudao cursor para a próxima linha. Caso ele chegue ao �m do Reader (no nosso caso, �m do arquivo), ele vaidevolver null. Então, com um simples laço, podemos ler o arquivo por inteiro:

1 class TestaEntrada {2 public static void main(String[] args) throws IOException {3 InputStream is = new FileInputStream("arquivo.txt");4 InputStreamReader isr = new InputStreamReader(is);5 BufferedReader br = new BufferedReader(isr);6

7 String s = br.readLine(); // primeira linha8

9 while (s != null) {10 System.out.println(s);11 s = br.readLine();12 }13

14 br.close();15 }16 }

15.4 Lendo Strings do teclado

Com um passe de mágica, passamos a ler do teclado em vez de um arquivo, utilizando o System.in, que éuma referência a um InputStream o qual, por sua vez, lê da entrada padrão.

1 class TestaEntrada {2 public static void main(String[] args) throws IOException {3 InputStream is = System.in;4 InputStreamReader isr = new InputStreamReader(is);5 BufferedReader br = new BufferedReader(isr);6 String s = br.readLine();

Capítulo 15 - Pacote java.io - Lendo Strings do teclado - Página 200

Material do Treinamento Java e Orientação a Objetos

7

8 while (s != null) {9 System.out.println(s);10 s = br.readLine();11 }12 }13 }

Apenas modi�camos a quem a variável is está se referindo. Podemos receber argumentos do tipoInputStream e ter esse tipo de abstração: não importa exatamente de onde estamos lendo esse punhadode bytes, desde que a gente receba a informação que estamos querendo. Como na �gura:

Repare que a ponta da direita poderia ser qualquer InputStream, seja ObjectInputStream,AudioInputStream, ByteArrayInputStream, ou a nossa FileInputStream. Polimor�smo! Ou você

mesmo pode criar uma �lha de InputStream, se desejar.

Por isso é muito comum métodos receberem e retornarem InputStream, em vez de suas �lhas especí�cas.Com isso, elas desacoplam as informações e escondem a implementação, facilitando a mudança e manu-

tenção do código. Repare que isso vai ao encontro de tudo o que aprendemos durante os capítulos que

apresentaram classes abstratas, interfaces, polimor�smo e encapsulamento.

15.5 A analogia para a escrita: OutputStream

Como você pode imaginar, escrever em um arquivo é o mesmo processo:

Capítulo 15 - Pacote java.io - A analogia para a escrita: OutputStream - Página 201

Material do Treinamento Java e Orientação a Objetos

1 class TestaSaida {2 public static void main(String[] args) throws IOException {3 OutputStream os = new FileOutputStream("saida.txt");4 OutputStreamWriter osw = new OutputStreamWriter(os);5 BufferedWriter bw = new BufferedWriter(osw);6

7 bw.write("caelum");8

9 bw.close();10 }11 }

Lembre-se de dar refresh (clique da direita no nome do projeto, refresh) no seu projeto do Eclipse para queo arquivo criado apareça. O FileOutputStream pode receber um booleano como segundo parâmetro, paraindicar se você quer reescrever o arquivo ou manter o que já estava escrito (append).

O método write do BufferedWriter não insere o(s) caractere(s) de quebra de linha. Para isso, você podechamar o método newLine.

Capítulo 15 - Pacote java.io - A analogia para a escrita: OutputStream - Página 202

Material do Treinamento Java e Orientação a Objetos

Fechando o arquivo com o finally e o try-with-resources

É importante sempre fechar o arquivo. Você pode fazer isso chamando diretamente

o método close do FileInputStream/OutputStream, ou ainda chamando o close doBufferedReader/Writer. Nesse último caso, o close será cascateado para os objetos os quaiso BufferedReader/Writer utiliza para realizar a leitura/escrita, além dele fazer o �ush dos buf-fers no caso da escrita.

É comum e fundamental que o close esteja dentro de um bloco finally. Se um arquivo foresquecido aberto e a referência para ele for perdida, pode ser que ele seja fechado pelo garbagecollector, que veremos mais a frente, por causa do finalize. Mas não é bom você se prender aisso. Se você esquecer de fechar o arquivo, no caso de um programaminúsculo como esse, o pro-

grama vai terminar antes que o tal do garbage collector te ajude, resultando em um arquivo não

escrito (os bytes �caram no bu�er do BufferedWriter). Problemas similares podem acontecercom leitores que não forem fechados.

No Java 7 há a estrutura try-with-resources, que já fará o finally cuidar dos recursos declara-dos dentro do try(), invocando close. Pra isso, os recursos devem implementar a interfacejava.lang.AutoCloseable, que é o caso dos Readers, Writers e Streams estudados aqui:

try (BufferedReader br = new BufferedReader(new File("arquivo.txt"))) {// com exceção ou não, o close() do br sera invocado

}

15.6 Uma maneira mais fácil: Scanner e PrintStream

A partir do Java 5, temos a classe java.util.Scanner, que facilita bastante o trabalho de ler de umInputStream. Além disso, a classe PrintStream possui um construtor que já recebe o nome de um arquivocomo argumento. Dessa forma, a leitura do teclado com saída para um arquivo �cou muito simples:

Scanner s = new Scanner(System.in);PrintStream ps = new PrintStream("arquivo.txt");while (s.hasNextLine()) {

ps.println(s.nextLine());}

Nenhum dos métodos lança IOException: PrintStream lança FileNotFoundException se você o construirpassando uma String. Essa exceção é �lha de IOException e indica que o arquivo não foi encontrado. O

Capítulo 15 - Pacote java.io - Uma maneira mais fácil: Scanner e PrintStream - Página 203

Material do Treinamento Java e Orientação a Objetos

Scanner considerará que chegou ao �m se uma IOException for lançada, mas o PrintStream simplesmenteengole exceptions desse tipo. Ambos possuem métodos para você veri�car se algum problema ocorreu.

A classe Scanner é do pacote java.util. Ela possui métodos muito úteis para trabalhar com Strings, emespecial, diversos métodos já preparados para pegar números e palavras já formatadas através de expressões

regulares. Fica fácil parsear um arquivo com qualquer formato dado.

System.out

Como vimos no capítulo passado, o atributo out da classe System é do tipo PrintStream (e,portanto, é um OutputStream).

15.7 Um pouco mais...

• Existem duas classes chamadas java.io.FileReader e java.io.FileWriter. Elas são atalhos para aleitura e escrita de arquivos.

• O do { .. } while(condicao); é uma alternativa para se construir um laço. Pesquise-o e utilize-ono código para ler um arquivo, ele vai �car mais sucinto (você não precisará ler a primeira linha fora

do laço).

15.8 Exercícios: Java I/O

1) Crie um projeto novo chamado teste-io.

Crie um programa (simplesmente uma classe com um main) que leia da entrada padrão. Para isso, vocêvai precisar de um BufferedReader que leia do System.in da mesma forma como �zemos.

Não digite esses nomes de classes complicados! Use o ctrl+espaço para te auxiliar, porque além de teajudar com o nome, ele colocará o import no devido lugar.

Cuidado que existe mais de uma classe chamada InputStream: queremos a do pacote java.io.

1 public class TestaEntrada {2

3 // está faltando o throws IOException!! Peça auxílio para o Eclipse!4

5 public static void main(String[] args) {6 InputStream is = System.in;7 InputStreamReader isr = new InputStreamReader(is);8 BufferedReader br = new BufferedReader(isr);9

10 String linha = br.readLine(); // primeira linha

Capítulo 15 - Pacote java.io - Um pouco mais... - Página 204

Material do Treinamento Java e Orientação a Objetos

11

12 while (linha != null) {13 System.out.println(linha);14 linha = br.readLine();15 }16 }17 }

O compilador vai reclamar que você não está tratando algumas exceções (como java.io.IOException).Utilize a cláusula throws para deixar “escapar” a exceção pelo seu main, ou use os devidos try/catch.Utilize o quick �x do Eclipse para isso (Ctrl + 1). Deixar todas as exceptions passarem desapercebidas nãoé uma boa prática! Você pode usar aqui, pois estamos focando apenas no aprendizado da utilização do

java.io.

Rode sua aplicação. Através da View Console você pode digitar algumas linhas para que seu programa ascapture.

EOF

Quando rodar sua aplicação, para encerrar a entrada de dados do teclado, é necessário enviarmos

um sinal de �m de stream. É o famoso EOF, End Of File.

No Linux/Mac/Solaris/Unix você faz isso com o CONTROL+D. No Windows, use o CONTROL+Z.

2) Vamos ler de um arquivo, em vez do teclado. Antes, vamos criar o arquivo que será lido pelo programa:

a) Clique com o botão direito em cima do seu projeto e selecione New -> File:

b) Nesta tela, digite o nome do arquivo no lugar indicado:

Capítulo 15 - Pacote java.io - Exercícios: Java I/O - Página 205

Material do Treinamento Java e Orientação a Objetos

c) Troque na classe TestaEntrada o System.in por um new FileInputStream:

InputStream is = new FileInputStream("arquivo.txt");

3) (conceitual) Seu programa lê todas as linhas desse arquivo. Repare na utilização do polimor�smo. Como

ambos são InputStream, isso faz com que eles se encaixem no InputStreamReader.

4) Repare que, no �nal, só usamos mesmo o BufferedReader. As referências para InputStream e paraInputStreamReader são apenas utilizadas temporariamente. Portanto, é comumencontrarmos o seguintecódigo nesses casos:

BufferedReader br = new BufferedReader(new InputStreamReader(

new FileInputStream("arquivo.txt")));

String linha = br.readLine(); // primeira linha

Capítulo 15 - Pacote java.io - Exercícios: Java I/O - Página 206

Material do Treinamento Java e Orientação a Objetos

Claro que devemos evitar um código mais sucinto em vez de sacri�car legibilidade, mas este código em

particular é bem comum e aceitável. Faça a alteração no seu programa!

5) Utilize a classe Scanner do Java 5 para ler de um arquivo e colocar na tela. O código vai �car incrivelmentepequeno.

1 class EntradaDeUmArquivo {2 public static void main(String[] args) throws IOException {3 InputStream is = new FileInputStream("arquivo.txt");4

5 Scanner entrada = new Scanner(is);6 while (entrada.hasNextLine()) {7 System.out.println(entrada.nextLine());8 }9

10 is.close();11 }12 }

Depois troque a variável is para que ela se re�ra ao System.in. Agora você está lendo do teclado!

6) (opcional) Altere seu programa para que ele leia do arquivo e, em vez de jogar na tela, jogue em um outro

arquivo. Você vai precisar, além do código anterior para ler de um arquivo, do código para escrever em

um arquivo. Para isso, você pode usar o BufferedWriter ou o PrintStream, sendo este último de maisfácil manipulação.

Se for usar o BufferedWriter, fazemos assim parar abri-lo:

OutputStream os = new FileOutputStream("saida.txt");OutputStreamWriter osw = new OutputStreamWriter(os);BufferedWriter bw = new BufferedWriter(osw);

Dentro do loop de leitura do teclado, você deve usar bw.write(x), onde x é a linha que você leu. Usebw.newLine() para pular de linha. Não se esqueça de, no término do loop, dar um bw.close(). Vocêpode seguir o modelo:

while (entrada.hasNextLine()) {String linha = entrada.nextLine();bw.write(linha);bw.newLine();

}

bw.close();

Após rodar seu programa, dê um refresh no seu projeto (clique da direita no nome do projeto, refresh) e

veja que ele criou um arquivo saida.txt no diretório.

7) (opcional) Altere novamente o programa para ele virar um pequeno editor: lê do teclado e escreve em

arquivo. Repare que a mudança a ser feita é mínima!

Capítulo 15 - Pacote java.io - Exercícios: Java I/O - Página 207

Material do Treinamento Java e Orientação a Objetos

8) (opcional) A classe Scanner é muito poderosa! Consulte seu javadoc para saber sobre o delimiter e osoutros métodos next.

15.9 Discussão emaula: DesignPatterns eoTemplateMethod

Aplicar bem os conceitos de orientação a objetos é sempre uma grande dúvida. Sempre queremos encap-

sular direito, favorecer a �exibilidade, desacoplar classes, escrever código elegante e de fácil manutenção. E

ouvimos falar que a Orientação a Objetos ajuda em tudo isso.

Mas, onde usar herança de forma saudável? Como usar interfaces? Onde o polimor�smo me ajuda? Como

encapsular direito? Classes abstratas são usadas em que situações?

Muitos anos atrás, grandes nomes do mundo da orientação a objetos perceberam que criar bons designs

orientados a objetos era um grande desa�o para muitas pessoas. Perceberam que muitos problemas de OO

apareciam recorrentemente em vários projetos; e que as pessoas já tinham certas soluções para esses proble-

mas clássicos (nem sempre muito elegantes).

O que �zeram foi criar soluções padrões para problemas comuns na orientação a objetos, e chamaram issode Design Patterns, ou Padrões de Projeto. O conceito vinha da arquitetura onde era muito comum teresse tipo de solução. E, em 1994, ganhou grande popularidade na computação com o livro Design Patterns:Elements of Reusable Object-Oriented So�ware, um catálogo com várias dessas soluções escrito por ErichGamma, Ralph Johnson, Richard Helm e John Vlissides (a Gangue dos Quatro, GoF).

Design Patterns tornou-se referência absoluta no bom uso da orientação a objetos. Outros padrões surgiramdepois, em outras literaturas igualmente consagradas. O conhecimento dessas técnicas é imprescindível para

o bom programador.

Discuta com o instrutor comoDesign Patterns ajudam a resolver problemas demodelagem em sistemasorientados a objetos. Veja como Design Patterns são aplicados emmuitos lugares do próprio Java.

O instrutor comentará do Template Method e mostrará o código fonte do método read() da classejava.io.InputStream:

1 public int read(byte b[], int off, int len) throws IOException {2 if (b == null) {3 throw new NullPointerException();4 } else if (off < 0 || len < 0 || len > b.length - off) {5 throw new IndexOutOfBoundsException();6 } else if (len == 0) {7 return 0;8 }9

10 int c = read();11 if (c == -1) {12 return -1;

Capítulo 15 - Pacote java.io - Discussão em aula: Design Patterns e o Template Method - Página 208

Material do Treinamento Java e Orientação a Objetos

13 }14

15 b[off] = (byte) c;16

17 int i = 1;18 try {19 for (; i < len ; i++) {20 c = read();21 if (c == -1) {22 break;23 }24 b[off + i] = (byte)c;25 }26 } catch (IOException ee) {27 }28 return i;29 }

Discuta em aula como esse método aplica conceitos importantes da orientação a objetos e promove �e-xibilidade e extensibilidade.

Capítulo 15 - Pacote java.io - Discussão em aula: Design Patterns e o Template Method - Página 209

Capítulo 16

Collections framework

“A amizade é um contrato segundo o qual nos comprometemos a prestar pequenos favores para que no-losretribuam com grandes.”

– Baron de la Brede et de Montesquieu

Ao término desse capítulo, você será capaz de:

• utilizar arrays, lists, sets ou maps dependendo da necessidade do programa;

• iterar e ordenar listas e coleções;

• usar mapas para inserção e busca de objetos.

16.1 Arrays são trabalhosos, utilizar estrutura de dados

Como vimos no capítulo de arrays, manipulá-las é bastante trabalhoso. Essa di�culdade aparece em diversos

momentos:

• não podemos redimensionar um array em Java;

• é impossível buscar diretamente por um determinado elemento cujo índice não se sabe;

• não conseguimos saber quantas posições do array já foram populadas sem criar, para isso, métodos

auxiliares.

Material do Treinamento Java e Orientação a Objetos

Na �gura acima, você pode ver um array que antes estava sendo completamente utilizado e que, depois, teve

um de seus elementos removidos.

Supondo que os dados armazenados representem contas, o que acontece quando precisarmos inserir uma

nova conta no banco? Precisaremos procurar por um espaço vazio? Guardaremos em alguma estrutura de

dados externa, as posições vazias? E se não houver espaço vazio? Teríamos de criar um array maior e copiar

os dados do antigo para ele?

Há mais questões: como posso saber quantas posições estão sendo usadas no array? Vou precisar sempre

percorrer o array inteiro para conseguir essa informação?

Além dessas di�culdades que os arrays apresentavam, faltava um conjunto robusto de classes para suprir a

necessidade de estruturas de dados básicas, como listas ligadas e tabelas de espalhamento.

Com esses e outros objetivos em mente, a Sun criou um conjunto de classes e interfaces conhecido como

Collections Framework, que reside no pacote java.util desde o Java2 1.2.

Collections

A API do Collections é robusta e possui diversas classes que representam estruturas de dadosavançadas.

Por exemplo, não é necessário reinventar a roda e criar uma lista ligada, mas sim utilizar aquela

que a Sun disponibilizou.

16.2 Listas: java.util.List

Um primeiro recurso que a API de Collections traz são listas. Uma lista é uma coleção que permite ele-mentos duplicados e mantém uma ordenação especí�ca entre os elementos.

Em outras palavras, você tem a garantia de que, quando percorrer a lista, os elementos serão encontrados

em uma ordem pré-determinada, de�nida na hora da inserção dos mesmos. Ela resolve todos os problemas

que levantamos em relação ao array (busca, remoção, tamanho “in�nito”,...). Esse código já está pronto!

A API de Collections traz a interface java.util.List, que especi�ca o que uma classe deve ser capaz defazer para ser uma lista. Há diversas implementações disponíveis, cada uma com uma forma diferente de

representar uma lista.

A implementação mais utilizada da interface List é a ArrayList, que trabalha com um array interno paragerar uma lista. Portanto, ela é mais rápida na pesquisa do que sua concorrente, a LinkedList, que é maisrápida na inserção e remoção de itens nas pontas.

Capítulo 16 - Collections framework - Listas: java.util.List - Página 211

Material do Treinamento Java e Orientação a Objetos

ArrayList não é um array!

É comum confundirem uma ArrayList com um array, porém ela não é um array. O que ocorreé que, internamente, ela usa um array como estrutura para armazenar os dados, porém este atri-

buto está propriamente encapsulado e você não tem como acessá-lo. Repare, também, que você

não pode usar [] com uma ArrayList, nem acessar atributo length. Não há relação!

Para criar um ArrayList, basta chamar o construtor:

ArrayList lista = new ArrayList();

É sempre possível abstrair a lista a partir da interface List:

List lista = new ArrayList();

Para criar uma lista de nomes (String), podemos fazer:

List lista = new ArrayList();lista.add("Manoel");lista.add("Joaquim");lista.add("Maria");

A interface List possui dois métodos add, um que recebe o objeto a ser inserido e o coloca no �nal da lista,e um segundo que permite adicionar o elemento em qualquer posição da mesma. Note que, em momento

algum, dizemos qual é o tamanho da lista; podemos acrescentar quantos elementos quisermos, que a lista

cresce conforme for necessário.

Toda lista (na verdade, toda Collection) trabalha do modo mais genérico possível. Isto é, não há umaArrayList especí�ca para Strings, outra para Números, outra para Datas etc. Todos os métodos trabalhamcom Object.

Assim, é possível criar, por exemplo, uma lista de Contas Correntes:

ContaCorrente c1 = new ContaCorrente();c1.deposita(100);

ContaCorrente c2 = new ContaCorrente();c2.deposita(200);

ContaCorrente c3 = new ContaCorrente();c3.deposita(300);

List contas = new ArrayList();

Capítulo 16 - Collections framework - Listas: java.util.List - Página 212

Material do Treinamento Java e Orientação a Objetos

contas.add(c1);contas.add(c3);contas.add(c2);

Para saber quantos elementos há na lista, usamos o método size():

System.out.println(contas.size());

Há ainda um método get(int) que recebe como argumento o índice do elemento que se quer recuperar.Através dele, podemos fazer um for para iterar na lista de contas:

for (int i = 0; i < contas.size(); i++) {contas.get(i); // código não muito útil....

}

Mas como fazer para imprimir o saldo dessas contas? Podemos acessar o getSaldo() diretamente após fazercontas.get(i)? Não podemos; lembre-se que toda lista trabalha sempre com Object. Assim, a referênciadevolvida pelo get(i) é do tipo Object, sendo necessário o cast para ContaCorrente se quisermos acessar ogetSaldo():

for (int i = 0; i < contas.size(); i++) {ContaCorrente cc = (ContaCorrente) contas.get(i);System.out.println(cc.getSaldo());

}// note que a ordem dos elementos não é alterada

Há ainda outrosmétodos, como remove() que recebe umobjeto que se deseja remover da lista; e contains(),que recebe umobjeto como argumento e devolve true ou false, indicando se o elemento está ou não na lista.

A interface List e algumas classes que a implementam podem ser vistas no diagrama a seguir:

Capítulo 16 - Collections framework - Listas: java.util.List - Página 213

Material do Treinamento Java e Orientação a Objetos

Acesso aleatório e percorrendo listas com get

Algumas listas, como a ArrayList, têm acesso aleatório aos seus elementos: a busca por umelemento em uma determinada posição é feita de maneira imediata, sem que a lista inteira seja

percorrida (que chamamos de acesso sequencial).

Neste caso, o acesso através do método get(int) é muito rápido. Caso contrário, percorrer umalista usando um for como esse que acabamos de ver, pode ser desastroso. Ao percorrermos umalista, devemos usar sempre um Iterator ou enhanced for, como veremos.

Uma lista é uma excelente alternativa a um array comum, já que temos todos os benefícios de arrays, sem a

necessidade de tomar cuidado com remoções, falta de espaço etc.

A outra implementação muito usada, a LinkedList, fornece métodos adicionais para obter e remover o pri-meiro e último elemento da lista. Ela também tem o funcionamento interno diferente, o que pode impactar

performance, como veremos durante os exercícios no �nal do capítulo.

Capítulo 16 - Collections framework - Listas: java.util.List - Página 214

Material do Treinamento Java e Orientação a Objetos

Vector

Outra implementação é a tradicional classe Vector, presente desde o Java 1.0, que foi adaptadapara uso com o framework de Collections, com a inclusão de novos métodos.

Ela deve ser escolhida com cuidado, pois lida de umamaneira diferente com processos correndo

em paralelo e terá um custo adicional em relação a ArrayList quando não houver acesso simul-tâneo aos dados.

16.3 Listas no Java 5 e Java 7 comGenerics

Em qualquer lista, é possível colocar qualquer Object. Com isso, é possível misturar objetos:

ContaCorrente cc = new ContaCorrente();

List lista = new ArrayList();lista.add("Uma string");lista.add(cc);...

Mas e depois, na hora de recuperar esses objetos? Como ométodo get devolve um Object, precisamos fazero cast. Mas com uma lista com vários objetos de tipos diferentes, isso pode não ser tão simples...

Geralmente, não nos interessa uma lista com vários tipos de objetos misturados; no dia-a-dia, usamos listas

como aquela de contas correntes. No Java 5.0, podemos usar o recurso de Generics para restringir as listas a

um determinado tipo de objetos (e não qualquer Object):

List<ContaCorrente> contas = new ArrayList<ContaCorrente>();contas.add(c1);contas.add(c3);contas.add(c2);

Repare no uso de um parâmetro ao lado de List e ArrayList: ele indica que nossa lista foi criada paratrabalhar exclusivamente com objetos do tipo ContaCorrente. Isso nos traz uma segurança em tempo decompilação:

contas.add("uma string"); // isso não compila mais!!

O uso de Generics também elimina a necessidade de casting, já que, seguramente, todos os objetos inseridos

na lista serão do tipo ContaCorrente:

Capítulo 16 - Collections framework - Listas no Java 5 e Java 7 com Generics - Página 215

Material do Treinamento Java e Orientação a Objetos

for(int i = 0; i < contas.size(); i++) {ContaCorrente cc = contas.get(i); // sem casting!System.out.println(cc.getSaldo());

}

A partir do Java 7, se você instancia um tipo genérico na mesma linha de sua declaração, não é necessário

passar os tipos novamente, basta usar new ArrayList<>(). É conhecido como operador diamante:

List<ContaCorrente> contas = new ArrayList<>();

16.4 A importância das interfaces nas coleções

Vale ressaltar a importância do uso da interface List: quando desenvolvemos, procuramos sempre nos referira ela, e não às implementações especí�cas. Por exemplo, se temos um método que vai buscar uma série de

contas no banco de dados, poderíamos fazer assim:

class Agencia {public ArrayList<Conta> buscaTodasContas() {

ArrayList<Conta> contas = new ArrayList<Conta>();

// para cada conta do banco de dados, contas.add

return contas;}

}

Porém, para que precisamos retornar a referência especí�ca a uma ArrayList? Para que ser tão especí�co?Dessa maneira, o dia que optarmos por devolver uma LinkedList em vez de ArrayList, as pessoas queestão usando o método buscaTodasContas poderão ter problemas, pois estavam fazendo referência a umaArrayList. O ideal é sempre trabalhar com a interface mais genérica possível:

class Agencia {

// modificação apenas no retorno:public List<Conta> buscaTodasContas() {

ArrayList<Conta> contas = new ArrayList<>();

// para cada conta do banco de dados, contas.add

return contas;}

}

Capítulo 16 - Collections framework - A importância das interfaces nas coleções - Página 216

Material do Treinamento Java e Orientação a Objetos

É o mesmo caso de preferir referenciar aos objetos com InputStream como �zemos no capítulo passado.

Assim como no retorno, é boa prática trabalhar com a interface em todos os lugares possíveis: métodos

que precisam receber uma lista de objetos têm List como parâmetro em vez de uma implementação emespecí�co como ArrayList, deixando o método mais �exível:

class Agencia {

public void atualizaContas(List<Conta> contas) {// ...

}}

Também declaramos atributos como List em vez de nos comprometer como uma ou outra implementação.Dessa forma obtemos um baixo acoplamento: podemos trocar a implementação, já que estamos progra-mando para a interface! Por exemplo:

class Empresa {

private List<Funcionario> empregados = new ArrayList<>();

// ...}

16.5 Ordenação: Collections.sort

Vimos anteriormente que as listas são percorridas de maneira pré-determinada de acordo com a inclusão

dos itens. Mas, muitas vezes, queremos percorrer a nossa lista de maneira ordenada.

A classe Collections traz um método estático sort que recebe um List como argumento e o ordena porordem crescente. Por exemplo:

List<String> lista = new ArrayList<>();lista.add("Sérgio");lista.add("Paulo");lista.add("Guilherme");

// repare que o toString de ArrayList foi sobrescrito:System.out.println(lista);

Collections.sort(lista);

System.out.println(lista);

Capítulo 16 - Collections framework - Ordenação: Collections.sort - Página 217

Material do Treinamento Java e Orientação a Objetos

Ao testar o exemplo acima, você observará que, primeiro, a lista é impressa na ordem de inserção e, depois

de invocar o sort, ela é impressa em ordem alfabética.

Mas toda lista em Java pode ser de qualquer tipo de objeto, por exemplo, ContaCorrente. E se quisermosordenar uma lista de ContaCorrente? Em que ordem a classe Collections ordenará? Pelo saldo? Pelo nomedo correntista?

ContaCorrente c1 = new ContaCorrente();c1.deposita(500);

ContaCorrente c2 = new ContaCorrente();c2.deposita(200);

ContaCorrente c3 = new ContaCorrente();c3.deposita(150);

List<ContaCorrente> contas = new ArrayList<>();contas.add(c1);contas.add(c3);contas.add(c2);

Collections.sort(contas); // qual seria o critério para esta ordenação?

Sempre que falamos em ordenação, precisamos pensar em um critério de ordenação, uma forma de de-terminar qual elemento vem antes de qual. É necessário instruir o sort sobre como comparar nossasContaCorrente a �m de determinar uma ordem na lista. Para isto, o método sort necessita que todos seusobjetos da lista sejam comparáveis e possuam ummétodo que se compara com outra ContaCorrente. Comoé que ométodo sort terá a garantia de que a sua classe possui essemétodo? Isso será feito, novamente, atravésde um contrato, de uma interface!

Vamos fazer com que os elementos da nossa coleção implementem a interface java.lang.Comparable, quede�ne o método int compareTo(Object). Este método deve retornar zero, se o objeto comparado for iguala este objeto, um número negativo, se este objeto for menor que o objeto dado, e um número positivo, seeste objeto formaior que o objeto dado.

Para ordenar as ContaCorrentes por saldo, basta implementar o Comparable:

public class ContaCorrente extends Contaimplements Comparable<ContaCorrente> {

// ... todo o código anterior fica aqui

public int compareTo(ContaCorrente outra) {if (this.saldo < outra.saldo) {

return -1;

Capítulo 16 - Collections framework - Ordenação: Collections.sort - Página 218

Material do Treinamento Java e Orientação a Objetos

}

if (this.saldo > outra.saldo) {return 1;

}

return 0;}

}

Com o código anterior, nossa classe tornou-se “comparável": dados dois objetos da classe, conseguimosdizer se um objeto é maior, menor ou igual ao outro, segundo algum critério por nós de�nido. No nosso

caso, a comparação será feita baseando-se no saldo da conta.

Repare que o critério de ordenação é totalmente aberto, de�nido pelo programador. Se quisermos ordenar

por outro atributo (ou até por uma combinação de atributos), basta modi�car a implementação do método

compareTo na classe.

Quando chamarmos o método sort de Collections, ele saberá como fazer a ordenação da lista; ele usará ocritério que de�nimos no método compareTo.

Mas, e o exemplo anterior, com uma lista de Strings? Por que a ordenação funcionou, naquele caso, sem

precisarmos fazer nada? Simples: quem escreveu a classe String (lembre que ela é uma classe como qualqueroutra) implementou a interface Comparable e o método compareTo para Strings, fazendo comparação emordem alfabética. (Consulte a documentação da classe String e veja o método compareTo lá). O mesmoacontece com outras classes como Integer, BigDecimal, Date, entre outras.

Definindo outros critérios de ordenação

É possível de�nir outros critérios de ordenação usando umobjeto do tipo Comparator. Existe ummétodo sort em Collections que recebe, além da List, um Comparator de�nindo um critériode ordenação especí�co. É possível ter vários Comparators com critérios diferentes para usarquando for necessário.

Capítulo 16 - Collections framework - Ordenação: Collections.sort - Página 219

Material do Treinamento Java e Orientação a Objetos

Outros métodos da classe Collections

A classe Collections traz uma grande quantidade de métodos estáticos úteis na manipulaçãode coleções.

• binarySearch(List, Object): Realiza uma busca binária por determinado elemento nalista ordenada e retorna sua posição ou um número negativo, caso não encontrado.

• max(Collection): Retorna o maior elemento da coleção.

• min(Collection): Retorna o menor elemento da coleção.

• reverse(List): Inverte a lista.

• ...e muitos outros. Consulte a documentação para ver outros métodos.

Existe uma classe análoga, a java.util.Arrays, que faz operações similares com arrays.

É importante conhecê-las para evitar escrever código já existente.

16.6 Exercícios: Ordenação

1) Abra sua classe Conta e veja se ela possui o atributo numero. Se não possuir, adicione-o:

protected int numero;

E gere o getter e o setter pelo Eclipse, caso necessário.

2) Faça sua classe ContaPoupanca implementar a interface Comparable<ContaPoupanca>. Utilize o critériode ordenar pelo número da conta ou pelo seu saldo (como visto no código deste capítulo).

public class ContaPoupanca extends Contaimplements Comparable<ContaPoupanca> {

...}

Repare que o Eclipse prontamente lhe oferecerá um quick�x, oferecendo a criação do esqueleto dos mé-

todos de�nidos na interface Comparable:

Capítulo 16 - Collections framework - Exercícios: Ordenação - Página 220

Material do Treinamento Java e Orientação a Objetos

Deixe o seu método compareTo parecido com este:

public class ContaPoupanca extends Contaimplements Comparable<ContaPoupanca> {

// ... todo o código anterior fica aqui

public int compareTo(ContaPoupanca o) {if (this.getNumero() < o.getNumero()) {

return -1;}if (this.getNumero() > o.getNumero()) {

return 1;}return 0;

}}

Outra implementação...

O que acha da implementação abaixo?

public int compareTo(ContaPoupanca outra) {return this.getNumero() - outra.getNumero();

}

3) Crie uma classe TestaOrdenacao, onde você vai instanciar diversas contas e adicioná-las a umaList<ContaPoupanca>. Use o Collections.sort() nessa lista:

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

List<ContaPoupanca> contas = new ArrayList<>();

ContaPoupanca c1 = new ContaPoupanca();c1.setNumero(1973);contas.add(c1);

ContaPoupanca c2 = new ContaPoupanca();c2.setNumero(1462);contas.add(c2);

ContaPoupanca c3 = new ContaPoupanca();c3.setNumero(1854);

Capítulo 16 - Collections framework - Exercícios: Ordenação - Página 221

Material do Treinamento Java e Orientação a Objetos

contas.add(c3);

Collections.sort(contas);}

}

Faça um laço para imprimir todos os números das contas na lista já ordenada:

for (int i = 0; i < contas.size(); i++) {Conta atual = contas.get(i);System.out.println("numero: " + atual.getNumero());

}

Atenção especial: repare que escrevemos um método compareTo em nossa classe e nosso código nuncao invoca!! Isto é muito comum. Reescrevemos (ou implementamos) um método e quem o invocará será

um outro conjunto de classes (nesse caso, quem está chamando o compareTo é o Collections.sort, queo usa como base para o algoritmo de ordenação). Isso cria um sistema extremamente coeso e, ao mesmo

tempo, com baixo acoplamento: a classe Collections nunca imaginou que ordenaria objetos do tipoContaPoupanca, mas já que eles são Comparable, o seu método sort está satisfeito.

Você poderia escrever o for acima de uma maneira mais sucinta:

for (int i = 0; i < contas.size(); i++) {System.out.println("numero: " + contas.get(i).getNumero());

}

4) O que teria acontecido se a classe ContaPoupanca não implementasse Comparable<ContaPoupanca>mastivesse o método compareTo?

Faça um teste: remova temporariamente a sentença implements Comparable<ContaPoupanca>, não re-mova o método compareTo e veja o que acontece. Basta ter o método, sem assinar a interface?

5) Utilize uma LinkedList em vez de ArrayList:

List<ContaPoupanca> contas = new LinkedList<>();

Precisamos alterar mais algum código para que essa substituição funcione? Rode o programa. Alguma

diferença?

6) Como posso inverter a ordem de uma lista? Como posso embaralhar todos os elementos de uma lista?

Como posso rotacionar os elementos de uma lista?

Investigue a documentação da classe Collections dentro do pacote java.util.

7) (opcional) Se preferir, insira novas contas através de um laço (for). Adivinhe o nome da classe paracolocar saldos aleatórios? Random. Do pacote java.util. Consulte sua documentação para usá-la (utilizeo método nextInt() passando o número máximo a ser sorteado).

8) (opcional) Imprima a referência para essa lista. Repare que o toString de uma ArrayList/LinkedList éreescrito:

Capítulo 16 - Collections framework - Exercícios: Ordenação - Página 222

Material do Treinamento Java e Orientação a Objetos

System.out.println(contas);

9) (opcional) Mude o critério de comparação da sua ContaPoupanca. Adicione um atributo nomeDoClientena sua classe (caso ainda não exista algo semelhante) e tente mudar o compareTo para que uma lista deContaPoupanca seja ordenada alfabeticamente pelo atributo nomeDoCliente.

Teste a ordenação.

16.7 Conjunto: java.util.Set

Um conjunto (Set) funciona de forma análoga aos conjuntos da matemática, ele é uma coleção que nãopermite elementos duplicados.

Outra característica fundamental dele é o fato de que a ordem em que os elementos são armazenados pode

não ser a ordem na qual eles foram inseridos no conjunto. A interface não de�ne como deve ser este com-

portamento. Tal ordem varia de implementação para implementação.

Capítulo 16 - Collections framework - Conjunto: java.util.Set - Página 223

Material do Treinamento Java e Orientação a Objetos

Um conjunto é representado pela interface Set e tem como suas principais implementações as classesHashSet, LinkedHashSet e TreeSet.

O código a seguir cria um conjunto e adiciona diversos elementos, e alguns repetidos:

Set<String> cargos = new HashSet<>();

cargos.add("Gerente");cargos.add("Diretor");cargos.add("Presidente");cargos.add("Secretária");cargos.add("Funcionário");cargos.add("Diretor"); // repetido!

// imprime na tela todos os elementosSystem.out.println(cargos);

Aqui, o segundo Diretor não será adicionado e o método add lhe retornará false.

O uso de um Set pode parecer desvantajoso, já que ele não armazena a ordem, e não aceita elementos re-petidos. Não há métodos que trabalham com índices, como o get(int) que as listas possuem. A grandevantagem do Set é que existem implementações, como a HashSet, que possui uma performance incompa-rável com as Lists quando usado para pesquisa (método contains por exemplo). Veremos essa enormediferença durante os exercícios.

Capítulo 16 - Collections framework - Conjunto: java.util.Set - Página 224

Material do Treinamento Java e Orientação a Objetos

Ordem de um Set

Seria possível usar uma outra implementação de conjuntos, como um TreeSet, que insere oselementos de tal forma que, quando forem percorridos, eles apareçam em uma ordem de�-

nida pelo método de comparação entre seus elementos. Esse método é de�nido pela interface

java.lang.Comparable. Ou, ainda, pode se passar um Comparator para seu construtor.

Já o LinkedHashSetmantém a ordem de inserção dos elementos.

Antes do Java 5, não podíamos utilizar generics, e usávamos o Set de forma que ele trabalhava com Object,havendo necessidade de castings.

16.8 Principais interfaces: java.util.Collection

As coleções têm como base a interface Collection, que de�ne métodos para adicionar e remover um ele-mento, e veri�car se ele está na coleção, entre outras operações, como mostra a tabela a seguir:

Uma coleção pode implementar diretamente a interface Collection, porém normalmente se usa uma dasduas subinterfaces mais famosas: justamente Set e List.

A interface Set, como previamente vista, de�ne um conjunto de elementos únicos enquanto a interface Listpermite elementos duplicados, além de manter a ordem a qual eles foram adicionados.

A busca em um Set pode ser mais rápida do que em um objeto do tipo List, pois diversas implementaçõesutilizam-se de tabelas de espalhamento (hash tables), realizando a busca para tempo linear (O(1)).

A interface Map faz parte do framework, mas não estende Collection. (veremos Mapmais adiante).

Capítulo 16 - Collections framework - Principais interfaces: java.util.Collection - Página 225

Material do Treinamento Java e Orientação a Objetos

No Java 5, temos outra interface �lha de Collection: a Queue, que de�ne métodos de entrada e de saída ecujo critério será de�nido pela sua implementação (por exemplo LIFO, FIFO ou ainda um heap onde cada

elemento possui sua chave de prioridade).

16.9 Percorrendo coleções no Java 5

Como percorrer os elementos de uma coleção? Se for uma lista, podemos sempre utilizar um laço for,invocando o método get para cada elemento. Mas e se a coleção não permitir indexação?

Por exemplo, um Set não possui um método para pegar o primeiro, o segundo ou o quinto elemento doconjunto, já que um conjunto não possui o conceito de “ordem”

Podemos usar o enhanced-for (o “foreach”) do Java 5 para percorrer qualquer Collection semnos preocuparcom isso. Internamente o compilador vai fazer com que seja usado o Iterator da Collection dada parapercorrer a coleção. Repare:

Set<String> conjunto = new HashSet<>();

conjunto.add("java");conjunto.add("vraptor");conjunto.add("scala");

for (String palavra : conjunto) {

Capítulo 16 - Collections framework - Percorrendo coleções no Java 5 - Página 226

Material do Treinamento Java e Orientação a Objetos

System.out.println(palavra);}

Em que ordem os elementos serão acessados?

Numa lista, os elementos aparecerão de acordo com o índice em que foram inseridos, isto é, de acordo com

o que foi pré-determinado. Em um conjunto, a ordem depende da implementação da interface Set: vocêmuitas vezes não vai saber ao certo em que ordem os objetos serão percorridos.

Por que o Set é, então, tão importante e usado?

Para perceber se um item já existe em uma lista, é muito mais rápido usar algumas implementações de Setdo que um List, e os TreeSets já vêm ordenados de acordo com as características que desejarmos! Sempreconsidere usar um Set se não houver a necessidade de guardar os elementos em determinada ordem e buscá-los através de um índice.

No eclipse, você pode escrever foreach e dar ctrl+espaço, que ele vai gerar o esqueleto desse enhanced for!Muito útil!

16.10 Para saber mais: Iterando sobre coleções comjava.util.Iterator

Antes do Java 5 introduzir o novo enhanced-for, iterações em coleções eram feitas com o Iterator. Todacoleção fornece acesso a um iterator, um objeto que implementa a interface Iterator, que conhece interna-mente a coleção e dá acesso a todos os seus elementos, como a �gura abaixo mostra.

Ainda hoje (depois do Java 5) podemos usar o Iterator, mas o mais comum é usar o enhanced-for. E, naverdade, o enhanced-for é apenas um açúcar sintático que usa iterator por trás dos panos.

Primeiro criamos um Iterator que entra na coleção. A cada chamada do método next, o Iterator retornao próximo objeto do conjunto. Um iterator pode ser obtido com o método iterator() de Collection,por exemplo numa lista de String:

Capítulo 16 - Collections framework - Para saber mais: Iterando sobre coleções com java.util.Iterator - Página 227

Material do Treinamento Java e Orientação a Objetos

Iterator<String> i = lista.iterator();

A interface Iterator possui dois métodos principais: hasNext() (com retorno booleano), indica se aindaexiste um elemento a ser percorrido; next(), retorna o próximo objeto.

Voltando ao exemplo do conjunto de strings, vamos percorrer o conjunto:

Set<String> conjunto = new HashSet<>();conjunto.add("item 1");conjunto.add("item 2");conjunto.add("item 3");

// retorna o iteratorIterator<String> i = conjunto.iterator();while (i.hasNext()) {

// recebe a palavraString palavra = i.next();System.out.println(palavra);

}

O while anterior só termina quando todos os elementos do conjunto forem percorridos, isto é, quando ométodo hasNextmencionar que não existem mais itens.

ListIterator

Uma lista fornece, além de acesso a um Iterator, um ListIterator, que oferece recursos adi-cionais, especí�cos para listas.

Usando o ListIterator, você pode, por exemplo, adicionar um elemento na lista ou voltar parao elemento que foi “iterado” anteriormente.

Usar Iterator em vez do enhanced-for?

O Iterator pode sim ainda ser útil, mesmo após o Java 5 . Além de iterar na coleção como fazo enhanced-for, o Iterator consegue remover elementos da coleção durante a iteração de umaforma elegante, através do método remove.

16.11 Mapas - java.util.Map

Muitas vezes queremos buscar rapidamente umobjeto dado alguma informação sobre ele. Umexemplo seria,

dada a placa do carro, obter todos os dados do carro. Poderíamos utilizar uma lista para isso e percorrer todos

Capítulo 16 - Collections framework - Mapas - java.util.Map - Página 228

Material do Treinamento Java e Orientação a Objetos

os seus elementos,mas isso pode ser péssimopara a performance,mesmopara listas nãomuito grandes. Aqui

entra o mapa.

Ummapa é composto por um conjunto de associações entre umobjeto chave a umobjeto valor. É equivalente

ao conceito de dicionário, usado em várias linguagens. Algumas linguagens, como Perl ou PHP, possuem um

suporte mais direto a mapas, onde são conhecidos como matrizes/arrays associativas.

java.util.Map é um mapa, pois é possível usá-lo para mapear uma chave a um valor, por exemplo: ma-peie à chave “empresa” o valor “Caelum”, ou então mapeie à chave “rua” ao valor “Vergueiro”. Semelhante a

associações de palavras que podemos fazer em um dicionário.

O método put(Object, Object) da interface Map recebe a chave e o valor de uma nova associação. Parasaber o que está associado a um determinado objeto-chave, passa-se esse objeto no método get(Object).Sem dúvida essas são as duas operações principais e mais frequentes realizadas sobre um mapa.

Observe o exemplo: criamos duas contas correntes e as colocamos em um mapa associando-as aos seus

donos.

ContaCorrente c1 = new ContaCorrente();c1.deposita(10000);

ContaCorrente c2 = new ContaCorrente();c2.deposita(3000);

// cria o mapaMap<String, ContaCorrente> mapaDeContas = new HashMap<>();

// adiciona duas chaves e seus respectivos valoresmapaDeContas.put("diretor", c1);mapaDeContas.put("gerente", c2);

Capítulo 16 - Collections framework - Mapas - java.util.Map - Página 229

Material do Treinamento Java e Orientação a Objetos

// qual a conta do diretor? (sem casting!)ContaCorrente contaDoDiretor = mapaDeContas.get("diretor");System.out.println(contaDoDiretor.getSaldo());

Ummapa é muito usado para “indexar” objetos de acordo com determinado critério, para podermos buscar

esse objetos rapidamente. Um mapa costuma aparecer juntamente com outras coleções, para poder realizar

essas buscas!

Ele, assim como as coleções, trabalha diretamente com Objects (tanto na chave quanto no valor), o quetornaria necessário o casting no momento que recuperar elementos. Usando os generics, como �zemos

aqui, não precisamos mais do casting.

Suas principais implementações são o HashMap, o TreeMap e o Hashtable.

Apesar do mapa fazer parte do framework, ele não estende a interface Collection, por ter um comporta-mento bem diferente. Porém, as coleções internas de um mapa (a de chaves e a de valores, ver Figura 7) são

acessíveis por métodos de�nidos na interface Map.

Ométodo keySet() retorna um Set com as chaves daquelemapa e ométodo values() retorna a Collectioncom todos os valores que foram associados a alguma das chaves.

Capítulo 16 - Collections framework - Mapas - java.util.Map - Página 230

Material do Treinamento Java e Orientação a Objetos

16.12 Para saber mais: Properties

Ummapa importante é a tradicional classe Properties, que mapeia strings e é muito utilizada para a con�-guração de aplicações.

A Properties possui, também, métodos para ler e gravar o mapeamento com base em um arquivo texto,facilitando muito a sua persistência.

Properties config = new Properties();

config.setProperty("database.login", "scott");config.setProperty("database.password", "tiger");config.setProperty("database.url","jdbc:mysql:/localhost/teste");

// muitas linhas depois...

String login = config.getProperty("database.login");String password = config.getProperty("database.password");String url = config.getProperty("database.url");DriverManager.getConnection(url, login, password);

Repare que não houve a necessidade do casting para String nomomento de recuperar os objetos associados.Isto porque a classe Properties foi desenhada com o propósito de trabalhar com a associação entre Strings.

16.13 Para saber mais: Equals eHashCode

Muitas das coleções do java guardam os objetos dentro de tabelas de hash. Essas tabelas são utilizadas para

que a pesquisa de um objeto seja feita de maneira rápida.

Como funciona? Cada objeto é “classi�cado” pelo seu hashCode e, com isso, conseguimos espalhar cadaobjeto agrupando-os pelo hashCode. Quando buscamos determinado objeto, só vamos procurar entre oselementos que estão no grupo daquele hashCode. Dentro desse grupo, vamos testando o objeto procuradocom o candidato usando equals().

Para que isso funcione direito, o método hashCode de cada objeto deve retornar o mesmo valor para doisobjetos, se eles são considerados equals. Em outras palavras:

a.equals(b) implica a.hashCode() == b.hashCode()

Implementar hashCode de tal maneira que ele retorne valores diferentes para dois objetos consideradosequals quebra o contrato de Object e resultará em collections que usam espalhamento (como HashSet,HashMap e Hashtable), não achando objetos iguais dentro de uma mesma coleção.

Capítulo 16 - Collections framework - Para saber mais: Properties - Página 231

Material do Treinamento Java e Orientação a Objetos

Equals e hashCode no Eclipse

O Eclipse é capaz de gerar uma implementação correta de equals e hashcode baseado nos atri-

butos que você queira comparar. Basta ir no menu Source e depois em Generate hashcode() and

equals().

16.14 Para saber mais: Boas práticas

As coleções do Java oferecemgrande �exibilidade ao usuário. A perda de performance em relação à utilização

de arrays é irrelevante, mas deve-se tomar algumas precauções:

• Grande parte das coleções usam, internamente, um array para armazenar os seus dados. Quando esse

array não é mais su�ciente, é criada um maior e o conteúdo da antiga é copiado. Este processo pode

acontecer muitas vezes, no caso de você ter uma coleção que cresce muito. Você deve, então, criar uma

coleção já com uma capacidade grande, para evitar o excesso de redimensionamento.

• Evite usar coleções que guardam os elementos pela sua ordem de comparação quando não há neces-

sidade. Um TreeSet gasta computacionalmente O(log(n)) para inserir (ele utiliza uma árvore rubro-negra como implementação), enquanto o HashSet gasta apenas O(1).

• Não itere sobre uma List utilizando um for de 0 até list.size() e usando get(int) para receber osobjetos. Enquanto isso parece atraente, algumas implementações da List não são de acesso aleatóriocomo a LinkedList, fazendo esse código ter umapéssima performance computacional. (use Iterator)

16.15 Exercícios: Collections

1) Crie um código que insira 30 mil números numa ArrayList e pesquise-os. Vamos usar um método deSystem para cronometrar o tempo gasto:

public class TestaPerformance {

public static void main(String[] args) {System.out.println("Iniciando...");long inicio = System.currentTimeMillis();Collection<Integer> teste = new ArrayList<>();

int total = 30000;

for (int i = 0; i < total; i++) {teste.add(i);

}

Capítulo 16 - Collections framework - Para saber mais: Boas práticas - Página 232

Material do Treinamento Java e Orientação a Objetos

for (int i = 0; i < total; i++) {teste.contains(i);

}

long fim = System.currentTimeMillis();long tempo = fim - inicio;System.out.println("Tempo gasto: " + tempo);

}}

Troque a ArrayList por um HashSet e veri�que o tempo que vai demorar:

Collection<Integer> teste = new HashSet<>();

O que é lento? A inserção de 30 mil elementos ou as 30 mil buscas? Descubra computando o tempo gasto

em cada for separadamente.

A diferença émais que gritante. Se você passar de 30mil para umnúmeromaior, como 50 ou 100mil, verá

que isso inviabiliza por completo o uso de uma List, no caso em que queremos utilizá-la essencialmenteem pesquisas.

2) (conceitual, importante) Repare que, se você declarar a coleção e der new assim:

Collection<Integer> teste = new ArrayList<>();

em vez de

ArrayList<Integer> teste = new ArrayList<>();

É garantido que vai ter de alterar só essa linha para substituir a implementação por HashSet. Estamosaqui usando o polimor�smo para nos proteger que mudanças de implementação venham nos obrigar a

alterar muito código. Mais uma vez: programe voltado a interface, e não à implementação! Esse é umexcelente exemplo de bom uso de interfaces, a�nal, de que importa como a coleção funciona? O quequeremos é uma coleção qualquer, isso é su�ciente para os nossos propósitos! Nosso código está com

baixo acoplamento em relação a estrutura de dados utilizada: podemos trocá-la facilmente.

Esse é um código extremamente elegante e �exível. Com o tempo você vai reparar que as pessoas tentam

programar sempre se referindo a essas interfaces menos especí�cas, na medida do possível: os métodos

costumam receber e devolver Collections, Lists e Sets em vez de referenciar diretamente uma imple-mentação. É o mesmo que ocorre com o uso de InputStream e OutputStream: eles são o su�ciente, nãohá porque forçar o uso de algo mais especí�co.

Obviamente, algumas vezes não conseguimos trabalhar dessa forma e precisamos usar uma interfacemais

especí�ca ou mesmo nos referir ao objeto pela sua implementação para poder chamar alguns métodos.

Por exemplo, TreeSet tem mais métodos que os de�nidos em Set, assim como LinkedList em relação aList.

3) Faça testes com o Map, como visto nesse capítulo:

Capítulo 16 - Collections framework - Exercícios: Collections - Página 233

Material do Treinamento Java e Orientação a Objetos

public class TestaMapa {

public static void main(String[] args) {Conta c1 = new ContaCorrente();c1.deposita(10000);

Conta c2 = new ContaCorrente();c2.deposita(3000);

// cria o mapaMap mapaDeContas = new HashMap();

// adiciona duas chaves e seus valoresmapaDeContas.put("diretor", c1);mapaDeContas.put("gerente", c2);

// qual a conta do diretor?Conta contaDoDiretor = (Conta) mapaDeContas.get("diretor");System.out.println(contaDoDiretor.getSaldo());

}}

Depois, altere o código para usar o generics, e não haver a necessidade do casting, além da garantia de

que nosso mapa estará seguro em relação a tipagem usada.

Você pode utilizar o quick�x do Eclipse para ele consertar isso, na linha em que você está chamando o

put. Depois de mais um quick�x (descubra!) seu código deve �car como segue:

// cria o mapaMap<String, Conta> mapaDeContas = new HashMap<>();

4) (opcional) Assim como no exercício 1, crie uma comparação entre ArrayList e LinkedList, para verqual é a mais rápida para se adicionar elementos na primeira posição (list.add(0, elemento)), comopor exemplo:

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

System.out.println("Iniciando...");long inicio = System.currentTimeMillis();

// trocar depois por ArrayListList<Integer> teste = new LinkedList<>();

for (int i = 0; i < 30000; i++) {teste.add(0, i);

}

Capítulo 16 - Collections framework - Exercícios: Collections - Página 234

Material do Treinamento Java e Orientação a Objetos

long fim = System.currentTimeMillis();double tempo = (fim - inicio) / 1000.0;System.out.println("Tempo gasto: " + tempo);

}}

Seguindo omesmo raciocínio, você pode ver qual é amais rápida para se percorrer usando o get(indice)(sabemos que o correto seria utilizar o enhanced for ou o iterator). Para isso, insira 30 mil elementos e

depois percorra-os usando cada implementação de List.

Perceba que aqui o nosso intuito não é que você aprenda quem é mais rápido que quem, o importante

é perceber que podemos tirar proveito do polimor�smo para nos comprometer apenas com a interface.

Depois, quando necessário, podemos trocar e escolher uma implementação mais adequada as nossas

necessidades. Mais uma vez aqui vemos a vantagem de programar voltado a interface.

5) (opcional) Crie uma classe Banco que possui uma List de Conta chamada contas. Repare que numa listade Conta, você pode colocar tanto ContaCorrente quanto ContaPoupanca por causa do polimor�smo.

Crie um método void adiciona(Conta c), um método Conta pega(int x) e outro intpegaTotalDeContas(), muito similar à relação anterior de Empresa-Funcionário. Basta usar a sualista e delegar essas chamadas para os métodos e coleções que estudamos.

6) (opcional) No Banco, crie um método Conta buscaPorNome(String nome) que procura por uma Contacujo nome seja equals ao nome dado.

Você pode implementar essemétodo comum for na sua lista de Conta, porém não tem uma performancee�ciente.

Adicionando um atributo privado do tipo Map<String, Conta> terá um impacto signi�cativo. Toda vezque o método adiciona(Conta c) for invocado, você deve invocar .put(c.getNome(), c) no seu mapa.Dessa maneira, quando alguém invocar o método Conta buscaPorNome(String nome), basta você fazero get no seu mapa, passando nome como argumento!

Acontece às vezes de termosmais de ummapa, se precisarmos buscar por objetos pormais de um critério.

7) (opcional, avançado) Crie o método hashCode para a sua conta, de forma que ele respeite o equals deque duas contas são equals quando tem omesmo número. Veri�que se sua classe funciona corretamentenum HashSet. Remova o método hashCode. Continua funcionando?

Dominar o uso e o funcionamento do hashCode é fundamental para o bom programador.

16.16 Desafios

1) Gere todos os números entre 1 e 1000 e ordene em ordem decrescente utilizando um TreeSet.

2) Gere todos os números entre 1 e 1000 e ordene em ordem decrescente utilizando um ArrayList.

Capítulo 16 - Collections framework - Desa�os - Página 235

Capítulo 17

Programação Concorrente e�reads

“O único lugar onde o sucesso vem antes do trabalho é no dicionário.”– Albert Einstein

Ao término desse capítulo, você será capaz de:

• executar tarefas simultaneamente;

• colocar tarefas para aguardar até que um determinado evento ocorra;

• entender o funcionamento do Garbage Collector.

17.1 Threads

“Duas tarefas ao mesmo tempo"

Em várias situações, precisamos “rodar duas coisas ao mesmo tempo”. Imagine um programa que gera um

relatório muito grande em PDF. É um processo demorado e, para dar alguma satisfação para o usuário,

queremos mostrar uma barra de progresso. Queremos então gerar o PDF e ao mesmo tempo atualizar abarrinha.

Pensando um pouco mais amplamente, quando usamos o computador também fazemos várias coisas simul-

taneamente: queremos navegar na internet e ao mesmo tempo ouvir música.

A necessidade de se fazer várias coisas simultaneamente, ao mesmo tempo, paralelamente, aparece fre-quentemente na computação. Para vários programas distintos, normalmente o próprio sistema operacional

gerencia isso através de vários processos em paralelo.

Em um programa só (um processo só), se queremos executar coisas em paralelo, normalmente falamos de

�reads.

Material do Treinamento Java e Orientação a Objetos

Threads em Java

Em Java, usamos a classe Thread do pacote java.lang para criarmos linhas de execução paralelas. A classeThread recebe como argumento um objeto com o código que desejamos rodar. Por exemplo, no programade PDF e barra de progresso:

public class GeraPDF {public void rodar () {

// lógica para gerar o pdf...}

}

public class BarraDeProgresso {public void rodar () {

// mostra barra de progresso e vai atualizando ela...}

}

E, no método main, criamos os objetos e passamos para a classe Thread. O método start é responsável poriniciar a execução da Thread:

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

GeraPDF gerapdf = new GeraPDF();Thread threadDoPdf = new Thread(gerapdf);threadDoPdf.start();

BarraDeProgresso barraDeProgresso = new BarraDeProgresso();Thread threadDaBarra = new Thread(barraDeProgresso);threadDaBarra.start();

}}

O código acima, porém, não compilará. Como a classe Thread sabe que deve chamar o método roda? Comoela sabe que nome de método daremos e que ela deve chamar esse método especial? Falta na verdade um

contrato entre as nossas classes a serem executadas e a classe Thread.

Esse contrato existe e é feito pela interface Runnable: devemos dizer que nossa classe é “executável” e que segueesse contrato. Na interface Runnable, há apenas um método chamado run. Basta implementá-lo, “assinar” ocontrato e a classe Thread já saberá executar nossa classe.

public class GeraPDF implements Runnable {public void run () {

Capítulo 17 - Programação Concorrente e�reads - �reads - Página 237

Material do Treinamento Java e Orientação a Objetos

// lógica para gerar o pdf...}

}

public class BarraDeProgresso implements Runnable {public void run () {

// mostra barra de progresso e vai atualizando ela...}

}

A classe Thread recebe no construtor um objeto que é um Runnable, e seu método start chama o métodorun da nossa classe. Repare que a classe Thread não sabe qual é o tipo especí�co da nossa classe; para ela,basta saber que a classe segue o contrato estabelecido e possui o método run.

É o bom uso de interfaces, contratos e polimor�smo na prática!

Estendendo a classe Thread

A classe Thread implementa Runnable. Então, você pode criar uma subclasse dela e reescrever orun que, na classe Thread, não faz nada:

public class GeraPDF extends Thread {public void run () {

// ...}

}

E, como nossa classe é uma Thread, podemos usar o start diretamente:

GeraPDF gera = new GeraPDF();gera.start();

Apesar de ser um código mais simples, você está usando herança apenas por “preguiça” (her-

damos um monte de métodos mas usamos apenas o run), e não por polimor�smo, que seria agrande vantagem. Pre�ra implementar Runnable a herdar de Thread.

Capítulo 17 - Programação Concorrente e�reads - �reads - Página 238

Material do Treinamento Java e Orientação a Objetos

Dormindo

Para que a thread atual durma basta chamar o método a seguir, por exemplo, para dormir 3

segundos:

Thread.sleep(3 * 1000);

17.2 Escalonador e trocas de contexto

Veja a classe a seguir:

1 public class Programa implements Runnable {2

3 private int id;4 // colocar getter e setter pro atributo id5

6 public void run () {7 for (int i = 0; i < 10000; i++) {8 System.out.println("Programa " + id + " valor: " + i);9 }10 }11 }

É uma classe que implementa Runnable e, no método run, apenas imprime dez mil números. Vamos usá-lasduas vezes para criar duas threads e imprimir os números duas vezes simultaneamente:

1 public class Teste {2 public static void main(String[] args) {3

4 Programa p1 = new Programa();5 p1.setId(1);6

7 Thread t1 = new Thread(p1);8 t1.start();9

10 Programa p2 = new Programa();11 p2.setId(2);12

13 Thread t2 = new Thread(p2);

Capítulo 17 - Programação Concorrente e�reads - Escalonador e trocas de contexto - Página 239

Material do Treinamento Java e Orientação a Objetos

14 t2.start();15

16 }17 }

Se rodarmos esse programa, qual será a saída? De um a mil e depois de um a mil? Provavelmente não, senão

seria sequencial. Ele imprimirá 0 de t1, 0 de t2, 1 de t1, 1 de t2, 2 de t1, 2 de t2 e etc? Exatamente intercalado?

Na verdade, não sabemos exatamente qual é a saída. Rode o programa várias vezes e observe: em cada

execução a saída é um pouco diferente.

O problema é que no computador existe apenas um processador capaz de executar coisas. E quando quere-

mos executar várias coisas ao mesmo tempo, e o processador só consegue fazer uma coisa de cada vez? Entra

em cena o escalonador de threads.

O escalonador (scheduler), sabendo que apenas uma coisa pode ser executada de cada vez, pega todas asthreads que precisam ser executadas e faz o processador �car alternando a execução de cada uma delas. A

ideia é executar um pouco de cada thread e fazer essa troca tão rapidamente que a impressão que �ca é que

as coisas estão sendo feitas ao mesmo tempo.

O escalonador é responsável por escolher qual a próxima thread a ser executada e fazer a troca de contexto(context switch). Ele primeiro salva o estado da execução da thread atual para depois poder retomar a exe-

cução da mesma. Aí ele restaura o estado da thread que vai ser executada e faz o processador continuar

a execução desta. Depois de um certo tempo, esta thread é tirada do processador, seu estado (o contexto)

é salvo e outra thread é colocada em execução. A troca de contexto é justamente as operações de salvar ocontexto da thread atual e restaurar o da thread que vai ser executada em seguida.

Quando fazer a troca de contexto, por quanto tempo a thread vai rodar e qual vai ser a próxima thread a ser

executada, são escolhas do escalonador. Nós não controlamos essas escolhas (embora possamos dar “dicas”

ao escalonador). Por isso que nunca sabemos ao certo a ordem em que programas paralelos são executados.

Você pode pensar que é ruim não saber a ordem. Mas perceba que se a ordem importa para você, se é

importante que determinada coisa seja feita antes de outra, então não estamos falando de execuções paralelas,

mas sim de um programa sequencial normal (onde uma coisa é feita depois da outra, em uma sequência).

Todo esse processo é feito automaticamente pelo escalonador do Java (e, mais amplamente, pelo escalona-

dor do sistema operacional). Para nós, programadores das threads, é como se as coisas estivessem sendo

executadas ao mesmo tempo.

Capítulo 17 - Programação Concorrente e�reads - Escalonador e trocas de contexto - Página 240

Material do Treinamento Java e Orientação a Objetos

E em mais de um processador?

A VM do Java e a maioria dos SOs modernos consegue fazer proveito de sistemas com vários

processadores oumulti-core. A diferença é que agora temosmais de um processador executando

coisas e teremos, sim, execuções verdadeiramente paralelas.

Mas o número de processos no SO e o número de�reads paralelas costumam ser tão grandes

que, mesmo com vários processadores, temos as trocas de contexto. A diferença é que o esca-

lonador tem dois ou mais processadores para executar suas threads. Mas di�cilmente terá uma

máquina com mais processadores que threads paralelas executando.

17.3 Garbage Collector

O Garbage Collector (coletor de lixo, lixeiro) funciona como uma Thread responsável por jogar fora todosos objetos que não estão sendo referenciados por nenhum outro objeto - seja de maneira direta ou indireta.

Considere o código:

Conta conta1 = new ContaCorrente();Conta conta2 = new ContaCorrente();

Até este momento, sabemos que temos 2 objetos em memória. Aqui, o Garbage Collector não pode eliminarnenhum dos objetos, pois ainda tem alguém se referindo a eles de alguma forma.

Podemos, então, executar uma linha que nos faça perder a referência para umdos dois objetos criados, como,

por exemplo, o seguinte código:

conta2 = conta1;

Quantos objetos temos em memória?

Perdemos a referência para um dos objetos que foram criados. Esse objeto já não é mais acessível. Temos,

então, apenas um objeto emmemória? Não podemos a�rmar isso! Como oGarbage Collector é uma�read,você não tem garantia de quando ele vai rodar. Você só sabe que, em algum momento no futuro, aquela

memória vai ser liberada.

Algumas pessoas costumam atribuir null a uma variável, com o intuito de acelerar a passagem do GarbageCollector por aquele objeto:

for (int i = 0; i < 100; i++) {List x = new ArrayList();// faz algumas coisas com a arraylistx = null;

}

Capítulo 17 - Programação Concorrente e�reads - Garbage Collector - Página 241

Material do Treinamento Java e Orientação a Objetos

Isso rarissimamente é necessário. OGarbage Collector age apenas sobre objetos, nunca sobre variáveis. Nessecaso, a variável x não existirá mais a cada iteração, deixando a ArrayList criada sem nenhuma referênciapara ela.

System.gc()

Você nunca consegue forçar o Garbage Collector, mas chamando o método estático gc da classeSystem, você está sugerindo que a Virtual Machine rode o Garbage Collector naquele momento.Se sua sugestão vai ser aceita ou não, isto depende de JVM para JVM, e você não tem garantias.

Evite o uso deste método. Você não deve basear sua aplicação em quando o Garbage Collector

vai rodar ou não.

Finalizer

A classe Object de�ne também um método finalize, que você pode reescrever. Esse métodoserá chamado no instante antes do Garbage Collector coletar este objeto. Não é um destrutor,

você não sabe em que momento ele será chamado. Algumas pessoas o utilizam para liberar

recursos “caros” como conexões, threads e recursos nativos. Isso deve ser utilizado apenas por

segurança: o ideal é liberar esses recursos o mais rápido possível, sem depender da passagem do

Garbage Collector.

17.4 Para saber mais: problemas com concorrência

O uso de�reads começa a �car interessante e complicado quando precisamos compartilhar objetos entre

várias�reads.

Imagine a seguinte situação: temos umBanco commilhões de Contas Bancárias. Clientes sacam e depositam

dinheiro continuamente, 24 horas por dia. No primeiro dia de cada mês, o Banco precisa atualizar o saldo de

todas as Contas de acordo com uma taxa especí�ca. Para isso, ele utiliza o AtualizadorDeContas que vimosanteriormente.

O AtualizadorDeContas, basicamente, pega uma a uma cada umadasmilhões de contas e chama seumétodoatualiza. A atualização de milhões de contas é um processo demorado, que dura horas; é inviável pararo banco por tanto tempo até que as atualizações tenham completado. É preciso executar as atualizações

paralelamente às atividades, de depósitos e saques, normais do banco.

Ou seja, teremos várias threads rodando paralelamente. Em uma thread, pegamos todas as contas e vamos

chamando o método atualiza de cada uma. Em outra, podemos estar sacando ou depositando dinheiro.Estamos compartilhando objetos entre múltiplas threads (as contas, no nosso caso).

Capítulo 17 - Programação Concorrente e�reads - Para saber mais: problemas com concorrência - Página 242

Material do Treinamento Java e Orientação a Objetos

Imagine a seguinte possibilidade (mesmo que muito remota): no exato instante em que o atualizador está

atualizando uma Conta X, o cliente dono desta Conta resolve efetuar um saque. Como sabemos, ao trabalhar

com�reads, o escalonador pode parar uma certa�read a qualquer instante para executar outra, e você

não tem controle sobre isso.

Veja essa classe Conta:

1 public class Conta {2

3 private double saldo;4

5 // outros métodos e atributos...6

7 public void atualiza(double taxa) {8 double saldoAtualizado = this.saldo * (1 + taxa);9 this.saldo = saldoAtualizado;10 }11

12 public void deposita(double valor) {13 double novoSaldo = this.saldo + valor;14 this.saldo = novoSaldo;15 }16 }

Imagine uma Conta com saldo de 100 reais. Um cliente entra na agência e faz um depósito de 1000 reais.

Isso dispara uma�read no banco que chama o método deposita(); ele começa calculando o novoSaldoque passa a ser 1100 (linha 13). Só que por algummotivo que desconhecemos, o escalonador pára essa thread.

Neste exato instante, ele começa a executar uma outra�read que chama o método atualiza da mesmaConta, por exemplo, com taxa de 1%. Isso quer dizer que o novoSaldo passa a valer 101 reais (linha 8). E, nesseinstante o escalonador troca de�reads novamente. Ele executa a linha 14 na�read que fazia o depósito; o

saldo passa a valer 1100. Acabando o deposita, o escalonador volta pra�read do atualiza e executa a linha

9, fazendo o saldo valer 101 reais.

Resultado: o depósito de mil reais foi totalmente ignorado e seu Cliente �cará pouco feliz com isso. Perceba

que não é possível detectar esse erro, já que todo o código foi executado perfeitamente, sem problemas. Oproblema, aqui, foi o acesso simultâneo de duas�reads ao mesmo objeto.

E o erro só ocorreu porque o escalonador parou nossas�reads naqueles exatos lugares. Pode ser que nosso

código �que rodando 1 ano sem dar problema algum e em um belo dia o escalonador resolve alternar nossas

�reads daquela forma. Não sabemos como o escalonador se comporta! Temos que proteger nosso código

contra esse tipo de problema. Dizemos que essa classe não é thread safe, isso é, não está pronta para ter umainstância utilizada entre várias threads concorrentemente.

O que queríamos era que não fosse possível alguém atualizar a Conta enquanto outra pessoa está depositandoum dinheiro. Queríamos que uma�read não pudesse mexer em uma Conta enquanto outra�read está

Capítulo 17 - Programação Concorrente e�reads - Para saber mais: problemas com concorrência - Página 243

Material do Treinamento Java e Orientação a Objetos

mexendo nela. Não há como impedir o escalonador de fazer tal escolha. Então, o que fazer?

Uma ideia seria criar uma trava e, no momento em que uma�read entrasse em um desses métodos, elatrancaria a entrada com uma chave. Dessa maneira, mesmo que sendo colocada de lado, nenhuma outra

�read poderia entrar nesses métodos, pois a chave estaria com a outra�read.

Essa ideia é chamada de região crítica. É um pedaço de código que de�nimos como crítico e que não podeser executado por duas threads ao mesmo tempo. Apenas uma thread por vez consegue entrar em alguma

região crítica.

Podemos fazer isso em Java. Podemos usar qualquer objeto como um lock (trava, chave), para poder sincro-nizar em cima desse objeto, isto é, se uma�read entrar em um bloco que foi de�nido como sincronizadopor esse lock, apenas uma�read poderá estar lá dentro ao mesmo tempo, pois a chave estará com ela.

A palavra chave synchronized dá essa característica a um bloco de código e recebe qual é o objeto que seráusado como chave. A chave só é devolvida no momento em que a�read que tinha essa chave sair do bloco,

seja por return ou disparo de uma exceção (ou ainda na utilização do método wait())..

Queremos, então, bloquear o acesso simultâneo a uma mesma Conta:

public class Conta {

private double saldo;

// outros métodos e atributos...

public void atualiza(double taxa) {synchronized (this) {

double saldoAtualizado = this.saldo * (1 + taxa);this.saldo = saldoAtualizado;

}}

public void deposita(double valor) {synchronized (this) {

double novoSaldo = this.saldo + valor;this.saldo = novoSaldo;

}}

}

Observe o uso dos blocos synchronized dentro dos dois métodos. Eles bloqueiam uma�read utilizando omesmo objeto Conta, o this.

Esses métodos sãomutuamente exclusivos e só executam demaneira atômica.�reads que tentam pegar um

lock que já está pego, �carão emumconjunto especial esperando pela liberação do lock (não necessariamente

numa �la).

Capítulo 17 - Programação Concorrente e�reads - Para saber mais: problemas com concorrência - Página 244

Material do Treinamento Java e Orientação a Objetos

Sincronizando o bloco inteiro

É comum sempre sincronizarmos um método inteiro, normalmente utilizando o this.

public void metodo() {synchronized (this) {

// conteúdo do metodo}

}

Para este mesmo efeito, existe uma sintaxe mais simples, onde o synchronized pode ser usadocomo modi�cador do método:

public synchronized void metodo() {// conteúdo do metodo

}

Mais sobre locks,monitores e concorrência

Se o método for estático, será sincronizado usando o lock do objeto que representa a classe

(NomeDaClasse.class).

Além disso, o pacote java.util.concurrent, conhecido como JUC, entrou no Java 5.0 parafacilitar uma série de trabalhos comuns que costumam aparecer em uma aplicação concorrente.

Esse pacote ajuda até mesmo criar threads e pool de threads, através dos Executors.

17.5 Para saber mais: Vector eHashtable

Duas collections muito famosas são Vector e Hashtable, a diferença delas com suas irmãs ArrayList eHashMap é que as primeiras são thread safe.

Você pode se perguntar porque não usamos sempre essas classes thread safe. Adquirir um lock temum custo,

e caso um objeto não vá ser usado entre diferentes threads, não há porque usar essas classes que consomem

mais recursos. Mas nem sempre é fácil enxergar se devemos sincronizar um bloco, ou se devemos utilizar

blocos sincronizados.

Antigamente o custo de se usar locks era altíssimo, hoje em dia isso custa pouco para a JVM, mas não é

Capítulo 17 - Programação Concorrente e�reads - Para saber mais: Vector e Hashtable - Página 245

Material do Treinamento Java e Orientação a Objetos

motivo para você sincronizar tudo sem necessidade.

17.6 Um pouco mais...

1) Você pode mudar a prioridade de cada uma de suas�reads, mas isto também é apenas uma sugestão ao

escalonador.

2) Existe um método stop nas�reads, porque não é boa prática chamá-lo?

3) Um tópico mais avançado é a utilização de wait, notifiy e notifyAll para que as�reads comuniquem-se de eventos ocorridos, indicando que podem ou não podem avançar de acordo com condições

4) O pacote java.util.concurrent foi adicionado no Java 5 para facilitar o trabalho na programação con-corrente. Ele possui uma série de primitivas para que você não tenha de trabalhar diretamente com waite notify, além de ter diversas coleções thread safe.

17.7 Exercícios

1) Teste o exemplo deste capítulo para imprimir números em paralelo.

Escreva a classe Programa:

1 public class Programa implements Runnable {2

3 private int id;4 // colocar getter e setter pro atributo id5

6 public void run () {7 for (int i = 0; i < 10000; i++) {8 System.out.println("Programa " + id + " valor: " + i);9 }10 }11 }

Escreva a classe de Teste:

1 public class Teste {2 public static void main(String[] args) {3

4 Programa p1 = new Programa();5 p1.setId(1);6

7 Thread t1 = new Thread(p1);8 t1.start();9

Capítulo 17 - Programação Concorrente e�reads - Um pouco mais... - Página 246

Material do Treinamento Java e Orientação a Objetos

10 Programa p2 = new Programa();11 p2.setId(2);12

13 Thread t2 = new Thread(p2);14 t2.start();15

16 }17 }

Rode várias vezes a classe Teste e observe os diferentes resultados em cada execução.

17.8 Exercícios avançados de programação concorrente elocks

Exercícios só recomendados se você já tinha algum conhecimento prévio de programação concorrente, locks,

etc.

1) Vamos enxergar o problema ao se usar uma classe que não é thread safe: a LinkedList por exemplo.

Imagine que temos um objeto que guarda todas as SQLs que uma aplicação precisa executar. Vamos usaruma LinkedList<String> para armazená-los. Nossa aplicação é multi thread, então diferentes threadsvão inserir diferentes SQLs para serem executados. Não importa a ordem que elas sejam executadas,

desde que elas um dia sejam!

Vamos usar a seguinte classe para adicionar as queries:

public class ProduzSQL implements Runnable{private int comeco;private int fim;private Collection<String> sqls;

public ProduzSQL(int comeco, int fim, Collection<String> sqls) {this.comeco = comeco;this.fim = fim;this.sqls = sqls;

}

public void run() {for (int i = comeco; i < fim; i++) {

sqls.add("SQL"+i);}

}}

Vamos criar três threads que rodem esse código, todas adicionando SQLs nomesmo HashSet. Em outras

Capítulo 17 - Programação Concorrente e�reads - Exercícios avançados de programação concorrente e locks - Página 247

Material do Treinamento Java e Orientação a Objetos

palavras, teremos threads compartilhando e acessando um mesmo objeto: é aqui que mora o perigo.

public class BancoDeDados {public static void main(String[] args) throws InterruptedException {

Collection<String> sqls = new HashSet<String>();

ProduzSQL p1 = new ProduzSQL(0, 10000, sqls);Thread t1 = new Thread(p1);

ProduzSQL p2 = new ProduzSQL(10000, 20000, sqls);Thread t2 = new Thread(p2);

ProduzSQL p3 = new ProduzSQL(20000, 30000, sqls);Thread t3 = new Thread(p3);

t1.start();t2.start();t3.start();

// faz com que nós (nós = thread que roda o main)// aguardemos o fim dessas três threadst1.join();t2.join();t3.join();

System.out.println("Threads produtoras de SQLs finalizadas!");

// verifica se todas as SQLs foram executadasfor (int i = 0; i < 15000; i++) {

if (!sqls.contains("SQL" + i)) {throw new IllegalStateException("não encontrei a SQL" + i);

}}

// verifica se null não se encontra!if (sqls.contains(null)) {

throw new IllegalStateException("não devia ter null aqui dentro!");}

System.out.println("Fim da execucao com sucesso");}

}

2) Teste o código anterior, mas usando synchronized ao adicionar na coleção:

public void run() {

Capítulo 17 - Programação Concorrente e�reads - Exercícios avançados de programação concorrente e locks - Página 248

Material do Treinamento Java e Orientação a Objetos

for (int i = comeco; i < fim; i++) {synchronized(sqls) {

sqls.add("SQL"+i);}

}}

3) Sem usar o synchronized teste com a classe Vector (que é uma Collection).

4) Novamente sem usar o synchronized, teste usar HashSet e ArrayList, em vez de Vector. Faça váriostestes, pois as threads vão se entrelaçar cada vez de uma maneira diferente, podendo ou não ter um efeito

inesperado.

No capítulo de Sockets usaremos threads para solucionar um problema real de execuções paralelas.

Capítulo 17 - Programação Concorrente e�reads - Exercícios avançados de programação concorrente e locks - Página 249

Capítulo 18

E agora?

“A primeira coisa a entender é que você não entende."– Soren Aabye Kierkegaard

Onde continuar ao terminar os exercícios de ‘Java e Orientação a Objetos’.

18.1 Praticando Java e usando bibliotecas

A melhor maneira para �xar tudo o que foi visto nos capítulos anteriores é planejar e montar pequenos

sistemas. Pense na modelagem de suas classes, como e onde usar herança, polimor�smo, encapsulamento e

outros conceitos. Pratique o uso das APIs mais úteis do Java integrando-as ao seus sistemas.

O curso FJ-16 é um laboratório que além de demonstrar o uso diversas APIs e boas práticas, vai mostrar

diversos design patterns e seus casos de uso. Para quem é aluno da Caelum, a apostila do FJ-16 está disponível

para download e pode ser baixada em: http://aluno.caelum.com.br/

18.2 Web

Um dos principais focos de Java, hoje em dia, é onde a maior parte das vagas existem: programando para a

web. Entram aqui tecnologias como Servlets, JSPs e ferramentas famosas do mercado, como o Struts.

A Caelum oferece o curso FJ-21, onde você pode estudar os tópicos necessários para começar a trabalhar com

Java na web usando as melhores práticas, design patterns e tecnologias do mercado. Essa apostila também

está disponível para download.

Material do Treinamento Java e Orientação a Objetos

18.3 Certificação

Vimos com profundidade diversos tópicos da linguagem Java, mas entrar em detalhes nos assuntos contidos

até agora, iriam no mínimo tornar os capítulos quatro vezes maior do que já são.

Os tópicos abordados (com a adição e remoção de alguns) constituem boa parte do que é cobrado na certi-

�cação o�cial para programadores da Oracle/Sun.

Para maiores informações sobre certi�cações, consulte a própria Sun, o javaranch.com ou o guj.com.br, que

possui diversas informações sobre o assunto. A Caelum oferece um curso de preparação para a prova de

certi�cação como programador em Java pela Oracle/Sun, o FJ-19. O objetivo desse curso vai além da certi-

�cação, pois vai se aprofundar bastante na linguagem sem ter de decorar regras, e sim entendendo como e

por que a sintaxe é desta maneira.

18.4 Revistas

Diversas revistas no Brasil e no exterior estudam o mundo java como ninguém, e podem ajudar o iniciante

a conhecer muito do que está acontecendo lá fora nas aplicações comerciais.

18.5 Grupos deUsuários

Diversos programadores com o mínimo ou máximo de conhecimento se reúnem online para a troca de

dúvidas, informações e ideias sobre projetos, bibliotecas e muito mais. São os grupos de usuários de java.

Um dos mais importantes e conhecidos no Brasil é o GUJ: http://www.guj.com.br

18.6 Falando em Java - Próximos módulos

O ‘Falando em Java’ não pára por aqui. A Caelum oferece uma grande variedade de cursos que você pode

seguir. Alguns dos mais requisitados:

FJ-19: Preparatório para Certi�cação Java

FJ-21: Java para desenvolvimento Web

FJ-16: Laboratório Java com Design Patterns, XML e Testes

FJ-25: Persistência com JPA2 e Hibernate

FJ-26: Laboratório Web com JSF2 e CDI

FJ-28: Desenvolvimento ágil para Web 2.0 com VRaptor, Hibernate e AJAX

FJ-31: Enterprise JavaBeans (EJB)

Capítulo 18 - E agora? - Certi�cação - Página 251

Material do Treinamento Java e Orientação a Objetos

FJ-57: Desenvolvimento móvel com Google Android

FJ-91: Arquitetura e Design de Projetos Java

RR-71: Desenvolvimento ágil para Web 2.0 com Ruby on Rails

RR-75: Ruby e Rails avançados: lidando com problemas do dia a dia

Consulte mais informações no nosso site e entre em contato conosco.

Capítulo 18 - E agora? - Falando em Java - Próximos módulos - Página 252

Capítulo 19

Apêndice - Sockets

“Olho por olho, e o mundo acabará cego."–Mohandas Gandhi

Conectando-se a máquinas remotas.

19.1 Motivação: uma API que usa os conceitos aprendidos

Neste capítulo, você vai conhecer a API de Sockets do java pelo pacote java.net.

Mais útil que conhecer a API, é você perceber que estamos usando, aqui, todos os conceitos e bibliotecas

aprendidas durante os outros capítulos. Repare, também, que é relativamente simples aprender a utilizar

uma API, agora que temos todos os conceitos necessários para tal.

Lembre-se de fazer esse apêndice com o javadoc aberto ao seu lado.

19.2 Protocolo

Da necessidade de dois computadores se comunicarem, surgiram diversos protocolos que permitissem tal

troca de informação: o protocolo que vamos usar aqui é o TCP (Transmission Control Protocol).

Através do TCP, é possível criar um �uxo entre dois computadores - como é mostrado no diagrama abaixo:

Material do Treinamento Java e Orientação a Objetos

É possível conectar mais de um cliente ao mesmo servidor, como é o caso de diversos banco de dados, ser-

vidores Web, etc.

Ao escrever um programa em Java que se comunique com outra aplicação, não é necessário se preocupar

com um nível tão baixo quanto o protocolo. As classes que trabalham com eles já foram disponibilizadas

para serem usadas por nós no pacote java.net.

A vantagem de se usar TCP, em vez de criar nosso próprio protocolo de bytes, é que o TCP vai garantir a

entrega dos pacotes que transferirmos e criar um protocolo base para isto é algo bem complicado.

19.3 Porta

Acabamos de mencionar que diversos computadores podem se conectar a um só, mas, na realidade, é muito

comum encontrar máquinas clientes com uma só conexão física. Então, como é possível se conectar a dois

pontos? Como é possível ser conectado por diversos pontos?

Todas as aplicações que estão enviando e recebendo dados fazem isso através da mesma conexão física, mas

o computador consegue discernir, durante a chegada de novos dados, quais informações pertencem a qual

aplicação. Mas como?

Capítulo 19 - Apêndice - Sockets - Porta - Página 254

Material do Treinamento Java e Orientação a Objetos

Assim como existe o IP para identi�car umamáquina, a porta é a solução para identi�car diversas aplicaçõesem umamáquina. Esta porta é um número de 2 bytes, varia de 0 a 65535. Se todas as portas de umamáquinaestiverem ocupadas, não é possível se conectar a ela enquanto nenhuma for liberada.

Ao con�gurar um servidor para rodar na porta 80 (padrão http), é possível se conectar a esse servidor atra-

vés dessa porta que, junto com o ip, vai formar o endereço da aplicação. Por exemplo, o servidor web da

caelum.com.br pode ser representado por: caelum.com.br:80

19.4 Socket

Mas se um cliente se conecta a um programa rodando na porta 80 de um servidor, enquanto ele não se

desconectar dessa porta, será impossível que outra pessoa se conecte?

Acontece que, ao efetuar e aceitar a conexão, o servidor redireciona o cliente de uma porta para outra, libe-

rando novamente sua porta inicial e permitindo que outros clientes se conectem novamente.

Em Java, isso deve ser feito através de threads e o processo de aceitar a conexão deve ser rodado omais rápido

possível.

19.5 Servidor

Iniciando ummodelo de servidor de chat, o serviço do computador que funciona como base deve, primeiro,

abrir uma porta e �car ouvindo até alguém tentar se conectar.

1 import java.net.*;2

3 public class Servidor {4 public static void main(String args[]) throws IOException {5

6 ServerSocket servidor = new ServerSocket(12345);

Capítulo 19 - Apêndice - Sockets - Socket - Página 255

Material do Treinamento Java e Orientação a Objetos

7 System.out.println("Porta 12345 aberta!");8 // a continuação do servidor deve ser escrita aqui9

10 }11 }

Se o objeto for realmente criado, signi�ca que a porta 12345 estava fechada e foi aberta. Se outro programa

possui o controle desta porta neste instante, é normal que o nosso exemplo não funcione, pois ele não con-

segue utilizar uma porta que já está em uso.

Após abrir a porta, precisamos esperar por um cliente através do método accept da ServerSocket. Assimque um cliente se conectar, o programa continuará, por isso dizemos que esse método é blocante, segura athread até que algo o noti�que.

Socket cliente = servidor.accept();System.out.println("Nova conexão com o cliente " +

cliente.getInetAddress().getHostAddress()); // imprime o ip do cliente

Por �m, basta ler todas as informações que o cliente nos enviar:

Scanner scanner = new Scanner(cliente.getInputStream());

while (scanner.hasNextLine()) {System.out.println(scanner.nextLine());

}

Fechamos as conexões, começando pelo �uxo:

in.close();cliente.close();servidor.close();

O resultado é a classe a seguir:

1 public class Servidor {2 public static void main(String[] args) throws IOException {3 ServerSocket servidor = new ServerSocket(12345);4 System.out.println("Porta 12345 aberta!");5

6 Socket cliente = servidor.accept();7 System.out.println("Nova conexão com o cliente " +8 cliente.getInetAddress().getHostAddress()9 );

Capítulo 19 - Apêndice - Sockets - Servidor - Página 256

Material do Treinamento Java e Orientação a Objetos

10

11 Scanner s = new Scanner(cliente.getInputStream());12 while (s.hasNextLine()) {13 System.out.println(s.nextLine());14 }15

16 s.close();17 servidor.close();18 cliente.close();19 }20 }

19.6 Cliente

A nossa tarefa é criar um programa cliente que envie mensagens para o servidor... o cliente é ainda mais

simples do que o servidor.

O código a seguir é a parte principal e tenta se conectar a um servidor no IP 127.0.0.1 (máquina local) e porta

12345:

Socket cliente = new Socket("127.0.0.1",12345);System.out.println("O cliente se conectou ao servidor!");

Queremos ler os dados do cliente, da entrada padrão (teclado):

Scanner teclado = new Scanner(System.in);while (teclado.hasNextLine()) {

// lê a linha e faz algo com ela}

Basta ler as linhas que o usuário digitar através do bu�er de entrada (in), e jogá-las no bu�er de saída:

PrintStream saida = new PrintStream(cliente.getOutputStream());Scanner teclado = new Scanner(System.in);while (teclado.hasNextLine()) {

saida.println(teclado.nextLine());}saida.close();teclado.close();

Repare que usamos os conceito de java.io aqui novamente, para leitura do teclado e envio de mensagenspara o servidor. Para as classes Scanner e PrintStream, tanto faz de onde que se lê ou escreve os dados: o im-portante é que esse stream seja um InputStream / OutputStream. É o poder das interfaces, do polimor�smo,aparecendo novamente.

Capítulo 19 - Apêndice - Sockets - Cliente - Página 257

Material do Treinamento Java e Orientação a Objetos

Nosso programa �nal:

1 public class Cliente {2 public static void main(String[] args)3 throws UnknownHostException, IOException {4 Socket cliente = new Socket("127.0.0.1", 12345);5 System.out.println("O cliente se conectou ao servidor!");6

7 Scanner teclado = new Scanner(System.in);8 PrintStream saida = new PrintStream(cliente.getOutputStream());9

10 while (teclado.hasNextLine()) {11 saida.println(teclado.nextLine());12 }13

14 saida.close();15 teclado.close();16 cliente.close();17 }18 }

Para testar o sistema, precisamos rodar primeiro o servidor e, logo depois, o cliente. Tudo o que for digitado

no cliente será enviado para o servidor.

Capítulo 19 - Apêndice - Sockets - Cliente - Página 258

Material do Treinamento Java e Orientação a Objetos

Multithreading

Para que o servidor seja capaz de trabalhar com dois clientes ao mesmo tempo é necessário criar

uma thread logo após executar o método accept.

A thread criada será responsável pelo tratamento dessa conexão, enquanto o laço do servidor

disponibilizará a porta para uma nova conexão:

while (true) {

Socket cliente = servidor.accept();

// cria um objeto que vai tratar a conexãoTratamentoClass tratamento = new TratamentoClass(cliente);

// cria a thread em cima deste objetoThread t = new Thread(tratamento);

// inicia a threadt.start();

}

19.7 Imagem geral

A socket do cliente tem um InputStream, que recebe do OutputStream do servidor, e tem um OutputStream,que transfere tudo para o InputStream do servidor. Muito parecido com um telefone!

Repare que cliente e servidor são rótulos que indicam um estado. Um micro (ou melhor, uma JVM) pode

Capítulo 19 - Apêndice - Sockets - Imagem geral - Página 259

Material do Treinamento Java e Orientação a Objetos

ser servidor num caso, mas pode ser cliente em outro caso.

19.8 Exercícios: Sockets

1) Crie um projeto sockets.

Vamos fazer umpequeno sistema emque tudo que é digitado nomicro cliente acaba aparecendo nomicro

servidor. Isto é, apenas uma comunicação unidirecional.

Crie a classe Servidor como vimos nesse capítulo. Abuse dos recursos do Eclipse para não ter de escrevermuito!

1 package br.com.caelum.chat;2

3 import java.io.IOException;4 import java.net.ServerSocket;5 import java.net.Socket;6 import java.util.Scanner;7

8 public class Servidor {9 public static void main(String[] args) throws IOException {10 ServerSocket servidor = new ServerSocket(12345);11 System.out.println("Porta 12345 aberta!");12

13 Socket cliente = servidor.accept();14 System.out.println("Nova conexão com o cliente " +15 cliente.getInetAddress().getHostAddress());16

17 Scanner entrada = new Scanner(cliente.getInputStream());18 while (entrada.hasNextLine()) {19 System.out.println(entrada.nextLine());20 }21

22 entrada.close();23 servidor.close();24 }25 }

2) Crie a classe Cliente como vista anteriormente:

1 package br.com.caelum.chat;2

3 import java.io.IOException;4 import java.io.PrintStream;5 import java.net.Socket;6 import java.net.UnknownHostException;

Capítulo 19 - Apêndice - Sockets - Exercícios: Sockets - Página 260

Material do Treinamento Java e Orientação a Objetos

7 import java.util.Scanner;8

9 public class Cliente {10 public static void main(String[] args)11 throws UnknownHostException, IOException {12 Socket cliente = new Socket("127.0.0.1", 12345);13 System.out.println("O cliente se conectou ao servidor!");14

15 Scanner teclado = new Scanner(System.in);16 PrintStream saida = new PrintStream(cliente.getOutputStream());17

18 while (teclado.hasNextLine()) {19 saida.println(teclado.nextLine());20 }21

22 saida.close();23 teclado.close();24 }25 }

Utilize dos quick �xes e control espaço para os imports e o throws.

3) Rode a classe Servidor: repare no console do Eclipse que o programa �ca esperando. Rode a classeCliente: a conexão deve ser feita e o Eclipse deve mostrar os dois consoles para você (existe um pequenoícone na view de Console para você alternar entre eles).

Digite mensagens no cliente e veja se elas aparecem corretamente no servidor.

4) Teste seu programa com um colega do curso, usando comunicação remota entre as duas máquinas.

Combinem entre si quem vai rodar o cliente e quem vai rodar o servidor. Quem for rodar o cliente deve

editar o IP na classe para indicar o endereço da outra máquina (veri�que também se estão acessando a

mesma porta).

Descobrindo o ip da máquina

No Windows, abra o console e digite ipcon�g para saber qual é o seu IP. No Linux (ou no BSD,Mac, Solaris), vá no console e digite ifcon�g.

5) (opcional) E se você quisesse, em vez de enviar tudo o que o cliente digitou, transferir um arquivo texto

do micro do cliente para servidor? Seria difícil?

Abuse do polimor�smo! Faça o cliente ler de um arquivo chamado arquivo.txt (crie-o!) e faça com queo servidor grave tudo que recebe num arquivo que chama recebido.txt.

Capítulo 19 - Apêndice - Sockets - Exercícios: Sockets - Página 261

Material do Treinamento Java e Orientação a Objetos

19.9 Desafio: Múltiplos Clientes

Quando o servidor aceita um cliente com a chamada ao accept, ele poderia chamar novamente este métodopara aceitar um novo cliente. E, se queremos aceitar vários clientes, simultâneos, basta chamar o acceptvárias vezes e tratar cada cliente em sua própria Thread (senão o método accept não será invocado nova-mente!).

Um esboço de solução para a classe Servidor:

ServerSocket servidor = new ServerSocket(12345);

// servidor fica eternamente aceitando clientes...while (true) {

Socket cliente = servidor.accept();// dispara uma Thread que trata esse cliente e já espera o próximo

}

19.10 Desafio: broadcast das mensagens

Agora que vários clientes podem mandar mensagens, gostaríamos que os clientes recebessem as mensagens

enviadas pelas outras pessoas. Ao invés do servidor simplesmente escrever asmensagens no console, ele deve

mandar cada mensagem para todos os clientes conectados.

Precisamos manter uma lista de clientes conectados e, quando chegar uma mensagem (de qualquer cliente),

percorremos essa lista e mandamos para todos.

Use um List para guardar os PrintStreams dos clientes. Logo depois que o servidor aceitar um cliente novo,crie um PrintStream usando o OutputStream dele e adicione na lista. E, quando receber uma mensagemnova, envia para todos na lista.

Um esboço:

Adicionando na lista:

while (true) {Socket cliente = servidor.accept();this.lista.add(new PrintStream(cliente.getOutputStream()));

// dispara uma Thread que trata esse cliente e já espera o próximo}

Método que distribui as mensagens:

void distribuiMensagem(String msg) {for (PrintStream cliente : lista) {

Capítulo 19 - Apêndice - Sockets - Desa�o: Múltiplos Clientes - Página 262

Material do Treinamento Java e Orientação a Objetos

cliente.println(msg);}

}

Mas nosso cliente também recebe mensagens. Então precisamos fazer com que o Cliente, além de ler men-

sagens do teclado e enviar para o servidor, simultaneamente também possa receber mensagens de outros

clientes enviadas pelo servidor.

Ou seja, precisamos de uma segunda �read na classe Cliente que �ca recebendo mensagens doInputStream do servidor e imprimindo no console.

Um esboço:

Scanner servidor = new Scanner(cliente.getInputStream());while (servidor.hasNextLine()) {

System.out.println(servidor.nextLine());}

Lembre que você precisará de no mínimo 2 threads para o cliente e 2 para o servidor. Então provavelmente

você vai ter que escrever 4 classes.

Melhorias possíveis:

• Faça com o a primeira linha enviada pelo cliente seja sempre o nick dele. E quando o servidor enviar

a mensagem, faça ele enviar o nick de cada cliente antes da mensagem.

• E quando um cliente desconectar? Como retirá-lo da lista?

• É difícil fazer o envio de arquivos pelo nosso sistema de chats? Sabendo que a leitura de um arquivo é

feita pelo FileInputStream, seria difícil mandar esse InputStream pelo OutputStream da conexão derede?

19.11 Solução do sistema de chat

Uma solução para o sistema de chat cliente-servidor commúltiplos clientes proposto nos desa�os acima. Re-

pare que a solução não está nem um pouco elegante: o main já faz tudo, além de não tratarmos as exceptions.O código visa apenas mostrar o uso de uma API. É uma péssima prática colocar toda a funcionalidade do

seu programa no main e também de jogar exceções para trás.

Nesta listagem, faltam os devidos imports.

Primeiro, as duas classes para o cliente. Repare que a única mudança grande é a classe nova, Recebedor:

1 public class Cliente {2 public static void main(String[] args)

Capítulo 19 - Apêndice - Sockets - Solução do sistema de chat - Página 263

Material do Treinamento Java e Orientação a Objetos

3 throws UnknownHostException, IOException {4 // dispara cliente5 new Cliente("127.0.0.1", 12345).executa();6 }7

8 private String host;9 private int porta;10

11 public Cliente (String host, int porta) {12 this.host = host;13 this.porta = porta;14 }15

16 public void executa() throws UnknownHostException, IOException {17 Socket cliente = new Socket(this.host, this.porta);18 System.out.println("O cliente se conectou ao servidor!");19

20 // thread para receber mensagens do servidor21 Recebedor r = new Recebedor(cliente.getInputStream());22 new Thread(r).start();23

24 // lê msgs do teclado e manda pro servidor25 Scanner teclado = new Scanner(System.in);26 PrintStream saida = new PrintStream(cliente.getOutputStream());27 while (teclado.hasNextLine()) {28 saida.println(teclado.nextLine());29 }30

31 saida.close();32 teclado.close();33 cliente.close();34 }35 }

1 public class Recebedor implements Runnable {2

3 private InputStream servidor;4

5 public Recebedor(InputStream servidor) {6 this.servidor = servidor;7 }8

9 public void run() {10 // recebe msgs do servidor e imprime na tela11 Scanner s = new Scanner(this.servidor);

Capítulo 19 - Apêndice - Sockets - Solução do sistema de chat - Página 264

Material do Treinamento Java e Orientação a Objetos

12 while (s.hasNextLine()) {13 System.out.println(s.nextLine());14 }15 }16 }

Já o Servidor sofreu bastante modi�cações. A classe TrataCliente é a responsável por cuidar de cada clienteconectado no sistema:

1 public class Servidor {2

3 public static void main(String[] args) throws IOException {4 // inicia o servidor5 new Servidor(12345).executa();6 }7

8 private int porta;9 private List<PrintStream> clientes;10

11 public Servidor (int porta) {12 this.porta = porta;13 this.clientes = new ArrayList<PrintStream>();14 }15

16 public void executa () throws IOException {17 ServerSocket servidor = new ServerSocket(this.porta);18 System.out.println("Porta 12345 aberta!");19

20 while (true) {21 // aceita um cliente22 Socket cliente = servidor.accept();23 System.out.println("Nova conexão com o cliente " +24 cliente.getInetAddress().getHostAddress()25 );26

27 // adiciona saida do cliente à lista28 PrintStream ps = new PrintStream(cliente.getOutputStream());29 this.clientes.add(ps);30

31 // cria tratador de cliente numa nova thread32 TrataCliente tc =33 new TrataCliente(cliente.getInputStream(), this);34 new Thread(tc).start();35 }36

Capítulo 19 - Apêndice - Sockets - Solução do sistema de chat - Página 265

Material do Treinamento Java e Orientação a Objetos

37 }38

39 public void distribuiMensagem(String msg) {40 // envia msg para todo mundo41 for (PrintStream cliente : this.clientes) {42 cliente.println(msg);43 }44 }45 }

1 public class TrataCliente implements Runnable {2

3 private InputStream cliente;4 private Servidor servidor;5

6 public TrataCliente(InputStream cliente, Servidor servidor) {7 this.cliente = cliente;8 this.servidor = servidor;9 }10

11 public void run() {12 // quando chegar uma msg, distribui pra todos13 Scanner s = new Scanner(this.cliente);14 while (s.hasNextLine()) {15 servidor.distribuiMensagem(s.nextLine());16 }17 s.close();18 }19 }

Capítulo 19 - Apêndice - Sockets - Solução do sistema de chat - Página 266

Capítulo 20

Apêndice - Instalação do Java

“Quem pouco pensa, engana-se muito.”– Leonardo da Vinci

Como vimos antes, a VM é apenas uma especi�cação e devemos baixar uma implementação. Há muitas

empresas que implementam uma VM, como a própria Oracle, a IBM, a Apache e outros.

A da Oracle é a mais usada e possui versões para Windows, Linux e Solaris. Você pode baixar o SDK aces-

sando:

http://www.oracle.com/technetwork/java/

Nesta página da Oracle, você deve escolher o Java SE, dentro dos top downloads. Depois, escolha o JDK e

seu sistema operacional.

20.1 Instalando noUbuntu e em outros Linux

Cada distribuição Linux tem sua própria forma de instalação. Algumas já trazem o Java junto, outras possi-

bilitam que você instale pelos repositórios o�ciais e em alguns casos você precisa baixar direto da Oracle e

con�gurar tudo manualmente.

No Ubuntu, a distribuição usada na Caelum, a instalação é bastante simples. Basta ir no terminal e digitar:

sudo add-apt-repository ppa:webupd8team/javasudo apt-get updatesudo apt-get install oracle-java7-installer

Caso pre�ra utilizar o openjdk, a distribuição opensource, basta fazer

Material do Treinamento Java e Orientação a Objetos

sudo apt-get install openjdk-7-jdk

No linux fedora, você faria com su -c "yum install java-1.7.0-openjdk".

Se você já tiver outras versões instaladas no seuUbuntu, pode utilizar sudo update-alternatives --configjava para escolher entre elas.

Uma instalação mais braçal, sem usar repositório , pode ser feita baixando o instalador no próprio site da

Oracle. É um tar.gz que possui um .bin que deve ser executado. Depois, é necessário apontar JAVA_HOMEpara esse diretório e adicionar JAVA_HOME/bin no seu PATH.

20.2 NoMacOS X

OMacOS X já traz o Java instalado junto com o sistema operacional até a versão 10.6. As versõesmais novas,

do Lion em diante, o instalador do Mac vai perguntar se você deseja baixá-lo quando for rodar sua primeira

aplicação Java, como o Eclipse.

A versão para o Java 7 ainda não está o�cialmente disponível. Você pode baixá-la em: http://jdk7.java.net/

macportpreview/

Vai ser preciso trocar a versão padrão do Java após a instalação, indo no painel de Preferences, e depois Java

Preferences.

20.3 Instalação do JDK em ambienteWindows

Para instalar o JDK no Windows, primeiro baixe-o no site da Oracle. É um simples arquivo executável que

contém oWizard de instalação:

http://www.oracle.com/technetwork/java/

Capítulo 20 - Apêndice - Instalação do Java - No Mac OS X - Página 268

Material do Treinamento Java e Orientação a Objetos

Instalação

1) Dê um clique duplo no arquivo jdk-<versão>-windows-i586-p.exe e espere até ele entrar no wizard deinstalação.

2) Aceite os próximos dois passos clicando em Next. Após um tempo, o instalador pedirá para escolherem que diretório instalar o SDK. Pode ser onde ele já oferece como padrão. Anote qual foi o diretório

escolhido, vamos utilizar esse caminho mais adiante. A cópia de arquivos iniciará:

3) O instalador instalará também o JavaFX 2. Após isso, você será direcionado à uma página onde você

pode, opcionalmente, criar uma conta na Oracle para registrar sua instalação.

Configurando o ambiente

Precisamos con�gurar algumas variáveis de ambiente após a instalação, para que o compilador seja acessível

via linha de comando. Caso você vá utilizar diretamente o Eclipse, provavelmente não será necessário realizar

esses passos.

1) Clique com o botão direito em cima do ícone Computador e selecione a opção Propriedades.

Capítulo 20 - Apêndice - Instalação do Java - Instalação do JDK em ambiente Windows - Página 269

Material do Treinamento Java e Orientação a Objetos

2) Escolha a aba “Con�gurações Avançadas de Sistema” e depois clique no botão “Variáveis de Ambiente”

3) Nesta tela, você verá, na parte de cima, as variáveis de ambiente do usuário corrente e, embaixo, as variá-

veis de ambiente do computador (servem para todos os usuários). Clique no botão Novo... da parte debaixo.

4) Em Nome da Variável digite JAVA_HOME e, em valor da variável, digite o caminho que você utilizou nainstalação do Java. Provavelmente será algo como: C:\Program Files\Java\jdk1.7.0_03:

Clique em Ok.

Capítulo 20 - Apêndice - Instalação do Java - Instalação do JDK em ambiente Windows - Página 270

Material do Treinamento Java e Orientação a Objetos

5) Não vamos criar outra variável, mas sim alterar. Para isso, procure a variável PATH, ou Path (dá nomesmo), e clique no botão de baixo “Editar”.

6) Não altere o nome da variável! Deixe como está e adicione no �nal do valor ;%JAVA_HOME%\bin, nãoesqueça do ponto-e-vírgula - assim, você está adicionando mais um caminho à sua variável Path.

7) Abra o prompt, indo em Iniciar, Executar e digite cmd.

8) No console, digite javac -version. O comando deve mostrar a versão do Java Compiler e algumas op-ções.

Você pode seguir para a instalação do Eclipse, conforme visto no seu capítulo, ou utilizar um editor de texto

simples como o bloco de notas para os primeiros capítulos de apostila.

Qualquer dúvida, não hesite de postá-la no Grupo de Usuários Java, em www.guj.com.br.

Capítulo 20 - Apêndice - Instalação do Java - Instalação do JDK em ambiente Windows - Página 271

Capítulo 21

Apêndice - Debugging

“Olho por olho, e o mundo acabará cego."–Mohandas Gandhi

21.1 O que é debugar

Debugging (em português, depuração ou depurar) é um processo de reduzir ou encontrar bugs no seu sis-

tema. De uma forma geral, debugging não é uma tarefa fácil de ser executada. Muitas variações podem

atrapalhar esse processo, por exemplo, a linguagem que estamos utilizando e ferramentas disponíveis para

fazermos debugging de um código.

O Java em si facilitamuito neste processo, pois nos fornecemaneiras de sabermos se o código está errado, por

exemplo as exceptions. Em linguagens de baixo nível saber onde o bug estava era extremamente complicado.

O que também facilita nosso trabalho são as ferramentas de debug. Veremos que elas são necessárias nos

casos que nossos testes de unidade de logging não foram su�cientes para encontrar a razão de um problema.

21.2 Debugando no Eclipse

No curso utilizamos o Eclipse como IDE para desenvolvermos nosso código. Como foi dito ferramentas

de debugging facilitam muito nosso trabalho, o Eclipse é uma das IDEs mais poderosas do mercado e nos

fornece uma ferramenta que torna o processo extremamente simples.

O primeiro recurso que temos que conhecer quando começamos a debugar no Eclipse são os breakpoints.Eles são pontos de partida em nosso código para iniciarmos o processo de debug. Por exemplo, no código

abaixo, imagine que desejamos debugar o comportamento do método saca da classe Conta, mais especi�ca-mente do if que veri�ca se saldo é menor que o valor a ser sacado. Colocaríamos o breakpoint exatamentena linha if (this.saldo < valor) {:

Material do Treinamento Java e Orientação a Objetos

public class Conta {

private double saldo;

public boolean saca(double valor) {if (this.saldo < valor) {

return false;} else {

this.saldo = this.saldo - valor;return true;

}}

}

Mas como faço isso? Muito simples, basta clicar na linha que deseja adicionar o breakpoint, depois clicar no

menu Run -> Toogle Breakpoint.

Esse é o tipo mais clássico de breakpoint, veremos alguns outros ao longo do capítulo.

Agora que já adicionamos o breakpoint que é o ponto de partida, vamos debugar nosso código. Precisamos

rodar nosso código, ou seja, chamar o método saca para que o breakpoint seja encontrado. Teremos umcódigo similar ao seguinte:

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

Capítulo 21 - Apêndice - Debugging - Debugando no Eclipse - Página 273

Material do Treinamento Java e Orientação a Objetos

Conta conta = new Conta();conta.saca(200);

}}

O processo normal para executarmos esse código seria clicar no menu Run -> Run As -> Java Application.Porém para rodar o nosso código em modo debug e ativar nosso breakpoint, devemos rodar o codigo nomenu Run -> Debug As -> Java Application. Quando um breakpoint for encontrado no código que estásendo executado, o eclipse exibirá uma perspectiva especí�ca de debug, apontando para a linha que tem o

breakpoint.

21.3 Perspectiva de debug

Temos várias informações disponíveis nessa perspectiva, algumas são essenciais e básicas para trabalharmos

com debug no nosso dia-a-dia, outras não tão relevantes e só usamos em casos muito especí�cos.

Dentro da perspectiva de debug, temos uma aba chamada Variables. São exibidas todas as variáveis en-contradas dentro do código que você está debugando. Por exemplo, no debug que �zemos serão exibidas as

variáveis do método saca, neste caso, valor. Além dos atributos de instância do objeto.

Capítulo 21 - Apêndice - Debugging - Perspectiva de debug - Página 274

Material do Treinamento Java e Orientação a Objetos

Podemos exibir mais informações sobre as variáveis, basta adicionarmos as colunas que desejamos na tabela

exibida.

É possível também adicionarmos constantes e variáveis estáticas da classe que está sendo debugada.

Capítulo 21 - Apêndice - Debugging - Perspectiva de debug - Página 275

Material do Treinamento Java e Orientação a Objetos

Na aba Breakpoints são exibidos todos os breakpoints que seu workspace possui. Mas por que isso é impor-tante? É importante porque podemos ver todos os pontos de debug presentes e melhor, podemos desabilitá-

los um a um ou todos de uma só vez. Você pode até mesmo pedir para exportar os breakpoints.

Para desabilitar ou habilitar todos breakpoints basta clicarmos no ícone Skip All Breakpoints. Se quisermosdesabilitar um a um, basta desmarcar o checkbox e o breakpoint será desativado. Às vezes, encontrar o código

onde o breakpoint foi colocado pode ser complicado, na aba Breakpoints isso �ca bem fácil de fazer, bastadar um duplo clique no breakpoint e o eclipse automaticamente nos mostra a classe “dona” dele.

Quando estamos debugando código, muitas vezes é interessante saber o valor de alguma expressão ou mé-

todo. Por exemplo, uma condição dentro de um if, this.saldo > valor. Esse valor não está em uma variá-vel, ele está em uma expressão, o que pode tornar saber o valor dela complicado. A feature de Expressionsdescomplica esse processo para nós. Na perspectiva de Debug temos a aba Expressions. Basta clicar com odireito dentro da aba, e clicar em Add Expression:

E o resultado da expressão é exibido.

Temos outra aba importante chamada de Debug. Dentre as funções dela estão:

• �reads - Exibe as threads que estão sendo executadas, e melhor, mostra qual thread efetuou a cha-mada para o método onde está o debug. Além disso mostra a pilha de execução, o que nos permite

voltar a chamada de um método

• Barra de navegação - Que permite alterarmos os caminhos que o debug seguirá.

Capítulo 21 - Apêndice - Debugging - Perspectiva de debug - Página 276

Material do Treinamento Java e Orientação a Objetos

A lista a seguir mostrar algumas teclas e botões que alteram o caminho natural dos nosss debug:

• F5 - Vai para o próximo passo do seu programa. Se o próximo passo for um método, ele entrará nocódigo associado;

• F6 - Também vai para o próximo passo, porém se o próximo passo for ummétodo, ele não entrará nocódigo associado;

• F7 - Voltará e mostrará ométodo que fez a chamada para o código que está sendo debugado. No nossocaso voltará para o método main da classe TestaConta;

• F8 - Vai para o próximo breakpoint, se nenhum for encontrado, o programa seguirá seu �uxo de exe-cução normal.

Você também pode usar os botões que estão presentes na aba Debug.

21.4 Debug avançado

Depois que colocamos um breakpoint em algum ponto do nosso código, podemos colocar algumas proprie-

dades nele, por exemplo, usar alguma condição para restringir quando o breakpoint será ativado em tempo

de execução. Podemos restringir na propriedadeHit Count que o breakpoint só será ativado quando a linhaem que ele encontra-se for executada ‘X’ vezes.

Capítulo 21 - Apêndice - Debugging - Debug avançado - Página 277

Material do Treinamento Java e Orientação a Objetos

Como na imagem acima o breakpoint só será ativado quando a linha de código em que ele se encontra for

executada ‘2’ vezes. Podemos também colocar alguma expressão condicional, um if, por exemplo.

Capítulo 21 - Apêndice - Debugging - Debug avançado - Página 278

Material do Treinamento Java e Orientação a Objetos

O breakpoint, neste caso, somente será ativado quando o argumento valor que foi passado ao método sacafor maior que 100. O importante aqui é notarmos que devemos retornar sempre um valor booleano, se não o�zermos, teremos um erro em tempo de execução. Essa propriedade é válida quando queremos colocar aque-

les famosos System.out.println("entrou no if tal") para efeito de log, podemos fazer isso colocando olog dentro da expressão condicional nas propriedades do breakpoint.

O display é uma das partes mais interessantes do debug do eclipse, ele provê uma maneira de executarmos

qualquer código que quisermos quando estamos em debugging. Criar uma classe, instanciar objetos dessa

classe, utilizar if ’s, for’s, while’s, todos os recursos do Java, além de poder utilizar as variáveis, métodos,

constantes da classe que estamos debugando.

Um exemplo clássico é quando estamos em debugging e queremos saber o retorno de algum método do

qual não temos acesso, o que faríamos antes seria colocar um amontoado de System.out.println, poluindoextremamente nosso código. No display o que fazemos é efetuar a chamada desse código e automaticamente

os resultados são exibidos.

Para vermos um efeito real disso, vamos alterar um pouco o comportamento da classe Conta, de modo que

agora o saldo para saque tenha que ser o saldo real mais o valor do limite. Nosso código �ca assim:

public class Conta {

private double saldoReal;private double limite;

Capítulo 21 - Apêndice - Debugging - Debug avançado - Página 279

Material do Treinamento Java e Orientação a Objetos

public Conta(double limite) {this.limite = limite;

}

public boolean saca(double valor) {if (!isSaldoSuficiente(valor)) {

return false;} else {

this.saldoReal = this.saldoReal - valor;return true;

}}

private boolean isSaldoSuficiente(double valor) {return (this.saldoReal + this.limite) > valor;

}}

Repare que o if que veri�ca se o saldo é su�ciente para efetuarmos o saque chama um método

isSaldoSuficiente, o que pode ser um problema quando estamos debugando, a�nal a condição do if éum método. Se utilizarmos o display podemos fazer a chamada do método isSaldoSuficiente, ver seuresultado e o melhor, não afetamos o debug, apenas queremos ver o resultado do método, por exemplo.

Para exibirmos a aba Display é bem simples. Tecle Ctrl + 3, digite Display e a aba será exibida. Quandorodarmos nosso código em modo debug, podemos ir no display, digitarmos uma chamada para o método

isSaldoSuficiente, executamos esse código que foi digitado selecionando-o dentro do display e teclandoCtrl + Shi� + D e o resultado será impresso, assim como na imagem abaixo:

Muitas vezes queremos “seguir” alguma variável de instância, ou seja, qualquer chamada para essa variável

(leitura ou escrita) queremos ser noti�cados disso. Podemos usar o watchpoint, que fará nosso programa

entrar em modo debug, quando qualquer alteração na variável que estamos seguindo ocorrer, o programa

entrará em debug exatamente na linha que fez a alteração. Para colocarmos um watchpoint, basta dar um

duplo clique no atributo de instância que deseja colocá-lo.

Capítulo 21 - Apêndice - Debugging - Debug avançado - Página 280

Material do Treinamento Java e Orientação a Objetos

É possível alterar esse comportamento padrão, e de�nir se você quer que o watchpoint seja ativado para

leitura ou somente para escrita.

A idéia desse tipo de breakpoint é fazer nosso programa entrar em debug quando alguma exceção especí�ca

ocorrer. Quando de�nirmos essa exceção no Exception Breakpoint e a mesma ocorrer, automaticamentenosso programa entra em debug na linha que gerou aquela exceção. Por exemplo, vamos alterar o codigo da

classe TestaConta para que a mesma tenha uma NullPointerException:

Capítulo 21 - Apêndice - Debugging - Debug avançado - Página 281

Material do Treinamento Java e Orientação a Objetos

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

Conta conta = null;conta.saca(10);

}}

Quando rodarmos o código acima, teremos uma NullPointerException. Pode ser útil nesses casos de-bugar e saber onde a exceção está ocorrendo de fato, em qual linha mais especi�camente. Para fazer-

mos isso podemos criar um Exception Breakpoint, que debugará códigos que eventualmente lancem uma

NullPointerException, por exemplo. Basta abrirmos a aba Breakpoints e clicarmos no ícone abaixo:

Será aberta uma janela onde podemos buscar por uma exceção especí�ca.

Podemos de�nir um breakpoint que é ativado ou antes ou depois que o método é chamado. Para de�nirmos

ele, basta estar em qualquer parte dométodo que desejamos debugar, clicar nomenuRun -> ToogleMethodBreakpoint. Podemos editar as propriedades desse breakpoint dizendo se queremos que ele seja ativadoantes(default) ou depois da execução do método. Basta acessar as propriedades do method breakpoint e

alterá-las.

Capítulo 21 - Apêndice - Debugging - Debug avançado - Página 282

Material do Treinamento Java e Orientação a Objetos

É util quando desejamos que um breakpoint seja ativado quando uma classe especí�ca for carregada pela

primeira vez, chamamos esse breakpoint de Class Breakpoint. Basta clicarmos no menu Run -> Add ClassLoad Breakpoint, uma janela será aberta e basta digitarmos o nome da classe e adicionarmos:

Capítulo 21 - Apêndice - Debugging - Debug avançado - Página 283

Material do Treinamento Java e Orientação a Objetos

21.5 Profiling

Um dos principais hábitos que nós desenvolvedores devemos evitar é a questão da otimização prematura, ou

seja, quando desenvolvemos uma aplicação para um cliente, devemos nos preocupar em atender o requisitosfuncionais de maneira mais rápida e mais simples possível. O passo seguinte é refatorar seu código paraque ele seja melhorado e para que no futuro possa se adaptar as possíveis mudanças.

A regra é: “Deixe os problemas do futuro, para serem resolvidos no futuro”.

Uma das ferramentas que nos auxiliam na questão de não otimizar nosso código prematuramente, são as

ferramentas de pro�ling, que tornam aparentes, por exemplo, os problemas de memória e cpu, que podem

fazer com que otimizemos nosso código. Atualmente devido as técnicas que utilizamos para entregar algo

de valor para o cliente, focamos principalmente na qualidade, aspectos funcionais, testes, etc. Porém, muitos

problemas que não fazem parte dos requisitos funcionais podem acontecer apenas quando a aplicação está

em produção, neste ponto as ferramentas de pro�ling também nos ajudam.

21.6 Profiling no Eclipse TPTP

Juntamente com o Eclipse temos a opção de instalar e utilizar uma ferramenta de pro�ling conhecida como

Eclipse TPTP (Eclipse Test & Performance Tools Platform), que nos fornece opções para isolar e identi�car

problemas de performance, tais como: memória (memory leak), recursos e processamento. O TPTP nos

permite analisar de simples aplicações java até aplicações que rodam emmúltiplas máquinas e em múltiplas

plataformas.

Capítulo 21 - Apêndice - Debugging - Pro�ling - Página 284

Material do Treinamento Java e Orientação a Objetos

Alternativas ao TPTP

Existem algumas alternativas ao TPTP, os mais conhecidos são Netbeans Pro�ler (http://pro�ler.

netbeans.org/) que é gratuito, e o JPro�ler (http://www.ej-technologies.com/products/jpro�ler/

overview.html) que é pago.

O TPTP não vem por padrão junto com o Eclipse. Portanto, para utilizarmos é necessário a instalação do

mesmo. Podemos fazer o processo de instalação de duas maneiras. A primeira e mais fácil é utilizando o

Update Site do Eclipse que resolve as possíveis dependências e nos possibilita escolher quais features que-

remos instalar. Para instalar o TPTP através desse recurso, basta ir no menu: Help -> Install New So�ware,uma janela será aberta, basta clicar em Add... e preenchê-la conforme a imagem a seguir:

Basta adicionar as ferramentas do TPTP em nosso eclipse, para isto, selecione o repositório que acabamos

de adicionar e a versão do TPTP que queremos instalar, neste caso, a versão 4.6.2.

Capítulo 21 - Apêndice - Debugging - Pro�ling no Eclipse TPTP - Página 285

Material do Treinamento Java e Orientação a Objetos

Instalando pelo Zip

Você tem a opção de instalar o TPTP baixando o zip do projeto e colocando manualmente no

diretório de instalação do seu eclipse. Mais informações no link: http://www.eclipse.org/tptp/

home/downloads/4.6.0/documents/installguide/InstallGuide46.html

Um problema que pode acontecer em aplicações e que muitas pessoas não conhecem a fundo, é a questão

do pool de Strings que pode eventualmente �car muito grande. Este problema pode ser causado porque

objetos do tipo String são imutáveis, sendo assim, se �zermos concatenações de Strings muitas vezes, cada

uma dessas concatenações produzirá uma nova String, que automaticamente será colocada no pool da JVM.

A alternativa neste caso, seria trabalhar com objetos do tipo StringBuilder ou StringBu�er que funcionam

como Strings, mas que não produzem Strings novas em caso de uma concatenação. Mas como medir o

tamanho do nosso pool de String?

O TPTP possui uma aba de estatísticas que nos mostra o tempo que um método levou para ser executado,

quanto processamento esse método gastou, quanto de memória foi gasto com cada método. Vamos analisar

Capítulo 21 - Apêndice - Debugging - Pro�ling no Eclipse TPTP - Página 286

Material do Treinamento Java e Orientação a Objetos

algumas dessas estatísticas criando um código que concatene várias Strings, de maneira que sobrecarregue

o pool, gere bastante processamento e consumo de memória.

public class Teste {

public static void main(String[] args) {for (int i = 0; i < 1000000; i++) {

String x = "a" + i;System.out.println(x);

}}

}

Para analisarmos o resultado do código, vamos rodar o código do main através do menu Run -> Pro�le As ->Java Application.

Versões

Infelizmente o TPTP funciona somente no Windows. Versões para MacOS e Linux são prome-

tidas, mas até hoje estão em desenvolvimento. Uma alternativa paga para esses outros sistemas

operacionais é o JPro�ler.

Capítulo 21 - Apêndice - Debugging - Pro�ling no Eclipse TPTP - Página 287

Índice Remissivo

abstract, 117

ANT, 170

argumento, 38

ARQUIVOS, 198

ARRAY, 58

atomicidade, 244

ATRIBUIÇÃO, 19

Atributo, 36

AUTOBOXING, 188

boolean, 18

BREAK, 27

Breakpoint de classe, 283

Breakpoint de Método, 282

Breakpoints, 272, 276

bytecode, 6

CASTING, 21

CASTING DE REFERÊNCIAS, 183

CHAR, 19

CLASSE, 35

classe abstrata, 117

Collections, 211

Começando o debug, 273

COMPARABLE, 218

COMPARE TO, 190

COMPOSIÇÃO, 94

CONDIÇÃO BOOLEANA, 24

CONSTRUTOR, 75

CONTINUE, 27

CONTRATO, 128

CTRL+ESPAÇO, 167

Debug, 276

Decorator Pattern, 200

Display, 279

DOUBLE, 18

Eclipse, 99

ELSE, 24

ENCAPSULAR, 71

ENTRADA E SAÍDA, 198

EQUALS, 185

ESCOPO, 27

EXCEPTION, 143

Exception Breakpoint, 281

Expressions, 276

FILEINPUTSTREAM, 198

�nalizer, 242

FINALLY, 157

FOR, 25

FULLY QUALIFIED NAME, 163

Garbage Collector, 241

GETTERS, 73

GUJ, 4

HASHMAP, 230

HASHTABLE, 230

HERANÇA, EXTENDS, 85

IF, 23

IMPLEMENTS, 129

IMPORT, 164

INPUTSTREAM, 198

INPUTSTREAMREADER, 199

Instalando, 285

int, 16

INTERFACE, 129

INVOCAÇÃO DEMÉTODO, 38

ITERATOR, 227

JAVA.IO, 198

JAVA.LANG, 180

java.lang.Object.�nalize, 242

java.lang.System.gc, 242

java.util.concurrent, 245

JAVADOC, 173

juc, 245

LAÇO, 25

288

Material do Treinamento Java e Orientação a Objetos

MÁQUINA VIRTUAL, 6

MÉTODO, 37

método abstrato, 118

MAIN, 12

MAP, 225

MATH, 192

MATRIZ, 58

MODIFICADOR DE ACESSO, 69

new, 36

NULL, 47

OBJECT, 182

OPERADOR DE NEGAÇÃO, 24

OPERADORES ARITMÉTICOS, 17

OPERADORES LÓGICOS, 24

Oracle, 4

ORIENTAÇÃO A OBJETOS, 32

PACKAGE, 162

PACOTES, 161

parâmetro, 38

plataforma java, 4

POLIMORFISMO, 90

PORTA, 255

PRIVATE, 69

Propriedades de Breakpoint, 277

PROTECTED, 87

PUBLIC, 70

REESCRITA, 88

REESCRITA DE MÉTODO, 88

REFERÊNCIA, 41

região crítica, 244

RETURN, 40

SERVERSOCKET, 256

SET, 223

SETTERS, 73

SOBRECARGA, 126

SOCKETS, 198

SPLIT, 189

STACKTRACE, 144

STATIC, 79

Sun, 4

Super e sub classes, 86

SYSTEM.EXIT, 181

TCP, 253

Testando, 286

this, 38

THROWS, 149

TOSTRING, 184

TREEMAP, 230

VALORES DEFAULT, 46

Variáveis, 274

variáveis, 16

void, 38

Watch Point, 280

WHILE, 25

WRAPPING, 188

Índice Remissivo - Índice Remissivo - Página 289