Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
EstaapostiladaCaelumvisaensinardeumamaneiraelegante,mostrandoapenasoqueénecessárioequandoénecessário,nomomentocerto,poupandoo leitordeassuntosquenãocostumamserde seuinteresseemdeterminadasfasesdoaprendizado.
ACaelumesperaquevocêaproveiteessematerial.Todososcomentários,críticasesugestõesserãomuitobem-vindos.
EssaapostilaéconstantementeatualizadaedisponibilizadanositedaCaelum.Sempreconsulteositeparanovasversõese,aoinvésdeanexaroPDFparaenviaraumamigo,indiqueositeparaqueelepossasemprebaixarasúltimasversões.Vocêpodeconferirocódigodeversãodaapostilalogono naldoíndice.
Baixesempreaversãomaisnovaem:www.caelum.com.br/apostilas
Esse material é parte integrante do treinamento Java e Orientação a Objetos e distribuídogratuitamente exclusivamente pelo site da Caelum. Todos os direitos são reservados à Caelum. Adistribuição, cópia, revenda e utilização paraministrar treinamentos são absolutamente vedadas. Parausocomercialdestematerial,porfavor,consulteaCaelumpreviamente.
SOBREESTAAPOSTILA
1
4
19
Sumário
1ComoAprenderJava1.1Oqueérealmenteimportante? 1
1.2Sobreosexercícios 2
1.3Tirandodúvidaseindoalém 2
2OqueéJava2.1Java 4
2.2UmabrevehistóriadoJava 5
2.3MáquinaVirtual 6
2.4Javalento?HotspoteJIT 8
2.5VersõesdoJavaeaconfusãodoJava2 9
2.6JVM?JRE?JDK?Oquedevobaixar? 9
2.7OndeusareosobjetivosdoJava 10
2.8Especificaçãoversusimplementação 11
2.9ComooFJ-11estáorganizado 11
2.10Compilandooprimeiroprograma 12
2.11Executandoseuprimeiroprograma 14
2.12Oqueaconteceu? 14
2.13Parasabermais:comoéobytecode? 15
2.14Exercícios:ModificandooHelloWorld 16
2.15Oquepodedarerrado? 16
2.16Umpoucomais... 17
2.17Exercíciosopcionais 18
3VariáveisprimitivaseControledefluxo3.1Declarandoeusandovariáveis 19
3.2Tiposprimitivosevalores 22
3.3Exercícios:Variáveisetiposprimitivos 22
3.4Discussãoemaula:convençõesdecódigoecódigolegível 23
3.5Castingepromoção 24
SumárioCaelum
35
60
76
3.6Oifeoelse 26
3.7OWhile 28
3.8OFor 28
3.9Controlandoloops 29
3.10Escopodasvariáveis 30
3.11Umblocodentrodooutro 32
3.12Parasabermais 32
3.13Exercícios:Fixaçãodesintaxe 32
3.14Desafios:Fibonacci 34
4Orientaçãoaobjetosbásica4.1Motivação:problemasdoparadigmaprocedural 35
4.2Criandoumtipo 37
4.3UmaclasseemJava 39
4.4Criandoeusandoumobjeto 39
4.5Métodos 41
4.6Métodoscomretorno 42
4.7Objetossãoacessadosporreferências 44
4.8Ométodotransfere() 47
4.9Continuandocomatributos 49
4.10Parasabermais:UmaFábricadeCarros 51
4.11Umpoucomais... 53
4.12Exercícios:OrientaçãoaObjetos 53
4.13Desafios 58
4.14Fixandooconhecimento 58
5Modificadoresdeacessoeatributosdeclasse5.1Controlandooacesso 60
5.2Encapsulamento 63
5.3GetterseSetters 65
5.4Construtores 68
5.5Anecessidadedeumconstrutor 69
5.6Atributosdeclasse 71
5.7Umpoucomais... 73
5.8Exercícios:Encapsulamento,construtoresestatic 73
5.9Desafios 75
6EclipseIDE6.1OEclipse 76
CaelumSumário
92
101
122
138
6.2ApresentandooEclipse 77
6.3ViewsePerspective 78
6.4Criandoumprojetonovo 80
6.5Criandoomain 84
6.6Executandoomain 86
6.7Pequenostruques 87
6.8Exercícios:Eclipse 88
6.9Discussãoemaula:Refactoring 91
7Pacotes-Organizandosuasclassesebibliotecas7.1Organização 92
7.2Diretórios 93
7.3Import 94
7.4Acessoaosatributos,construtoresemétodos 96
7.5UsandooEclipsecompacotes 97
7.6Exercícios:Pacotes 99
8Ferramentas:jarejavadoc8.1Arquivos,bibliotecaseversões 101
8.2GerandooJARpeloEclipse 103
8.3Javadoc 105
8.4GerandooJavadoc 106
8.5Exercícios:JareJavadoc 109
8.6Importandoumjarexterno 110
8.7Exercícios:Importandoumjar 110
8.8Manipulandoacontapelainterfacegráfica 112
8.9Exercícios:Mostrandoosdadosdacontanatela 119
9Herança,reescritaepolimorfismo9.1Repetindocódigo? 122
9.2Reescritademétodo 126
9.3Invocandoométodoreescrito 127
9.4Polimorfismo 128
9.5Umoutroexemplo 130
9.6Umpoucomais... 132
9.7Exercícios:HerançaePolimorfismo 132
9.8Discussõesemaula:Alternativasaoatributoprotected 137
10ClassesAbstratas10.1Repetindomaiscódigo? 138
SumárioCaelum
147
163
183
10.2Classeabstrata 139
10.3Métodosabstratos 141
10.4Aumentandooexemplo 142
10.5Parasabermais... 145
10.6Exercícios:ClassesAbstratas 145
11Interfaces11.1Aumentandonossoexemplo 147
11.2Interfaces 151
11.3Dificuldadenoaprendizadodeinterfaces 155
11.4Exemplointeressante:conexõescomobancodedados 156
11.5Exercícios:Interfaces 157
11.6Exercíciosopcionais 160
11.7Discussão:favoreçacomposiçãoemrelaçãoàherança 161
12Exceçõesecontroledeerros12.1Motivação 163
12.2Exercícioparacomeçarcomosconceitos 165
12.3ExceçõesdeRuntimemaiscomuns 169
12.4Outrotipodeexceção:CheckedExceptions 170
12.5UmpoucodagrandefamíliaThrowable 173
12.6Maisdeumerro 174
12.7Lançandoexceções 174
12.8Oquecolocardentrodotry? 176
12.9Criandoseuprópriotipodeexceção 177
12.10Parasabermais:finally 178
12.11Exercícios:Exceções 179
12.12Desafios 181
12.13Discussãoemaula:catchethrowsemException 181
13Opacotejava.lang13.1Pacotejava.lang 183
13.2UmpoucosobreaclasseSystem 183
13.3java.lang.Object 184
13.4Métodosdojava.lang.Object:equalsetoString 185
13.5Exercícios:java.lang.Object 189
13.6java.lang.String 190
13.7Exercícios:java.lang.String 193
13.8Desafio 194
CaelumSumário
196
206
236
13.9Discussãoemaula:OquevocêprecisafazeremJava? 194
14Umpoucodearrays14.1Oproblema 196
14.2Arraysdereferências 197
14.3Percorrendoumaarray 198
14.4PercorrendoumaarraynoJava5.0 199
14.5Exercícios:Arrays 200
14.6Umpoucomais... 203
14.7DesafiosOpcionais 205
15Collectionsframework15.1Arrayssãotrabalhosos,utilizarestruturadedados 206
15.2Listas:java.util.List 207
15.3ListasnoJava5eJava7comGenerics 211
15.4Aimportânciadasinterfacesnascoleções 212
15.5Ordenação:Collections.sort 213
15.6Exercícios:Ordenação 216
15.7Conjunto:java.util.Set 218
15.8Principaisinterfaces:java.util.Collection 220
15.9PercorrendocoleçõesnoJava5 221
15.10Parasabermais:Iterandosobrecoleçõescomjava.util.Iterator 222
15.11Mapas-java.util.Map 224
15.12Parasabermais:Properties 226
15.13Parasabermais:EqualseHashCode 227
15.14Parasabermais:Boaspráticas 228
15.15Exercícios:Collections 228
15.16Desafios 232
15.17Parasabermais:Comparators,classesanônimas,Java8eolambda 233
16Pacotejava.io16.1ConhecendoumaAPI 236
16.2Orientaçãoaobjetosnojava.io 237
16.3InputStream,InputStreamReadereBufferedReader 237
16.4LendoStringsdoteclado 239
16.5Aanalogiaparaaescrita:OutputStream 241
16.6Umamaneiramaisfácil:ScannerePrintStream 242
16.7Umpoucomais... 243
16.8Integereclasseswrappers(box) 244
SumárioCaelum
251
254
263
276
283
16.9AutoboxingnoJava5.0 245
16.10Parasabermais:java.lang.Math 245
16.11Exercícios:JavaI/O 246
16.12Discussãoemaula:DesignPatternseoTemplateMethod 248
17Eagora?17.1Web 251
17.2PraticandoJavaeusandobibliotecas 251
17.3GruposdeUsuários 252
17.4Próximoscursos 252
18Apêndice-ProgramaçãoConcorrenteeThreads18.1Threads 254
18.2Escalonadoretrocasdecontexto 257
18.3GarbageCollector 258
18.4Exercícios 260
18.5Easclassesanônimas? 261
19Apêndice-Sockets19.1Motivação:umaAPIqueusaosconceitosaprendidos 263
19.2Protocolo 263
19.3Porta 264
19.4Socket 265
19.5Servidor 266
19.6Cliente 267
19.7Imagemgeral 268
19.8Exercícios:Sockets 269
19.9Desafio:MúltiplosClientes 271
19.10Desafio:broadcastdasmensagens 271
19.11Soluçãodosistemadechat 273
20Apêndice-Problemascomconcorrência20.1Threadsacessandodadoscompartilhados 276
20.2Controlandooacessoconcorrente 278
20.3VectoreHashtable 280
20.4Umpoucomais... 280
20.5Exercíciosavançadosdeprogramaçãoconcorrenteelocks 280
21Apêndice-InstalaçãodoJava21.1InstalandonoUbuntueemoutrosLinux 283
21.2NoMacOSX 284
CaelumSumário
289
21.3InstalaçãodoJDKemambienteWindows 284
22Apêndice-Debugging22.1Oqueédebugar 289
22.2DebugandonoEclipse 289
22.3Perspectivadedebug 291
22.4Debugavançado 294
22.5Profiling 300
22.6ProfilingnoEclipseTPTP 301
Versão:24.8.4
SumárioCaelum
CAPÍTULO1
"Buscouminstantefelizquejustifiqueminhaexistência"--FiodórDostoiévski
Muitoslivros,aopassardoscapítulos,mencionamtodososdetalhesdalinguagemjuntamentecomseus princípios básicos. Isso acaba criando muita confusão, em especial porque o estudante nãoconseguedistinguirexatamenteoqueéprimordial aprenderno início,daquiloquepodeserestudadomaisadiante.
Seumaclasseabstratadeveounãoteraomenosummétodoabstrato,seoifsóaceitaargumentosbooleanosetodososdetalhessobreclassesinternas,realmentenãodevemsetornarpreocupaçõesparaaquelecujoobjetivoprimárioéaprenderJava.Essetipodeinformaçãoseráadquiridacomotempo,enãoénecessárionoinício.
Nestecurso,separamosessasinformaçõesemquadrosespeciais,jáquesãoinformaçõesextras.Ouentão, apenas citamos num exercício e deixamos para o leitor procurar informações se for de seuinteresse.
Porfim,faltamencionaralgosobreaprática,quedeveser tratadaseriamente: todososexercíciossãomuito importantes e os desafios podem ser feitos quando o curso terminar.De qualquermaneirarecomendamosaosalunosestudarememcasa,epraticarembastantecódigoevariações.
OCURSO
ParaaquelesqueestãofazendoocursoJavaeOrientaçãoaObjetos,recomendamosestudarememcasaaquiloquefoivistoduranteaaula,tentandoresolverosexercíciosopcionaiseosdesafiosapresentados.
COMOAPRENDERJAVA
1.1OQUEÉREALMENTEIMPORTANTE?
1COMOAPRENDERJAVA 1
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
Os exercícios do curso variam de práticos até pesquisas na Internet, ou mesmo consultas sobreassuntosavançadosemdeterminadostópicosparaincitaracuriosidadedoaprendiznatecnologia.
Existemtambém,emdeterminadoscapítulos,umasériededesafios.Elesfocammaisnoproblemacomputacionalquenalinguagem,porémsãoumaexcelenteformadetreinarasintaxee,principalmente,familiarizar o aluno coma biblioteca padrão Java, alémde proporcionar umganhona velocidade dedesenvolvimento.
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 pordesenvolvedoresdaCaelum,ehojecontacommaisdeummilhãodemensagens.
Foraisso,sinta-seàvontadeparaentraremcontatocomseuinstrutorparatirartodasasdúvidasquesurgiremduranteocurso.
Seoquevocêestábuscandosãolivrosdeapoio,sugerimosconheceraeditoraCasadoCódigo:
http://www.casadocodigo.com.br
ACaelum fornecemuitosoutros cursos Java, comdestaqueparaoFJ-21que traz a aplicaçãodoJavanaweb.
http://www.caelum.com.br/
Há tambémcursos online que vão te ajudar a ir além, commuita interação comos instrutores, a
JáconheceoscursosonlineAlura?
1.2SOBREOSEXERCÍCIOS
1.3TIRANDODÚVIDASEINDOALÉM
2 1.2SOBREOSEXERCÍCIOS
CAPÍTULO2
"Computadoressãoinúteis,elesapenasdãorespostas"--Picasso
ChegouahoraderesponderasperguntasmaisbásicassobreJava.Aotérminodessecapítulo,vocêserácapazde:
responderoqueéJava;mostrarasvantagensedesvantagensdoJava;entenderbemoconceitodemáquinavirtual;compilareexecutarumprogramasimples.
Entender um pouco da história da plataforma Java é essencial para enxergar os motivos que alevaramaosucesso.
Quaiseramosseusmaioresproblemasquandoprogramavanadécadade1990?
ponteiros?gerenciamentodememória?organização?faltadebibliotecas?terdereescreverpartedocódigoaomudardesistemaoperacional?custofinanceirodeusaratecnologia?
AlinguagemJavaresolvebemessesproblemas,queatéentãoapareciamcomfrequêncianasoutraslinguagens. Alguns desses problemas foram particularmente atacados porque uma das grandesmotivações para a criação da plataforma Java era de que essa linguagem fosse usada em pequenosdispositivos,comotvs,videocassetes,aspiradores, liquidificadoreseoutros.Apesardissoa linguagemteve seu lançamento focado no uso em clientes web (browsers) para rodar pequenas aplicações(applets).Hoje em dia esse não é o grandemercado do Java: apesar de ter sido idealizado comumpropósitoelançadocomoutro,oJavaganhoudestaquenoladodoservidor.
O Java foi criado pela antiga Sun Microsystems 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,voltadoaoconsumidordeprodutoseusuáriosleigos,nãodesenvolvedores.ComacompradaSunpelaOracle em 2009,muitasURLs e nomes tem sido trocados para refletir amarca daOracle.A páginaprincipaldoJavaé:http://www.oracle.com/technetwork/java/
No Brasil, diversos grupos de usuários se formaram para tentar disseminar o conhecimento da
OQUEÉJAVA
2.1JAVA
4 2OQUEÉJAVA
linguagem.UmdeleséoGUJ(http://www.guj.com.br),umacomunidadevirtualcomartigos,tutoriaisefórumpara tirardúvidas,omaioremlínguaportuguesacommaisdecemmilusuáriose1milhãodemensagens.
Encorajamostodososalunosausarmuitoosfórunsdomesmo,poiséumadasmelhoresmaneirasparaacharsoluçõesparapequenosproblemasqueacontecemcomgrandefrequência.
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
ASuncriouum time (conhecidocomoGreenTeam)paradesenvolver inovações tecnológicasem1992.EssetimefoilideradoporJamesGosling,consideradoopaidoJava.Otimevoltoucomaideiadecriaruminterpretador(jáeraumamáquinavirtual,veremosoqueéissomaisafrente)parapequenosdispositivos,facilitandoareescritadesoftwareparaaparelhoseletrônicos,comovídeocassete,televisãoeaparelhosdeTVacabo.
A ideianãodeucerto.Tentaramfechardiversoscontratoscomgrandes fabricantesdeeletrônicos,comoPanasonic,masnãohouveêxitodevidoaoconflitode interessesecustos.Hoje,sabemosqueoJava domina o mercado de aplicações para celulares com mais de 2.5 bilhões de dispositivoscompatíveis,porémem1994aindaeramuitocedoparaisso.
Com o advento da web, a Sun percebeu que poderia utilizar a ideia criada em 1992 para rodarpequenasaplicaçõesdentrodobrowser.Asemelhançaeraquenainternethaviaumagrandequantidadede sistemasoperacionais ebrowsers, e com isso seriagrandevantagempoderprogramarnumaúnicalinguagem, independente da plataforma. Foi aí que o Java 1.0 foi lançado: focado em transformar obrowserdeapenasumclientemagro(thinclientouterminalburro)emumaaplicaçãoquepossatambémrealizaroperaçõesavançadas,enãoapenasrenderizarhtml.
OsappletsdeixaramdeserofocodaSun,enemaOraclenuncateveinteresse.Écuriosonotarquea
JáconheceoscursosonlineAlura?
2.2UMABREVEHISTÓRIADOJAVA
2.2UMABREVEHISTÓRIADOJAVA 5
tecnologia Java nasceu com um objetivo em mente, foi lançado com outro, mas, no final, decoloumesmonodesenvolvimentodeaplicaçõesdoladodoservidor.Sorte?HáhojeoJavaFX,tentandodarforçaparaoJavanãosónodesktopmascomoaplicaçõesricasnaweb,masmuitosnãoacreditamquehajaespaçoparatal,considerandoodestinodetecnologiascomoAdobeFlexeMicrosoftSilverlight.
VocêpodelerahistóriadalinguagemJavaem:http://www.java.com/en/javahistory/
Eumvídeointeressante:http://tinyurl.com/histjava
Em2009aOraclecomprouaSun, fortalecendoamarca.AOracle sempre foi, juntocoma IBM,umadasempresasquemaisinvestiramefizeramnegóciosatravésdousodaplataformaJava.Em2014surgeaversãoJava8commudançasinteressantesnalinguagem.
Em uma linguagem de programação como C e Pascal, temos a seguinte situação quando vamoscompilarumprograma:
O código fonte é compilado para código de máquina específico de uma plataforma e sistemaoperacional.Muitasvezesoprópriocódigofonteédesenvolvidovisandoumaúnicaplataforma!
Esse código executável (binário) resultante será executado pelo sistema operacional e, por essemotivo,eledevesaberconversarcomosistemaoperacionalemquestão.
Istoé, temosumcódigoexecutávelparacadasistemaoperacional.ÉnecessáriocompilarumavezparaWindows,outraparaoLinux,eassimpordiante,casoagentequeiraqueessenossosoftwarepossaserutilizadoemváriasplataformas.EsseéocasodeaplicativoscomooOpenOffice,Firefoxeoutros.
2.3MÁQUINAVIRTUAL
6 2.3MÁQUINAVIRTUAL
Como foi dito anteriormente, namaioria das vezes, a sua aplicação se utiliza das bibliotecas dosistemaoperacional,como,porexemplo,adeinterfacegráficaparadesenharas"telas".AbibliotecadeinterfacegráficadoWindowsébemdiferentedasdoLinux:comocriarentãoumaaplicaçãoquerodedeformaparecidanosdoissistemasoperacionais?
Precisamosreescreverummesmopedaçodaaplicaçãoparadiferentessistemasoperacionais,jáqueelesnãosãocompatíveis.
Já o Java utiliza do conceito demáquina virtual, onde existe, entre o sistema operacional e aaplicação, uma camada extra responsável por "traduzir" -mas não apenas isso - o que sua aplicaçãodesejafazerparaasrespectivaschamadasdosistemaoperacionalondeelaestárodandonomomento:
Dessaforma,amaneiracomaqualvocêabreumajanelanoLinuxounoWindowséamesma:vocêganhaindependênciadesistemaoperacional.Ou,melhorainda,independênciadeplataformaemgeral:nãoéprecisosepreocuparemqualsistemaoperacionalsuaaplicaçãoestárodando,nememquetipodemáquina,configurações,etc.
Reparequeumamáquinavirtualéumconceitobemmaisamploqueodeuminterpretador.Comoopróprio nome diz, uma máquina virtual é como um "computador de mentira": tem tudo que umcomputador tem. Em outras palavras, ela é responsável por gerenciar memória, threads, a pilha deexecução,etc.
Sua aplicação roda sem nenhum envolvimento com o sistema operacional! Sempre conversandoapenascomaJavaVirtualMachine(JVM).
Essacaracterísticaéinteressante:comotudopassapelaJVM,elapodetirarmétricas,decidirondeémelhoralocaramemória,entreoutros.UmaJVMisolatotalmenteaaplicaçãodosistemaoperacional.SeumaJVMterminaabruptamente,sóasaplicaçõesqueestavamrodandonelairãoterminar:issonãoafetaráoutrasJVMsqueestejamrodandonomesmocomputador,nemafetaráosistemaoperacional.
Essacamadadeisolamentotambéméinteressantequandopensamosemumservidorquenãopodesesujeitararodarcódigoquepossainterferirnaboaexecuçãodeoutrasaplicações.
2.3MÁQUINAVIRTUAL 7
Essa camada, a máquina virtual, não entende código java, ela entende um código de máquinaespecífico.Essecódigodemáquinaégeradoporumcompiladorjava,comoojavac,eéconhecidopor"bytecode",poisexistemmenosde256códigosdeoperaçãodessa linguagem,ecada"opcode"gastaumbyte.OcompiladorJavageraessebytecodeque,diferentedaslinguagenssemmáquinavirtual,vaiservirparadiferentessistemasoperacionais,jáqueelevaiser"traduzido"pelaJVM.
WRITEONCE,RUNANYWHERE
EsseeraumsloganqueaSunusavaparaoJava,jáquevocênãoprecisareescreverpartesdasuaaplicaçãotodavezquequisermudardesistemaoperacional.
HotspotéatecnologiaqueaJVMutilizaparadetectarpontosquentesdasuaaplicação:códigoqueéexecutadomuito,provavelmentedentrodeumoumaisloops.QuandoaJVMjulgarnecessário,elavaicompilar estes códigos para instruções realmente nativas da plataforma, tendo emvista que isso vaiprovavelmente melhorar a performance da sua aplicação. Esse compilador é o JIT: Just inTimeCompiler,ocompiladorqueaparece"bemnahora"quevocêprecisa.
Você pode pensar então: porque a JVM não compila tudo antes de executar a aplicação? É queteoricamentecompilardinamicamente,amedidadonecessário,podegerarumaperformancemelhor.Omotivoésimples:imagineum.exegeradopeloVisualBasic,pelogccoupeloDelphi;eleéestático.Elejáfoiotimizadobaseadoemheurísticas,ocompiladorpodetertomadoumadecisãonãotãoboa.
Já a JVM, por estar compilando dinamicamente durante a execução, pode perceber que umdeterminadocódigonãoestácomperformanceadequadaeotimizarmaisumpoucoaquele trecho,ouaindamudaraestratégiadeotimização.ÉporessemotivoqueasJVMsmaisrecentesemalgunscasoschegamaganhardecódigosCcompiladoscomoGCC3.x.
2.4JAVALENTO?HOTSPOTEJIT
8 2.4JAVALENTO?HOTSPOTEJIT
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoJavaeOrientaçãoaObjetos
Java1.0e1.1sãoasversõesmuitoantigasdoJava,masjátraziambibliotecasimportantescomooJDBCeojava.io.
Com o Java 1.2 houve um aumento grande no tamanho da API, e foi nesse momento em quetrocaramanomenclatura de Javapara Java2, comoobjetivodediminuir a confusãoquehavia entreJavaeJavascript.Maslembre-se,nãoháversão"Java2.0",o2foiincorporadoaonome,tornando-seJava21.2.
DepoisvieramoJava21.3e1.4,eoJava1.5passouasechamarJava5,tantoporumaquestãodemarketingeporquemudançassignificativasnalinguagemforamincluídas.Énessemomentoqueo"2"donomeJavadesaparece.Reparequeparafinsdedesenvolvimento,oJava5aindaéreferidocomoJava1.5.
HojeaúltimaversãodisponíveldoJavaéa8.
OquegostaríamosdebaixarnositedaOracle?
JVM=apenasavirtualmachine,essedownloadnãoexiste,elasemprevemacompanhada.JRE=JavaRuntimeEnvironment,ambientedeexecuçãoJava,formadopelaJVMebibliotecas,tudoquevocêprecisaparaexecutarumaaplicaçãoJava.Masnósprecisamosdemais.JDK=JavaDevelopmentKit:Nós,desenvolvedores, faremosodownloaddo JDKdo JavaSE(StandardEdition).EleéformadopelaJREsomadoaferramentas,comoocompilador.
Tanto o JRE e o JDK podem ser baixados do site http://www.oracle.com/technetwork/java/.Paraencontrá-los,acesseolinkJavaSEdentrodostopdownloads.ConsulteoapêndicedeinstalaçãodoJDK
VocêpodetambémfazerocursodatadessaapostilanaCaelum
2.5VERSÕESDOJAVAEACONFUSÃODOJAVA2
2.6JVM?JRE?JDK?OQUEDEVOBAIXAR?
2.5VERSÕESDOJAVAEACONFUSÃODOJAVA2 9
paramaioresdetalhes.
Nodecorrerdocurso,vocêpodeacharqueoJavatemmenorprodutividadequandocomparadacomalinguagemquevocêestáacostumado.
ÉprecisoficarclaroqueapremissadoJavanãoéadecriarsistemaspequenos,ondetemosumoudoisdesenvolvedores,maisrapidamentequelinguagenscomophp,perl,eoutras.
Ofocodaplataformaéoutro:aplicaçõesdemédioagrandeporte,ondeotimededesenvolvedorestemváriaspessoasesemprepodeviramudarecrescer.NãotenhadúvidasquecriaraprimeiraversãodeumaaplicaçãousandoJava,mesmoutilizando IDEse ferramentaspoderosas, serámais trabalhosoquemuitaslinguagensscriptoudealtaprodutividade.Porém,comumalinguagemorientadaaobjetosemaduracomooJava,seráextremamentemaisfácilerápidofazeralteraçõesnosistema,desdequevocêsigaasboaspráticaserecomendaçõessobredesignorientadoaobjetos.
Alémdisso, a quantidade enormedebibliotecas gratuitas para realizar osmais diversos trabalhos(taiscomo relatórios,gráficos, sistemasdebusca,geraçãodecódigodebarra,manipulaçãodeXML,tocadores de vídeo, manipuladores de texto, persistência transparente, impressão, etc) é um pontofortíssimopara adoçãodo Java:vocêpode criarumaaplicação sofisticada, usandodiversos recursos,sem precisar comprar um componente específico, que costuma ser caro. O ecossistema do Java éenorme.
Cadalinguagemtemseuespaçoeseumelhoruso.OusodoJavaéinteressanteemaplicaçõesquevirãoacrescer,emquealegibilidadedocódigoéimportante,ondetemosmuitaconectividadeesehámuitas plataformas (ambientes e sistemas operacionais) heterogêneas (Linux,Unix,OSX eWindowsmisturados).
VocêpodeverissopelaquantidadeenormedeofertasdeempregoprocurandodesenvolvedoresJavaparatrabalharcomsistemaswebeaplicaçõesdeintegraçãonoservidor.
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 (emespecialMicrosoft.NET).AatualtentativaéoJavaFX,ondeaOracleteminvestidobastante.
2.7ONDEUSAREOSOBJETIVOSDOJAVA
10 2.7ONDEUSAREOSOBJETIVOSDOJAVA
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Outro ponto importante: quando falamos de Java Virtual Machine, estamos falando de umaespecificação.EladizcomoobytecodedeveserinterpretadopelaJVM.Quandofazemosodownloadno site da Oracle, o que vem junto é a Oracle JVM. Em outras palavras, existem outras JVMsdisponíveis,comoaJRockitdaBEA(tambémadquiridapelaOracle),aJ9daIBM,entreoutras.
Esseéoutropontointeressanteparaasempresas.CasonãoestejamgostandodealgumdetalhedaJVMdaOracleouprefiram trabalhar comoutra empresa,pagandopor suporte, elaspodem trocardeJVMcomagarantiaabsolutadequetodoosistemacontinuaráfuncionando.IssoporquetodaJVMdeveser certificada pela Oracle, provando a sua compatibilidade. Não há nem necessidade de recompilarnenhumadesuasclasses.
Além de independência de hardware e sistema operacional, você tem a independência de vendor(fabricante):graçasaideiadaJVMserumaespecificaçãoenãoumsoftware.
Javaéumalinguagemsimples:existempoucasregras,muitobemdefinidas.
Porém quebrar o paradigma procedural para mergulhar na orientação a objetos não é simples.QuebraroparadigmaeganharfluênciacomalinguagemeAPIsãoosobjetivosdoFJ-11.
Ocomeçopodeserumpoucofrustrante:exemplossimples,controlede fluxocomoif,for,
whileecriaçãodepequenosprogramasquenemaomenoscaptamdadosdoteclado.Apesardeisso
tudosernecessário,ésónos20%finaisdocursoqueutilizaremosbibliotecaspara,nofinal,criarmosum chat entre duas máquinas que transferem Strings por TCP/IP. Neste ponto, teremos tudo que énecessárioparaentendercompletamentecomoaAPIfunciona,quemestendequem,eoporquê.
Seuslivrosdetecnologiaparecemdoséculopassado?
2.8ESPECIFICAÇÃOVERSUSIMPLEMENTAÇÃO
2.9COMOOFJ-11ESTÁORGANIZADO
2.8ESPECIFICAÇÃOVERSUSIMPLEMENTAÇÃO 11
Depois desse capítulo no qual o Java, a JVM e primeiros conceitos são passados, veremos oscomandosbásicosdojavaparacontroledefluxoeutilizaçãodevariáveisdotipoprimitivo.Criaremosclassespara testaressepequenoaprendizado,semsaberexatamenteoqueéumaclasse.Issodificultaaindamaisacurvadeaprendizado,porémcadaconceitoseráintroduzidonomomentoconsideradomaisapropriadopelosinstrutores.
Passamos para o capítulo de orientação a objetos básico, mostrando os problemas do paradigmaprocedural e a necessidade de algo diferente para resolvê-los. Atributos, métodos, variáveis do tiporeferênciaeoutros.
Os capítulos de modificadores de acesso, herança, classes abstratas e interfaces demonstram oconceitofundamentalqueocursoquerpassar:encapsule,exponhaomínimodesuasclasses,foquenoque elas fazem, no relacionamento entre elas. Com um bom design, a codificação fica fácil e amodificaçãoeexpansãodosistematambém.
No decorrer desses capítulos, o Eclipse é introduzido de forma natural, evitando-se ao máximowizardsemenus,priorizandomostraroschamadoscodeassistsequickfixes.IssofazcomqueoEclipsetrabalhedeformasimbióticacomodesenvolvedor,semseintrometer,semfazermágica.
Pacotes,javadoc,jarsejava.langapresentamosúltimosconceitosfundamentaisdoJava,dando
todaafundaçãopara,então,passarmosaestudarasprincipaisemaisutilizadasAPIsdoJavaSE.
AsAPIsestudadasserãojava.utilejava.io.Todaselasusameabusamdosconceitosvistos
no decorrer do curso, ajudando a sedimentá-los. Juntamente, temos os conceitos básicos do uso deThreads,eosproblemaseperigosdaprogramaçãoconcorrentequandodadossãocompartilhados.
Resumindo: o objetivo do curso é apresentar o Java ao mesmo tempo que os fundamentos daorientaçãoaobjetossãointroduzidos.Bateremosmuitonopontodedizerqueoimportanteécomoasclassesserelacionamequaléopapeldecadauma,enãoemcomoelasrealizamassuasobrigações.Programevoltadoàinterface,enãoàimplementação.
Vamosparaonossoprimeirocódigo!Oprogramaqueimprimeumalinhasimples.
Paramostrarumalinha,podemosfazer:
System.out.println("MinhaprimeiraaplicaçãoJava!");
Masessecódigonãoseráaceitopelocompiladorjava.OJavaéumalinguagembastanteburocrática,eprecisademaisdoqueissoparainiciarumaexecução.Veremososdetalheseosporquêsduranteospróximoscapítulos.Omínimoqueprecisaríamosescreveréalgocomo:
classMeuPrograma{publicstaticvoidmain(String[]args){
2.10COMPILANDOOPRIMEIROPROGRAMA
12 2.10COMPILANDOOPRIMEIROPROGRAMA
System.out.println("MinhaprimeiraaplicaçãoJava!");}}
NOTAÇÃO
Todososcódigosapresentadosnaapostilaestãoformatadoscomrecursosvisuaisparaauxiliara leitura e compreensão dos mesmos. Quando for digitar os códigos no computador, trate oscódigoscomotextosimples.
Anumeraçãodaslinhasnãofazpartedocódigoenãodeveserdigitada;éapenasumrecursodidático.OJavaécasesensitive:tomecuidadocommaiúsculaseminúsculas.
Apósdigitarocódigoacima,grave-ocomoMeuPrograma.javaemalgumdiretório.Paracompilar,você deve pedir para que o compilador de Java da Oracle, chamado javac , gere o bytecode
correspondenteaoseucódigoJava.
Depoisdecompilar,obytecodefoigerado.Quandoosistemaoperacionallistarosarquivoscontidosnodiretórioatual,vocêpoderáverqueumarquivo.classfoigerado,comomesmonomedasuaclasseJava.
ASSUSTADOCOMOCÓDIGO?
ParaquemjátemumaexperiênciacomJava,esseprimeirocódigoémuitosimples.Mas,seéseu primeiro código em Java, pode ser umpouco traumatizante.Nãodeixe de ler o prefácio docurso, que deixará você mais tranquilo em relação a curva de aprendizado da linguagem,conhecendocomoocursoestáorganizado.
2.10COMPILANDOOPRIMEIROPROGRAMA 13
PRECISOSEMPREPROGRAMARUSANDOONOTEPADOUSIMILAR?
NãoénecessáriodigitarsempreseuprogramaemumsimplesaplicativocomooNotepad.Vocêpodeusarumeditorquetenhasyntaxhighlightingeoutrosbenefícios.
Mas,nocomeço,éinteressantevocêusaralgoquenãopossuaferramentas,paraquevocêpossaseacostumarcomoserrosdecompilação,sintaxeeoutros.Depoisdocapítulodepolimorfismoeherança sugerimos a utilização do Eclipse (http://www.eclipse.org), a IDE líder no mercado, egratuita.ExisteumcapítuloaparteparaousodoEclipsenestaapostila.
NoLinux,recomendamosousodogedit,kateevi.NoWindows,vocêpodeusaroNotepad++ouoTextPad.NoMac,TextMate,Sublimeoumesmoovi.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Osprocedimentosparaexecutarseuprogramasãomuitosimples.OjavacéocompiladorJava,eojavaéoresponsávelporinvocaramáquinavirtualparainterpretaroseuprograma.
Aoexecutar,podeserqueaacentuaçãoresultantesaiaerradadevidoaalgumasconfiguraçõesquedeixamosdefazer.Semproblemas.
Agoraéamelhorhoradeaprenderalgonovo
2.11EXECUTANDOSEUPRIMEIROPROGRAMA
2.12OQUEACONTECEU?
14 2.11EXECUTANDOSEUPRIMEIROPROGRAMA
classMeuPrograma{publicstaticvoidmain(String[]args){
//miolodoprogramacomeçaaqui!System.out.println("MinhaprimeiraaplicaçãoJava!!");//fimdomiolodoprograma
}}
Omiolodoprogramaéoqueseráexecutadoquandochamamosamáquinavirtual.Porenquanto,todasaslinhasanteriores,ondeháadeclaraçãodeumaclasseeadeummétodo,nãoimportamparanósnessemomento.Masdevemossaberque todaaplicaçãoJavacomeçaporumpontodeentrada,eestepontodeentradaéométodomain.
Aindanãosabemosoqueémétodo,masveremosnocapítulo4.Atélá,nãosepreocupecomessasdeclarações.Semprequeumexercícioforfeito,ocódigoquenosimportasempreestaránessemiolo.
Nocasodonossocódigo,alinhadoSystem.out.printlnfazcomqueoconteúdoentreaspasseja
colocadonatela.
OMeuPrograma.classgeradonãoélegívelporsereshumanos(nãoquesejaimpossível).Eleestá
escritonoformatoqueavirtualmachinesabeentenderequefoiespecificadoqueelaentendesse.
É como um assembly, escrito para esta máquina em específico. Podemos ler os mnemônicosutilizandoaferramentajavapqueacompanhaoJDK:
javap-cMeuPrograma
Easaída:
MeuPrograma();Code:0:aload_01:invokespecial#1;//Methodjava/lang/Object."<init>":()V4:return
publicstaticvoidmain(java.lang.String[]);Code:0:getstatic#2;//Fieldjava/lang/System.out:Ljava/io/PrintStream;3:ldc#3;//StringMinhaprimeiraaplicaçãoJava!!5:invokevirtual#4;//Methodjava/io/PrintStream.println:(Ljava/lang/String;)V8:return
}
Éocódigoacima,queaJVMsabeler.Éo"códigodemáquina",damáquinavirtual.
Um bytecode pode ser revertido para o .java original (com perda de comentários e nomes de
2.13PARASABERMAIS:COMOÉOBYTECODE?
2.13PARASABERMAIS:COMOÉOBYTECODE? 15
variáveislocais).Casoseusoftwarevávirarumprodutodeprateleira,éfundamentalusarumofuscadorno seu código, que vai embaralhar classes, métodos e um monte de outros recursos (indicamos ohttp://proguard.sf.net).
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
1. Altereseuprogramaparaimprimirumamensagemdiferente.2. AltereseuprogramaparaimprimirduaslinhasdetextousandoduaslinhasdecódigoSystem.out.3. Sabendoqueos caracteres\n representamumaquebra de linhas, imprimaduas linhas de texto
usandoumaúnicalinhadecódigoSystem.out.
Muitos erros podemocorrer nomomento que você rodar seu primeiro código.Vamos ver algunsdeles:
Código:
classX{publicstaticvoidmain(String[]args){System.out.println("Faltapontoevírgula")}}
Erro:
X.java:4:';'expected}^1error
Esseéoerrodecompilaçãomaiscomum:aqueleondeumpontoevírgulaforaesquecido.Repare
EditoraCasadoCódigocomlivrosdeumaformadiferente
2.14EXERCÍCIOS:MODIFICANDOOHELLOWORLD
2.15OQUEPODEDARERRADO?
16 2.14EXERCÍCIOS:MODIFICANDOOHELLOWORLD
queocompiladoréexplícitoemdizerquealinha4éacomproblemas.Outroserrosdecompilação
podem ocorrer se você escreveu palavras chaves (as que colocamos em negrito) em maiúsculas,esqueceudeabrirefecharas{},etc.
Duranteaexecução,outroserrospodemaparecer:
SevocêdeclararaclassecomoX,compilá-laedepoistentarusá-lacomoxminúsculo(javax),oJavateavisa:
Exceptioninthread"main"java.lang.NoClassDefFoundError:X(wrongname:x)
Setentaracessarumaclassenodiretórioouclasspatherrado,ouseonomeestivererrado,ocorreráoseguinteerro:
Exceptioninthread"main"java.lang.NoClassDefFoundError:X
SeesquecerdecolocarstaticouoargumentoString[]argsnométodomain:
Exceptioninthread"main"java.lang.NoSuchMethodError:main
Porexemplo:
classX{publicvoidmain(String[]args){System.out.println("Faltouostatic,tenteexecutar!");}}
Senãocolocarométodomaincomopublic:
Mainmethodnotpublic.
Porexemplo:
classX{staticvoidmain(String[]args){System.out.println("Faltouopublic");}}
Procureumcolega,oualgumconhecido,queestejaemumprojetoJava.DescubraporqueJavafoiescolhidocomotecnologia.OqueéimportanteparaesseprojetoeoqueacaboufazendodoJavaamelhorescolha?
2.16UMPOUCOMAIS...
2.16UMPOUCOMAIS... 17
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
1. UmarquivofonteJavadevesempreteraextensão.java,ouocompiladororejeitará.Alémdisso,
existemalgumasoutras regrasnahoradedaronomedeumarquivo Java.ExperimentegravarocódigodestecapítulocomOutroNome.javaoualgosimilar.
Compileeverifiqueonomedoarquivogerado.Comoexecutarasuaaplicação?
JáconheceoscursosonlineAlura?
2.17EXERCÍCIOSOPCIONAIS
18 2.17EXERCÍCIOSOPCIONAIS
CAPÍTULO3
"Péssimaideia,adequenãosepodemudar"--Montaigne
AprenderemosatrabalharcomosseguintesrecursosdalinguagemJava:
declaração,atribuiçãodevalores,castingecomparaçãodevariáveis;controledefluxoatravésdeifeelse;
instruçõesdelaçoforewhile,controledefluxocombreakecontinue.
Dentrodeumbloco,podemosdeclararvariáveiseusá-las.EmJava,todavariáveltemumtipoquenãopodesermudado,umavezquedeclarado:
tipoDaVariavelnomeDaVariavel;
Porexemplo,épossívelterumaidadequeguardaumnúmerointeiro:
intidade;
Comisso,vocêdeclaraavariávelidade,quepassaaexistirapartirdaquelalinha.Elaédotipo
int,queguardaumnúmerointeiro.Apartirdaí,vocêpodeusá-la,primeiramenteatribuindovalores.
Alinhaaseguiréatraduçãode:"idadedevevalerquinze".
idade=15;
VARIÁVEISPRIMITIVASECONTROLEDEFLUXO
3.1DECLARANDOEUSANDOVARIÁVEIS
3VARIÁVEISPRIMITIVASECONTROLEDEFLUXO 19
COMENTÁRIOSEMJAVA
Parafazerumcomentárioemjava,vocêpodeusaro//paracomentaratéofinaldalinha,ou
entãousaro/**/paracomentaroqueestiverentreeles.
/*comentáriodaqui,ateaqui*/
//umalinhadecomentáriosobreaidadeintidade;
Além de atribuir, você pode utilizar esse valor. O código a seguir declara novamente a variável idade com valor 15 e imprime seu valor na saída padrão através da chamada a
System.out.println.
//declaraaidadeintidade;idade=15;
//imprimeaidadeSystem.out.println(idade);
Por fim, podemos utilizar o valor de uma variável para algum outro propósito, como alterar oudefinirumasegundavariável.OcódigoaseguircriaumavariávelchamadaidadeNoAnoQueVem com
valordeidademaisum.
//calculaaidadenoanoseguinteintidadeNoAnoQueVem;idadeNoAnoQueVem=idade+1;
Nomesmomomentoquevocêdeclaraumavariável,tambémépossívelinicializá-laporpraticidade:
intidade=15;
Você pode usar os operadores +, -, / e * para operar comnúmeros, sendo eles responsáveis pelaadição, subtração, divisão e multiplicação, respectivamente. Além desses operadores básicos, há ooperador%(módulo)quenadamaiséqueorestodeumadivisãointeira.Vejaalgunsexemplos:
intquatro=2+2;inttres=5-2;
intoito=4*2;intdezesseis=64/4;
intum=5%2;//5divididopor2dá2etemresto1;//ooperador%pegaorestodadivisãointeira
20 3.1DECLARANDOEUSANDOVARIÁVEIS
COMORODARESSESCÓDIGOS?
Vocêdevecolocaressestrechosdecódigodentrodoblocomainquevimosnocapítuloanterior.Istoé, issodeve ficarnomiolodoprograma.UsebastanteSystem.out.println, dessa forma
vocêpodeveralgumresultado,casocontrário,aoexecutaraaplicação,nadaaparecerá.
Porexemplo,paraimprimiraidadeeaidadeNoAnoQueVem podemos escrever o seguinte
programadeexemplo:
classTestaIdade{
publicstaticvoidmain(String[]args){//imprimeaidadeintidade=20;System.out.println(idade);
//geraumaidadenoanoseguinteintidadeNoAnoQueVem;idadeNoAnoQueVem=idade+1;
//imprimeaidadeSystem.out.println(idadeNoAnoQueVem);}}
Representarnúmerosinteiroséfácil,mascomoguardarvaloresreais,taiscomofraçõesdenúmerosinteiroseoutros?Outrotipodevariávelmuitoutilizadoéodouble,quearmazenaumnúmerocom
pontoflutuante(equetambémpodearmazenarumnúmerointeiro).
doublepi=3.14;doublex=5*10;
O tipo boolean armazena um valor verdadeiro ou falso, e só: nada de números, palavras ouendereços,comoemalgumasoutraslinguagens.
booleanverdade=true;
trueefalse sãopalavras reservadasdoJava.Écomumqueumboolean seja determinado
através de uma expressãobooleana, isto é, um trecho de código que retorna um booleano, como oexemplo:
intidade=30;booleanmenorDeIdade=idade<18;
Otipocharguardaum,eapenasum,caractere.Essecaracteredeveestarentreaspassimples.Nãoseesqueçadessasduascaracterísticasdeumavariáveldotipochar!Porexemplo,elanãopodeguardarumcódigocomo''poisovazionãoéumcaractere!
charletra='a';
3.1DECLARANDOEUSANDOVARIÁVEIS 21
System.out.println(letra);
Variáveisdotipocharsãopoucousadasnodiaadia.VeremosmaisafrenteousodasStrings,
queusamosconstantemente,porémestasnãosãodefinidasporumtipoprimitivo.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
EssestiposdevariáveissãotiposprimitivosdoJava:ovalorqueelasguardamsãoorealconteúdodavariável.Quandovocêutilizarooperadordeatribuição=ovalorserácopiado.
inti=5;//irecebeumacópiadovalor5intj=i;//jrecebeumacópiadovalordeii=i+1;//ivira6,jcontinua5
Aqui,ificacomovalorde6.Masej?Nasegundalinha,jestávalendo5.Quandoipassaa
valer6,seráquejtambémmudadevalor?Não,poisovalordeumtipoprimitivosempreécopiado.
Apesardalinha2fazerj=i,apartirdessemomentoessasvariáveisnãotemrelaçãonenhuma:o
queacontececomuma,nãorefleteemnadacomaoutra.
OUTROSTIPOSPRIMITIVOS
Vimos aqui os tipos primitivos que mais aparecem. O Java tem outros, que são o byte,
short,longefloat.
Cada tipo possui características especiais que, para um programador avançado, podem fazermuitadiferença.
Agoraéamelhorhoradeaprenderalgonovo
3.2TIPOSPRIMITIVOSEVALORES
3.3EXERCÍCIOS:VARIÁVEISETIPOSPRIMITIVOS
22 3.2TIPOSPRIMITIVOSEVALORES
1. Na empresa onde trabalhamos, há tabelas com o quanto foi gasto em cada mês. Para fechar obalanço do primeiro trimestre, precisamos somar o gasto total. Sabendo que, em Janeiro, foramgastos 15000 reais, em Fevereiro, 23000 reais e emMarço, 17000 reais, faça um programa quecalculeeimprimaogastototalnotrimestre.Sigaessespassos:
Crie uma classe chamada BalancoTrimestral com um bloco main, como nos exemplos
anteriores;Dentrodomain(omiolodoprograma),declareumavariávelinteirachamadagastosJaneiro
einicialize-acom15000;Crie tambémas variáveisgastosFevereiro egastosMarco, inicializando-as com 23000 e
17000,respectivamente,utilizeumalinhaparacadadeclaração;
CrieumavariávelchamadagastosTrimestreeinicialize-acomasomadasoutras3variáveis:
intgastosTrimestre=gastosJaneiro+gastosFevereiro+gastosMarco;
ImprimaavariávelgastosTrimestre.
2. Adicione código (sem alterar as linhas que já existem) na classe anterior para imprimir amédiamensal de gasto, criando uma variável mediaMensal junto com uma mensagem. Para isso,
concateneaStringcomovalor,usando"Valordamédiamensal="+mediaMensal.
DiscutacomoinstrutoreseuscolegassobreconvençõesdecódigoJava.Porqueexistem?Porquesãoimportantes?
Discutatambémasvantagensdeseescrevercódigofácildelereseevitarcomentáriosemexcesso.(Dica:procureporjavacodeconventions).
3.4 DISCUSSÃO EM AULA: CONVENÇÕES DE CÓDIGO E CÓDIGOLEGÍVEL
3.4DISCUSSÃOEMAULA:CONVENÇÕESDECÓDIGOECÓDIGOLEGÍVEL 23
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Algunsvaloressãoincompatíveissevocêtentarfazerumaatribuiçãodireta.Enquantoumnúmerorealcostumaserrepresentadoemumavariáveldotipodouble,tentaratribuireleaumavariávelint
nãofuncionaporqueéumcódigoquediz:"idevevalerd",masnãosesabesed realmente é umnúmerointeiroounão.
doubled=3.1415;inti=d;//nãocompila
Omesmoocorrenoseguintetrecho:
inti=3.14;
Omaisinteressante,équenemmesmooseguintecódigocompila:
doubled=5;//ok,odoublepodeconterumnúmerointeirointi=d;//nãocompila
Apesarde5serumbomvalorparaumint,ocompiladornão temcomosaberquevalorestará
dentro desse double no momento da execução. Esse valor pode ter sido digitado pelo usuário, e
ninguémvaigarantirqueessaconversãoocorrasemperdadevalores.
Jánocasoaseguir,éocontrário:
inti=5;doubled2=i;
Ocódigoacimacompilasemproblemas,jáqueumdoublepodeguardarumnúmerocomousem
pontoflutuante.Todososinteirosrepresentadosporumavariáveldotipointpodemserguardadosem
umavariáveldouble,entãonãoexistemproblemasnocódigoacima.
Àsvezes,precisamosqueumnúmeroquebradosejaarredondadoearmazenadonumnúmerointeiro.
EditoraCasadoCódigocomlivrosdeumaformadiferente
3.5CASTINGEPROMOÇÃO
24 3.5CASTINGEPROMOÇÃO
Para fazer isso sem que haja o erro de compilação, é preciso ordenar que o número quebrado sejamoldado(casted)comoumnúmerointeiro.Esseprocessorecebeonomedecasting.
doubled3=3.14;inti=(int)d3;
Ocastingfoifeitoparamoldaravariáveld3comoumint.Ovalordeiagoraé3.
Omesmoocorreentrevaloresintelong.
longx=10000;inti=x;//nãocompila,poispodeestarperdendoinformação
E,sequisermosrealmentefazerisso,fazemosocasting:
longx=10000;inti=(int)x;
CASOSNÃOTÃOCOMUNSDECASTINGEATRIBUIÇÃO
Algunscastingsaparecemtambém:
floatx=0.0;
O código acima não compila pois todos os literais com ponto flutuante são consideradosdoublepeloJava.Efloatnãopodereceberumdoublesemperdadeinformação,parafazer
issofuncionarpodemosescreveroseguinte:
floatx=0.0f;
Aletraf,quepodesermaiúsculaouminúscula,indicaqueaqueleliteraldevesertratadocomofloat.
Outrocaso,queémaiscomum:
doubled=5;floatf=3;
floatx=f+(float)d;
VocêprecisadocastingporqueoJavafazascontasevaiarmazenandosemprenomaiortipoqueapareceuduranteasoperações,nocasoodouble.
E,umaobservação:nomínimo,oJavaarmazenaoresultadoemumint,nahoradefazeras
contas.
Atécastingcomvariáveisdotipocharpodemocorrer.Oúnicotipoprimitivoquenãopode
seratribuídoanenhumoutrotipoéoboolean.
3.5CASTINGEPROMOÇÃO 25
CASTINGSPOSSÍVEIS
AbaixoestãorelacionadostodososcastspossíveisnalinguagemJava,mostrandoaconversãodeumvalorparaoutro.AindicaçãoImpl.querdizerqueaquelecastéimplícitoeautomático,ouseja,vocênãoprecisa indicarocast explicitamente (lembrandoqueo tipobooleannãopode serconvertidoparanenhumoutrotipo).
TAMANHODOSTIPOS
Natabelaabaixo,estãoostamanhosdecadatipoprimitivodoJava.
AsintaxedoifnoJavaéaseguinte:
if(condicaoBooleana){codigo;}
3.6OIFEOELSE
26 3.6OIFEOELSE
Umacondiçãobooleanaéqualquerexpressãoqueretornetrueoufalse.Paraisso,vocêpodeusarosoperadores<,>,<=,>=eoutros.Umexemplo:
intidade=15;if(idade<18){System.out.println("Nãopodeentrar");}
Alémdisso,vocêpodeusaracláusulaelseparaindicarocomportamentoquedeveserexecutado
nocasodaexpressãobooleanaserfalsa:
intidade=15;if(idade<18){System.out.println("Nãopodeentrar");}else{System.out.println("Podeentrar");}
Vocêpodeconcatenarexpressõesbooleanasatravésdosoperadoreslógicos"E"e"OU".O"E"érepresentadopelo&&eo"OU"érepresentadopelo||.
Umexemploseriaverificarseeletemmenosde18anoseseelenãoéamigododono:
intidade=15;booleanamigoDoDono=true;if(idade<18&&amigoDoDono==false){System.out.println("Nãopodeentrar");}else{System.out.println("Podeentrar");}
Esse código poderia ficar ainda mais legível, utilizando-se o operador de negação, o !. Esse
operadortransformaoresultadodeumaexpressãobooleanadefalseparatrueeviceversa.
intidade=15;booleanamigoDoDono=true;if(idade<18&&!amigoDoDono){System.out.println("Nãopodeentrar");}else{System.out.println("Podeentrar");}
Reparenalinha3queotrechoamigoDoDono==falsevirou!amigoDoDono.Elestêmomesmovalor.
Para comparar se uma variável tem o mesmo valor que outra variável ou valor, utilizamos ooperador==.Reparequeutilizarooperador=dentrodeumifvairetornarumerrodecompilação,
jáqueooperador=éodeatribuição.
intmes=1;if(mes==1){System.out.println("Vocêdeveriaestardeférias");}
3.6OIFEOELSE 27
Owhile é um comando usado para fazer um laço (loop), isto é, repetir um trecho de códigoalgumasvezes.Aideiaéqueessetrechodecódigosejarepetidoenquantoumadeterminadacondiçãopermanecerverdadeira.
intidade=15;while(idade<18){System.out.println(idade);idade=idade+1;}
Otrechodentrodoblocodowhileseráexecutadoatéomomentoemqueacondiçãoidade<18
passe a ser falsa.E issoocorrerá exatamentenomomentoemqueidade==18, o quenãoo fará
imprimir18.
inti=0;while(i<10){System.out.println(i);i=i+1;}
Jáowhileacimaimprimede0a9.
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
Outrocomandodeloopextremamenteutilizadoéofor.Aideiaéamesmadowhile:fazerumtrecho de código ser repetido enquanto uma condição continuar verdadeira.Mas alémdisso, ofor
isolatambémumespaçoparainicializaçãodevariáveiseomodificadordessasvariáveis.Issofazcomquefiquemmaislegíveis,asvariáveisquesãorelacionadasaoloop:
for(inicializacao;condicao;incremento){codigo;
3.7OWHILE
JáconheceoscursosonlineAlura?
3.8OFOR
28 3.7OWHILE
}
Umexemploéoaseguir:
for(inti=0;i<10;i=i+1){System.out.println("olá!");}
Reparequeesseforpoderiasertrocadopor:
inti=0;while(i<10){System.out.println("olá!");i=i+1;}
Porém,ocódigodoforindicaclaramentequeavariáveliserve,emespecial,paracontrolara
quantidadedelaçosexecutados.Quandousarofor?Quandousarowhile?Dependedogostoeda
ocasião.
PÓSINCREMENTO++
i=i+1poderealmentesersubstituídopori++quandoisolado,porém,emalgunscasos,
temosessainstruçãoenvolvidaem,porexemplo,umaatribuição:
inti=5;intx=i++;
Qualéovalordex?Odei,apósessalinha,é6.
O operador ++, quando vem após a variável, retorna o valor antigo, e incrementa (pós
incremento),fazendoxvaler5.
Sevocêtivesseusadoo++antesdavariável(préincremento),oresultadoseria6:
inti=5;intx=++i;//aquixvalera6
Apesardetermoscondiçõesbooleanasnosnossoslaços,emalgummomento,podemosdecidirpararoloopporalgummotivoespecialsemqueorestodolaçosejaexecutado.
for(inti=x;i<y;i++){if(i%19==0){System.out.println("Acheiumnúmerodivisívelpor19entrexey");break;}}
3.9CONTROLANDOLOOPS
3.9CONTROLANDOLOOPS 29
Ocódigoacimavaipercorrerosnúmerosdexayepararquandoencontrarumnúmerodivisívelpor19,umavezquefoiutilizadaapalavrachavebreak.
Damesmamaneira,épossívelobrigaroloopaexecutaropróximolaço.Paraissousamosapalavrachavecontinue.
for(inti=0;i<100;i++){if(i>50&&i<60){continue;}System.out.println(i);}
Ocódigoacimanãovaiimprimiralgunsnúmeros.(Quaisexatamente?)
No Java, podemos declarar variáveis a qualquer momento. Porém, dependendo de onde você asdeclarou,elavaivalerdeumdeterminadopontoaoutro.
//aquiavariávelinãoexisteinti=5;//apartirdaquielaexiste
Oescopodavariáveléonomedadoaotrechodecódigoemqueaquelavariávelexisteeondeépossívelacessá-la.
Quandoabrimosumnovoblococomaschaves,asvariáveisdeclaradasalidentrosóvalematéofimdaquelebloco.
//aquiavariávelinãoexisteinti=5;//apartirdaquielaexistewhile(condicao){//oiaindavaleaquiintj=7;//ojpassaaexistir}//aquiojnãoexistemais,masoicontinuadentrodoescopo
Noblocoacima,avariáveljpáradeexistirquandoterminaoblocoondeelafoideclarada.Sevocê
tentaracessarumavariávelforadeseuescopo,ocorreráumerrodecompilação.
Omesmovaleparaumif:
3.10ESCOPODASVARIÁVEIS
30 3.10ESCOPODASVARIÁVEIS
if(algumBooleano){inti=5;}else{inti=10;}System.out.println(i);//cuidado!
Aquiavariávelinãoexisteforadoifedoelse!Sevocêdeclararavariávelantesdoif,vai
haveroutroerrodecompilação:dentrodoifedoelseavariávelestásendoredeclarada!Entãoo
códigoparacompilarefazersentidofica:
inti;if(algumBooleano){i=5;}else{i=10;}System.out.println(i);
Umasituaçãoparecidapodeocorrercomofor:
for(inti=0;i<10;i++){System.out.println("olá!");}System.out.println(i);//cuidado!
Nestefor,avariávelimorreaoseutérmino,nãopodendoseracessadadeforadofor,gerando
umerrodecompilação.Sevocêrealmentequeracessarocontadordepoisdoloopterminar,precisadealgocomo:
inti;for(i=0;i<10;i++){System.out.println("olá!");}System.out.println(i);
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoJavaeOrientaçãoaObjetos
VocêpodetambémfazerocursodatadessaapostilanaCaelum
3.10ESCOPODASVARIÁVEIS 31
Umblocotambémpodeserdeclaradodentrodeoutro.Istoé,umifdentrodeumfor,ouum
fordentrodeumfor,algocomo:
while(condicao){for(inti=0;i<10;i++){//código}}
Vimosapenasoscomandosmaisusadosparacontroledefluxo.OJavaaindapossuiodo..while
eoswitch.Pesquisesobreelesedigaquandoéinteressanteusarcadaumdeles.
Algumasvezes, temosvários laços encadeados.Podemosutilizarobreak para quebrar o laço
maisinterno.Mas,sequisermosquebrarumlaçomaisexterno,teremosdeencadeardiversosifseseucódigoficaráumabagunça.OJavapossuiumartifíciochamadolabeledloops;pesquisesobreeles.
Oqueacontecesevocêtentardividirumnúmerointeiropor0?Epor0.0?
Existeumcaminhoentreos tiposprimitivosque indicamseháanecessidadeounãodecastingentreos tipos.Porexemplo,int ->long ->double (umint pode ser tratado comoum
double,masnãoocontrário).Pesquise (ou teste), eposicioneosoutros tiposprimitivosnesse
fluxo.
Alémdosoperadoresdeincremento,existemosdedecremento,como--iei--.Alémdesses,
vocêpodeusarinstruçõesdotipoi+=xei-=x,oqueessasinstruçõesfazem?Teste.
Mais exercícios de fixação de sintaxe. Para quem já conhece um pouco de Java, pode sermuitosimples;mas recomendamos fortemente que você faça os exercícios para se acostumar comerros decompilação,mensagensdojavac,convençãodecódigo,etc...
Apesardeextremamentesimples,precisamospraticarasintaxequeestamosaprendendo.Paracadaexercício,crieumnovoarquivocomextensão.java,edeclareaqueleestranhocabeçalho,dandonomeaumaclasseecomumblocomaindentrodele:
classExercicioX{publicstaticvoidmain(String[]args){//seuexercíciovaiaqui}}
3.11UMBLOCODENTRODOOUTRO
3.12PARASABERMAIS
3.13EXERCÍCIOS:FIXAÇÃODESINTAXE
32 3.11UMBLOCODENTRODOOUTRO
Nãocopieecoledeumexercíciojáexistente!Aproveiteparapraticar.
1. Imprimatodososnúmerosde150a300.
2. Imprimaasomade1até1000.
3. Imprimatodososmúltiplosde3,entre1e100.
4. Imprimaosfatoriaisde1a10.
Ofatorialdeumnúmeronén*(n-1)*(n-2)*...*1.Lembre-sedeutilizarosparênteses.
Ofatorialde0é1
Ofatorialde1é(0!)*1=1
Ofatorialde2é(1!)*2=2
Ofatorialde3é(2!)*3=6
Ofatorialde4é(3!)*4=24
Façaumforqueinicieumavariáveln(número)como1efatorial(resultado)como1evariande1até10:
intfatorial=1;for(intn=1;n<=10;n++){
}
5. Nocódigodoexercícioanterior,aumenteaquantidadedenúmerosqueterãoosfatoriaisimpressos,até20,30,40.Emumdeterminadomomento,alémdessecálculodemorar,vaicomeçaramostrarrespostascompletamenteerradas.Porquê?
Mudedeintparalongparaveralgumamudança.
6. (opcional) Imprima os primeiros números da série de Fibonacci até passar de 100. A série deFibonacciéaseguinte:0,1,1,2,3,5,8,13,21,etc...Paracalculá-la,oprimeiroelementovale0,osegundovale1,daípordiante,on-ésimoelementovaleo(n-1)-ésimoelementosomadoao(n-2)-ésimoelemento(ex:8=5+3).
7. (opcional)Escrevaumprogramaque, dadaumavariávelx com algum valor inteiro, temosum
novoxdeacordocomaseguinteregra:
sexépar,x=x/2
sexéimpar,x=3*x+1
imprimex
3.13EXERCÍCIOS:FIXAÇÃODESINTAXE 33
Oprogramadevepararquandoxtiverovalorfinalde1.Porexemplo,parax=13,asaída
será:
40->20->10->5->16->8->4->2->1
IMPRIMINDOSEMPULARLINHA
Umdetalhe importante équeumaquebrade linhaé impressa todavezquechamamosprintln.Paranãopularumalinha,usamosocódigoaseguir:
System.out.print(variavel);
8. (opcional)Imprimaaseguintetabela,usandoforsencadeados:
124369481216nn*2n*3....n*n
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
1. FaçaoexercíciodasériedeFibonacciusandoapenasduasvariáveis.
Seuslivrosdetecnologiaparecemdoséculopassado?
3.14DESAFIOS:FIBONACCI
34 3.14DESAFIOS:FIBONACCI
CAPÍTULO4
"Programaçãoorientadaaobjetoséumapéssimaideia,quesópoderiaternascidonaCalifórnia."--EdsgerDijkstra
Aotérminodestecapítulo,vocêserácapazde:
dizeroqueéeparaqueserveorientaçãoaobjetos;conceituarclasses,atributosecomportamentos;entenderosignificadodevariáveiseobjetosnamemória.
Orientação a objetos é uma maneira de programar que ajuda na organização e resolve muitosproblemasenfrentadospelaprogramaçãoprocedural.
ConsideremosoclássicoproblemadavalidaçãodeumCPF.Normalmente,temosumformulário,noqualrecebemosessa informação,edepois temosqueenviaressescaracteresparaumafunçãoquevaivalidá-lo,comonopseudocódigoabaixo:
cpf=formulario->campo_cpfvalida(cpf)
AlguémteobrigaasemprevalidaresseCPF?Vocêpode,inúmerasvezes,esquecerdechamaressevalidador.Mais:considerequevocêtem50formulárioseprecisevalidaremtodoselesoCPF.Sesuaequipetem3programadorestrabalhandonessesformulários,quemficaresponsávelporessavalidação?Todos!
Asituaçãopodepiorar:naentradadeumnovodesenvolvedor,precisaríamosavisá-loquesempredevemosvalidarocpfdeumformulário.Énessemomentoquenascemaquelesguiasdeprogramaçãopara o desenvolvedor que for entrar nesse projeto - às vezes, é um documento enorme. Em outraspalavras,tododesenvolvedorprecisaficarsabendodeumaquantidadeenormedeinformações,que,namaioriadasvezes,nãoestárealmenterelacionadoàsuapartenosistema,maseleprecisalertudoisso,resultandoumentravemuitogrande!
Outra situação onde ficam claros os problemas da programação procedural, é quando nosencontramosnanecessidadedelerocódigoquefoiescritoporoutrodesenvolvedoredescobrircomoele funciona internamente.Umsistemabemencapsuladonãodeveriagerar essanecessidade.Emum
ORIENTAÇÃOAOBJETOSBÁSICA
4.1MOTIVAÇÃO:PROBLEMASDOPARADIGMAPROCEDURAL
4ORIENTAÇÃOAOBJETOSBÁSICA 35
sistemagrande,simplesmentenãotemostempodelertodoocódigoexistente.
Considerandoquevocênãoerrenessepontoequesuaequipe tenhaumacomunicaçãomuitoboa(percebaquecomunicaçãoexcessivapodeserprejudicialeatrapalharoandamento),aindatemosoutroproblema:imagineque,emtodoformulário,vocêtambémquerqueaidadedoclientesejavalidada-oclienteprecisatermaisde18anos.Vamosterdecolocarumif...masonde?Espalhadoportodoseu
código... Mesmo que se crie outra função para validar, precisaremos incluir isso nos nossos 50formuláriosjáexistentes.Qualéachancedeesquecermosemumdeles?Émuitogrande.
Aresponsabilidadedeverificarseoclientetemounãotem18anosficouespalhadaportodooseucódigo.Seriainteressantepoderconcentraressaresponsabilidadeemumlugarsó,paranãoterchancesdeesquecerisso.
Melhor ainda seria se conseguíssemos mudar essa validação e os outros programadores nemprecisassemficarsabendodisso.Emoutraspalavras,elescriariamformulárioseumúnicoprogramadorseriaresponsávelpelavalidação:osoutrosnemsabemdaexistênciadessetrechodecódigo.Impossível?Não,oparadigmadaorientaçãoaobjetosfacilitatudoisso.
Oproblemadoparadigmaprocedural é quenão existe uma forma simples de criar conexão forteentredadosefuncionalidades.Noparadigmaorientadoaobjetosémuitofácilteressaconexãoatravésdosrecursosdapróprialinguagem.
QUAISASVANTAGENS?
Orientação a objetos vai te ajudar em muito em se organizar e escrever menos, além deconcentrar as responsabilidades nos pontos certos, flexibilizando sua aplicação, encapsulando alógicadenegócios.
Outra enorme vantagem, onde você realmente vai economizar montanhas de código, é opolimorfismodasreferências,queveremosemumposteriorcapítulo.
Nos próximos capítulos, conseguiremos enxergar toda essa vantagem, mas, primeiramente énecessárioconhecerumpoucomaisdasintaxeedacriaçãodetiposereferênciasemJava.
36 4.1MOTIVAÇÃO:PROBLEMASDOPARADIGMAPROCEDURAL
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Considere um programa para um banco, é bem fácil perceber que uma entidade extremamenteimportante para o nosso sistema é a conta. Nossa ideia aqui é generalizarmos alguma informação,juntamentecomfuncionalidadesquetodacontadeveter.
Oquetodacontatemeéimportanteparanós?
númerodacontanomedotitulardacontasaldo
Oquetodacontafazeéimportanteparanós?Istoé,oquegostaríamosde"pediràconta"?
sacaumaquantidadexdepositaumaquantidadeximprimeonomedotitulardacontadevolveosaldoatualtransfereumaquantidadexparaumaoutracontaydevolveotipodeconta
Comisso,temosoprojetodeumacontabancária.Podemospegaresseprojetoeacessarseusaldo?Não.Oquetemosaindaéoprojeto.Antes,precisamosconstruirumaconta,parapoderacessaroqueelatem,epediraelaquefaçaalgo.
Agoraéamelhorhoradeaprenderalgonovo
4.2CRIANDOUMTIPO
4.2CRIANDOUMTIPO 37
Reparenafigura:apesardopapeldoladoesquerdoespecificarumaConta,essaespecificaçãoéumaConta?Nós depositamos e sacamos dinheiro desse papel?Não.Utilizamos a especificação daContaparapodercriarinstânciasquerealmentesãocontas,ondepodemosrealizarasoperaçõesquecriamos.
Apesardedeclararmosquetodacontatemumsaldo,umnúmeroeumaagêncianopedaçodepapel(comoàesquerdanafigura),sãonasinstânciasdesseprojetoquerealmenteháespaçoparaarmazenaressesvalores.
Aoprojetodaconta,istoé,adefiniçãodaconta,damosonomedeclasse.Aoquepodemosconstruirapartirdesseprojeto,ascontasdeverdade,damosonomedeobjetos.
A palavra classe vem da taxonomia da biologia. Todos os seres vivos de uma mesma classebiológicatêmumasériedeatributosecomportamentosemcomum,masnãosãoiguais,podemvariarnosvaloresdessesatributosecomorealizamessescomportamentos.
HomoSapiensdefineumgrupodeseresquepossuemcaracterísticasemcomum,porémadefinição(a ideia,oconceito)deumHomoSapiens éumserhumano?Não.Tudoestá especificadonaclasseHomoSapiens,massequisermosmandaralguémcorrer,comer,pular,precisaremosdeumainstânciadeHomoSapiens,ouentãodeumobjetodotipoHomoSapiens.
Umoutroexemplo:umareceitadebolo.Aperguntaécerteira:vocêcomeumareceitadebolo?Não.
38 4.2CRIANDOUMTIPO
Precisamos instanciá-la, criar um objeto bolo a partir dessa especificação (a classe) para utilizá-la.Podemos criar centenas de bolos a partir dessa classe (a receita, no caso), eles podem ser bemsemelhantes,algunsatéidênticos,massãoobjetosdiferentes.
Podemos fazer milhares de analogias semelhantes. A planta de uma casa é uma casa?Definitivamentenão.Nãopodemosmorardentrodaplantadeumacasa,nempodemosabrirsuaportaou pintar suas paredes. Precisamos, antes, construir instâncias a partir dessa planta. Essas instâncias,sim,podemospintar,decoraroumorardentro.
Pode parecer óbvio,mas a dificuldade inicial do paradigmada orientação a objetos é justo saberdistinguiroqueéclasseeoqueéobjeto.Écomumo inicianteutilizar,obviamentede formaerrada,essasduaspalavrascomosinônimos.
VamoscomeçarapenascomoqueumaConta tem, enãocomoqueela faz (veremos logoem
seguida).
Umtipodesses,comooespecificadodeContaacima,podeserfacilmentetraduzidoparaJava:
classConta{intnumero;Stringtitular;doublesaldo;
//..}
STRING
StringéumaclasseemJava.Elaguardaumacadeiadecaracteres,umafrasecompleta.Comoestamos ainda aprendendo o que é uma classe, entenderemos com detalhes a classe String
apenasemcapítulosposteriores.
Porenquanto,declaramosoquetodacontadeveter.Estessãoosatributosquetodaconta,quandocriada,vaiter.Reparequeessasvariáveisforamdeclaradasforadeumbloco,diferentedoquefazíamosquandotinhaaquelemain.Quandoumavariávelédeclaradadiretamentedentrodoescopodaclasse,échamadadevariáveldeobjeto,ouatributo.
JátemosumaclasseemJavaqueespecificaoquetodoobjetodessaclassedeveter.Mascomousá-
4.3UMACLASSEEMJAVA
4.4CRIANDOEUSANDOUMOBJETO
4.3UMACLASSEEMJAVA 39
la?Alémdessa classe, ainda teremos oPrograma.java e a partir dele é que vamos utilizar a classeConta.
Paracriar (construir, instanciar)umaConta, bastausar apalavrachavenew.Devemosutilizar
tambémosparênteses,quedescobriremosoquefazemexatamenteemumcapítuloposterior:
classPrograma{publicstaticvoidmain(String[]args){newConta();}}
Bem,ocódigoacimacriaumobjetodotipoConta,mascomoacessaresseobjetoquefoicriado?
Precisamosteralgumaformadenosreferenciarmosaesseobjeto.Precisamosdeumavariável:
classPrograma{publicstaticvoidmain(String[]args){ContaminhaConta;minhaConta=newConta();}}
PodeparecerestranhoescrevermosduasvezesConta:umaveznadeclaraçãodavariáveleoutra
veznousodonew.Masháummotivo,queembreveentenderemos.
Através da variável minhaConta , podemos acessar o objeto recém criado para alterar seu
titular,seusaldo,etc:
classPrograma{publicstaticvoidmain(String[]args){ContaminhaConta;minhaConta=newConta();
minhaConta.titular="Duke";minhaConta.saldo=1000.0;
System.out.println("Saldoatual:"+minhaConta.saldo);}}
Éimportante fixarqueoponto foiutilizadoparaacessaralgoemminhaConta.AminhaConta
pertenceaoDuke,etemsaldodemilreais.
40 4.4CRIANDOEUSANDOUMOBJETO
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Dentro da classe, também declararemos o que cada conta faz e como isto é feito - oscomportamentosquecadaclassetem,istoé,oqueelafaz.Porexemplo,dequemaneiraqueumaContasacadinheiro?EspecificaremosissodentrodaprópriaclasseConta,enãoemumlocaldesatreladodas
informações da própria Conta. É por isso que essas "funções" são chamadas demétodos. Pois é amaneiradefazerumaoperaçãocomumobjeto.
Queremos criar um método que saca uma determinada quantidade e não devolve nenhumainformaçãoparaquemacionaressemétodo:
classConta{doublesalario;//...outrosatributos...
voidsaca(doublequantidade){doublenovoSaldo=this.saldo-quantidade;this.saldo=novoSaldo;}}
A palavra chave void diz que, quando você pedir para a conta sacar uma quantia, nenhuma
informaçãoseráenviadadevoltaaquempediu.
Quando alguém pedir para sacar, ele também vai dizer quanto quer sacar. Por isso precisamosdeclararométodocomalgodentrodosparênteses-oquevaiaídentroéchamadodeargumentodométodo(ouparâmetro).Essavariáveléumavariávelcomum,chamadatambémdetemporáriaoulocal,pois,aofinaldaexecuçãodessemétodo,eladeixadeexistir.
Dentrodométodo,estamosdeclarandoumanovavariável.Essavariável,assimcomooargumento,vaimorrernofimdométodo,poisesteéseuescopo.Nomomentoquevamosacessarnossoatributo,
EditoraCasadoCódigocomlivrosdeumaformadiferente
4.5MÉTODOS
4.5MÉTODOS 41
usamos a palavra chave this para mostrar que esse é um atributo, e não uma simples variável.
(veremosdepoisqueéopcional)
Repare que, nesse caso, a conta poderia estourar um limite fixado pelo banco.Mais para frente,evitaremosessasituação,edeumamaneiramuitoelegante.
Damesmaforma,temosométodoparadepositaralgumaquantia:
classConta{//...outrosatributosemétodos...
voiddeposita(doublequantidade){this.saldo+=quantidade;}}
Observequenãousamosumavariávelauxiliare,alémdisso,usamosaabreviação+=paradeixaro
métodobemsimples.O+= somaquantidade aovalor antigodo saldo e guardanopróprio saldo, o
valorresultante.
Paramandarumamensagemaoobjetoepedirqueeleexecuteummétodo,tambémusamosoponto.Otermousadoparaissoéinvocaçãodemétodo.
Ocódigoaseguirsacadinheiroedepoisdepositaoutraquantiananossaconta:
classTestaAlgunsMetodos{publicstaticvoidmain(String[]args){//criandoacontaContaminhaConta;minhaConta=newConta();
//alterandoosvaloresdeminhaContaminhaConta.titular="Duke";minhaConta.saldo=1000;
//saca200reaisminhaConta.saca(200);
//deposita500reaisminhaConta.deposita(500);System.out.println(minhaConta.saldo);}}
Uma vez que seu saldo inicial é 1000 reais, se sacarmos 200 reais, depositarmos 500 reais eimprimirmosovalordosaldo,oqueseráimpresso?
Ummétodo sempre temquedefiniroque retorna,nemquedefinaquenãohá retorno, comonosexemplosanterioresondeestávamosusandoovoid.
4.6MÉTODOSCOMRETORNO
42 4.6MÉTODOSCOMRETORNO
Ummétodopoderetornarumvalorparaocódigoqueochamou.Nocasodonossométodosaca,
podemosdevolverumvalorbooleanoindicandoseaoperaçãofoibemsucedida.
classConta{//...outrosmétodoseatributos...
booleansaca(doublevalor){if(this.saldo<valor){returnfalse;}else{this.saldo=this.saldo-valor;returntrue;}}}
Adeclaraçãodométodomudou!Ométodosacanão temvoid na frente. Isto quer dizer que,
quandoé acessado, eledevolve algum tipode informação.Nocaso,umboolean.Apalavra chave
returnindicaqueométodovaiterminarali,retornandotalinformação.
Exemplodeuso:
minhaConta.saldo=1000;booleanconsegui=minhaConta.saca(2000);if(consegui){System.out.println("Conseguisacar");}else{System.out.println("Nãoconseguisacar");}
Ouentão,possoeliminaravariáveltemporária,sedesejado:
minhaConta.saldo=1000;if(minhaConta.saca(2000)){System.out.println("Conseguisacar");}else{System.out.println("Nãoconseguisacar");}
Maisadiante,veremosquealgumasvezesémaisinteressantelançarumaexceção(exception)nessescasos.
Meuprogramapodemanternamemórianãoapenasumaconta,comomaisdeuma:
4.6MÉTODOSCOMRETORNO 43
classTestaDuasContas{publicstaticvoidmain(String[]args){
ContaminhaConta;minhaConta=newConta();minhaConta.saldo=1000;
ContameuSonho;meuSonho=newConta();meuSonho.saldo=1500000;}}
Quandodeclaramosumavariávelparaassociaraumobjeto,naverdade,essavariávelnãoguardaoobjeto,esimumamaneiradeacessá-lo,chamadadereferência.
Époressemotivoque,diferentedos tiposprimitivoscomoint elong, precisamosdarnew
depoisdedeclaradaavariável:
publicstaticvoidmain(String[]args){Contac1;c1=newConta();
Contac2;c2=newConta();}
Ocorretoaqui,édizerquec1serefereaumobjeto.Nãoécorretodizerquec1éumobjeto,poisc1éumavariávelreferência,apesarde,depoisdeumtempo,osprogramadoresJavafalarem"Tenho
umobjetocdotipoConta",masapenasparaencurtarafrase"TenhoumareferênciacaumobjetodotipoConta".
Bastalembrarque,emJava,umavariávelnuncaéumobjeto.Nãohá,noJava,umamaneiradecriarmos o que é conhecido como "objeto pilha" ou "objeto local", pois todo objeto em Java, semexceção,éacessadoporumavariávelreferência.
Essecódigonosdeixanaseguintesituação:
Contac1;c1=newConta();
Contac2;c2=newConta();
4.7OBJETOSSÃOACESSADOSPORREFERÊNCIAS
44 4.7OBJETOSSÃOACESSADOSPORREFERÊNCIAS
Internamente,c1ec2vãoguardarumnúmeroqueidentificaemqueposiçãodamemóriaaquela
Contaseencontra.Dessamaneira,aoutilizarmoso"."paranavegar,oJavavaiacessaraContaque
seencontranaquelaposiçãodememória,enãoumaoutra.
Para quem conhece, é parecido com um ponteiro, porém você não pode manipulá-lo como umnúmeroenemutilizá-loparaaritmética,elaétipada.
Umoutroexemplo:
classTestaReferencias{publicstaticvoidmain(String[]args){Contac1=newConta();c1.deposita(100);
Contac2=c1;//linhaimportante!c2.deposita(200);
System.out.println(c1.saldo);System.out.println(c2.saldo);}}
Qualéoresultadodocódigoacima?Oqueapareceaorodar?
Oqueaconteceaqui?Ooperador=copiaovalordeumavariável.Masqualéovalordavariável
c1?Éoobjeto?Não.Naverdade, o valor guardado é a referência (endereço) deondeoobjeto seencontranamemóriaprincipal.
Namemória,oqueacontecenessecaso:
Contac1=newConta();Contac2=c1;
4.7OBJETOSSÃOACESSADOSPORREFERÊNCIAS 45
Quandofizemosc2=c1,c2passaafazerreferênciaparaomesmoobjetoquec1referencia
nesseinstante.
Então,nessecódigoemespecífico,quandoutilizamosc1ouc2estamosnosreferindoexatamente
aomesmoobjeto!Elassãoduasreferênciasdistintas,porémapontamparaomesmoobjeto!Compará-lascom"=="vainosretornartrue,poisovalorqueelascarregaméomesmo!
Outraformadeperceber,équedemosapenasumnew,entãosópodehaverumobjetoContana
memória.
Atenção:nãoestamosdiscutindoaquiautilidadedefazerumareferênciaapontarpromesmoobjetoque outra. Essa utilidade ficará mais clara quando passarmos variáveis do tipo referência comoargumentoparamétodos.
NEW
Oqueexatamentefazonew?
Onewexecutaumasériedetarefas,queveremosmaisadiante.
Mas, para melhor entender as referências no Java, saiba que o new, depois de alocar a
memória para esse objeto, devolve uma "flecha", isto é, um valor de referência. Quando vocêatribuiissoaumavariável,essavariávelpassaasereferirparaessemesmoobjeto.
Podemosentãoveroutrasituação:
publicstaticvoidmain(String[]args){Contac1=newConta();c1.titular="Duke";c1.saldo=227;
Contac2=newConta();c2.titular="Duke";c2.saldo=227;
if(c1==c2){System.out.println("Contasiguais");}}
Ooperador==comparaoconteúdodasvariáveis,masessasvariáveisnãoguardamoobjeto,esim
oendereçoemqueeleseencontra.Comoemcadaumadessasvariáveisguardamosduascontascriadasdiferentemente,elasestãoemespaçosdiferentesdamemória,oquefazotestenoifvalerfalse.As
contas podem ser equivalentes no nosso critério de igualdade, porém elas não são omesmo objeto.Quandosetratadeobjetos,podeficarmaisfácilpensarqueo==comparaseosobjetos(referências,na
46 4.7OBJETOSSÃOACESSADOSPORREFERÊNCIAS
verdade)sãoomesmo,enãosesãoiguais.
Para saber se dois objetos têm o mesmo conteúdo, você precisa comparar atributo por atributo.Veremosumasoluçãomaiseleganteparaissotambém.
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
Esequisermos terummétodoque transferedinheiroentreduascontas?Podemosficar tentadosacriarummétodoquerecebedoisparâmetros:conta1econta2dotipoConta.Mascuidado:assim
estamospensandodemaneiraprocedural.
Aideiaéque,quandochamarmosométodotransfere,játeremosumobjetodotipoConta(o
this), portantoométodo recebe apenasum parâmetrodo tipoConta, a Conta destino (além do
valor):
classConta{
//atributosemétodos...
voidtransfere(Contadestino,doublevalor){
JáconheceoscursosonlineAlura?
4.8OMÉTODOTRANSFERE()
4.8OMÉTODOTRANSFERE() 47
this.saldo=this.saldo-valor;destino.saldo=destino.saldo+valor;}}
Para deixar o código mais robusto, poderíamos verificar se a conta possui a quantidade a sertransferidadisponível.Paraficaraindamaisinteressante,vocêpodechamarosmétodosdeposita e
sacajáexistentesparafazeressatarefa:
classConta{
//atributosemétodos...
booleantransfere(Contadestino,doublevalor){booleanretirou=this.saca(valor);if(retirou==false){//nãodeuprasacar!returnfalse;}else{destino.deposita(valor);returntrue;}}}
QuandopassamosumaContacomoargumento,oqueseráqueacontecenamemória?Seráqueo
objetoéclonado?
No Java, a passagem de parâmetro funciona como uma simples atribuição como no uso do "=".Então,esseparâmetrovaicopiarovalordavariáveldotipoContaqueforpassadocomoargumento.E
qualéovalordeumavariáveldessas?Seuvaloréumendereço,umareferência,nuncaumobjeto.Por
48 4.8OMÉTODOTRANSFERE()
issonãohácópiadeobjetosaqui.
Esseúltimocódigopoderiaserescritocomumasintaxemuitomaissucinta.Como?
TRANSFEREPARA
PercebaqueonomedestemétodopoderiasertransfereParaaoinvésdesótransfere.A
chamadadométodoficamuitomaisnatural,épossível lera fraseemportuguêsqueela temumsentido:
conta1.transferePara(conta2,50);
Aleituradestecódigoseria"Conta1transfereparaconta250reais".
As variáveis do tipo atributo, diferentemente das variáveis temporárias (declaradas dentro de ummétodo),recebemumvalorpadrão.Nocasonumérico,valem0,nocasodeboolean,valemfalse.
Vocêtambémpodedarvaloresdefault,comosegue:
classConta{intnumero=1234;Stringtitular="Duke";doublesaldo=1000.0;}
Nesse caso, quando você criar uma conta, seus atributos já estão "populados" com esses valorescolocados.
ImaginequecomecemosaaumentarnossaclasseContaeadicionarnome,sobrenomeecpfdo
titulardaconta.Começaríamosatermuitosatributos...e,sevocêpensardireito,umaContanãotem
nome,nemsobrenomenemcpf,quemtemessesatributoséumCliente.Entãopodemoscriar
umanovaclasseefazerumacomposição
Seus atributos também podem ser referências para outras classes. Suponha a seguinte classeCliente:
classCliente{Stringnome;Stringsobrenome;Stringcpf;}
classConta{intnumero;doublesaldo;
4.9CONTINUANDOCOMATRIBUTOS
4.9CONTINUANDOCOMATRIBUTOS 49
Clientetitular;//..}
Edentrodomaindaclassedeteste:
classTeste{publicstaticvoidmain(String[]args){ContaminhaConta=newConta();Clientec=newCliente();minhaConta.titular=c;//...}}
Aqui,simplesmentehouveumaatribuição.Ovalordavariávelcécopiadoparaoatributotitular
doobjeto aoqualminhaConta se refere.Emoutras palavras,minhaConta temuma referência ao
mesmoClientequecserefere,epodeseracessadoatravésdeminhaConta.titular.
Vocêpoderealmentenavegarsobretodaessaestruturadeinformação,sempreusandooponto:
ClienteclienteDaMinhaConta=minhaConta.titular;clienteDaMinhaConta.nome="Duke";
Ouainda,podefazerissodeumaformamaisdiretaeatémaiselegante:
minhaConta.titular.nome="Duke";
Umsistemaorientadoaobjetoséumgrandeconjuntodeclassesquevaisecomunicar,delegandoresponsabilidadesparaquemformaisaptoarealizardeterminadatarefa.AclasseBancousaaclasse
ContaqueusaaclasseCliente,queusaaclasseEndereco.Dizemosqueessesobjetoscolaboram,
trocandomensagensentresi.Porissoacabamostendomuitasclassesemnossosistema,eelascostumamterumtamanhorelativamentecurto.
Mas,esedentrodomeucódigoeunãodessenewemClienteetentasseacessá-lodiretamente?
classTeste{publicstaticvoidmain(String[]args){ContaminhaConta=newConta();
minhaConta.titular.nome="Manoel";//...}}
Quando damos new em um objeto, ele o inicializa com seus valores default, 0 para números,
falseparabooleanenullparareferências.nulléumapalavrachaveemjava,queindicauma
referênciaparanenhumobjeto.
50 4.9CONTINUANDOCOMATRIBUTOS
Se,emalgumcaso,vocêtentaracessarumatributooumétododealguémqueestásereferenciandoparanull,vocêreceberáumerroduranteaexecução(NullPointerException,queveremosmaisà
frente).Daparaperceber,então,queonewnãotrazumefeitocascata,amenosquevocêdêumvalor
default(ouuseconstrutores,quetambémveremosmaisafrente):
classConta{intnumero;doublesaldo;Clientetitular=newCliente();//quandochamaremnewConta,//haveraumnewClienteparaele.}
Comessecódigo,todanovaContacriadajáteráumnovoClienteassociado,semnecessidade
de instanciá-lo logo em seguida da instanciação de uma Conta. Qual alternativa você deve usar?
Dependedocaso:paratodanovaContavocêprecisadeumnovoCliente?Éessaperguntaquedeve
serrespondida.Nessenossocasoarespostaénão,masdependedonossoproblema.
Atenção:paraquemnãoestáacostumadocomreferências,podeserbastanteconfusopensarsempreem como os objetos estão namemória para poder tirar as conclusões de o que ocorrerá ao executardeterminado código, por mais simples que ele seja. Com tempo, você adquire a habilidade derapidamente saber o efeito de atrelar as referências, sem ter de gastar muito tempo para isso. Éimportante,nessecomeço,vocêestarsemprepensandonoestadodamemória.Erealmentelembrarque,noJava"umavariávelnuncacarregaumobjeto,esimumareferênciaparaele"facilitamuito.
AlémdoBancoqueestamoscriando,vamosvercomoficariamcertasclassesrelacionadasauma
fábrica de carros. Vamos criar uma classe Carro , com certos atributos, que descrevem suas
características,ecomcertosmétodos,quedescrevemseucomportamento.
classCarro{Stringcor;Stringmodelo;doublevelocidadeAtual;doublevelocidadeMaxima;
//ligaocarrovoidliga(){System.out.println("Ocarroestáligado");}
//aceleraumacertaquantidadevoidacelera(doublequantidade){doublevelocidadeNova=this.velocidadeAtual+quantidade;this.velocidadeAtual=velocidadeNova;}
//devolveamarchadocarrointpegaMarcha(){if(this.velocidadeAtual<0){return-1;
4.10PARASABERMAIS:UMAFÁBRICADECARROS
4.10PARASABERMAIS:UMAFÁBRICADECARROS 51
}if(this.velocidadeAtual>=0&&this.velocidadeAtual<40){return1;}if(this.velocidadeAtual>=40&&this.velocidadeAtual<80){return2;}return3;}}
VamostestarnossoCarroemumnovoprograma:
classTestaCarro{publicstaticvoidmain(String[]args){CarromeuCarro;meuCarro=newCarro();meuCarro.cor="Verde";meuCarro.modelo="Fusca";meuCarro.velocidadeAtual=0;meuCarro.velocidadeMaxima=80;
//ligaocarromeuCarro.liga();
//aceleraocarromeuCarro.acelera(20);System.out.println(meuCarro.velocidadeAtual);}}
NossocarropodecontertambémumMotor:
classMotor{intpotencia;Stringtipo;}
classCarro{Stringcor;Stringmodelo;doublevelocidadeAtual;doublevelocidadeMaxima;Motormotor;
//..}
Podemos, criar diversos Carros e mexer com seus atributos e métodos, assim como fizemos noexemplodoBanco.
52 4.10PARASABERMAIS:UMAFÁBRICADECARROS
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoJavaeOrientaçãoaObjetos
Quandodeclaramosumaclasse,ummétodoouumatributo,podemosdaronomequequisermos,seguindo uma regra. Por exemplo, o nome de ummétodo não pode começar com um número.Pesquisesobreessasregras.
Como você pode ter reparado, sempre damos nomes às variáveis com letrasminúsculas. É queexistemconvenções de código, dadas pela Oracle, para facilitar a legibilidade do código entreprogramadores. Essa convenção é muito seguida. Leia sobre ela pesquisando por "java codeconventions".
Énecessáriousarapalavrachavethisquandoforacessarumatributo?Paraque,então,utilizá-
la?
Existe um padrão para representar suas classes em diagramas, que é amplamente utilizado,chamadoUML.Pesquisesobreele.
Omodelodacontaaseguirseráutilizadoparaosexercíciosdospróximoscapítulos.
Oobjetivo aqui é criar um sistemapara gerenciar as contas deumBanco.Osexercíciosdessecapítulosãoextremamenteimportantes.
1. Modele uma conta. A ideia aqui é apenas modelar, isto é, só identifique que informações sãoimportantes.DesenhenopapeltudooqueumaContatemetudooqueelafaz.Eladeveteronome
dotitular(String),onúmero (int), a agência (String), o saldo (double) e umadata de
abertura(String).Alémdisso, eladeve fazer as seguintes ações: saca,para retirarumvalordo
saldo;deposita,paraadicionarumvaloraosaldo;calculaRendimento,paradevolverorendimento
VocêpodetambémfazerocursodatadessaapostilanaCaelum
4.11UMPOUCOMAIS...
4.12EXERCÍCIOS:ORIENTAÇÃOAOBJETOS
4.11UMPOUCOMAIS... 53
mensaldessaconta.
2. Transforme o modelo acima em uma classe Java. Teste-a, usando uma outra classe que tenha omain.VocêdevecriaraclassedacontacomonomeConta,maspodenomear comoquiser a
classedetestes,contudo,eladevepossuirométodomain.
AclasseContadeveconterpelomenososseguintesmétodos:
sacaquerecebeumvalorcomoparâmetroeretiraessevalordosaldodaconta
depositaquerecebeumvalorcomoparâmetroeadicionaessevaloraosaldodaconta
calculaRendimentoquenãorecebeparâmetroalgumedevolveovalordosaldomultiplicado
por0.1
Umesboçodaclasse:
classConta{
doublesaldo;//seusoutrosatributosemétodos
voidsaca(doublevalor){//oquefazeraquidentro?}
voiddeposita(doublevalor){//oquefazeraquidentro?}
doublecalculaRendimento(){//oquefazeraquidentro?}}
Você pode (e deve) compilar seu arquivo java sem que você ainda tenha terminado sua classeConta.Issoevitaráquevocêrecebadezenasdeerrosdecompilaçãodeumavezsó.Crieaclasse
Conta,coloqueseusatributose,antesdecolocarqualquermétodo,compileoarquivojava.O
arquivoConta.classserágerado,masnãopodemos"executá-lo"jáqueessaclassenãotemum
main.Dequalquerforma,avantageméqueassimverificamosquenossaclasseContajáestá
tomandoformaeestáescritaemsintaxecorreta.
Esseéumprocessoincremental.Procuredesenvolverassimseusexercícios,paranãodescobrirsónofimdocaminhoquealgoestavamuitoerrado.
Umesboçodaclassequepossuiomain:
classTestaConta{
publicstaticvoidmain(String[]args){Contac1=newConta();
54 4.12EXERCÍCIOS:ORIENTAÇÃOAOBJETOS
c1.titular="Hugo";c1.numero=123;c1.agencia="45678-9";c1.saldo=50.0;c1.dataDeAbertura="04/06/2015";
c1.deposita(100.0);System.out.println("saldoatual:"+c1.saldo);System.out.println("rendimentomensal:"+c1.calculaRendimento());}}
Incremente essa classe. Faça outros testes, imprima outros atributos e invoque osmétodos quevocêcriouamais.
Lembre-se de seguir a convenção java, isso é importantíssimo. Isto é, preste atenção nasmaiúsculas e minúsculas, seguindo o seguinte exemplo: nomeDeAtributo, nomeDeMetodo,
nomeDeVariavel,NomeDeClasse,etc...
TODASASCLASSESNOMESMOARQUIVO?
Vocêatépodecolocartodasasclassesnomesmoarquivoeapenascompilaressearquivo.Elevaigerarum.classparacadaclassepresentenele.
Porém,porumaquestãodeorganização,éboapráticacriarumarquivo.javaparacada
classe.Emcapítulosposteriores,veremos tambémdeterminadoscasosnosquaisvocê seráobrigadoadeclararcadaclasseemumarquivoseparado.
Essa separação não é importante nesse momento do aprendizado, mas se quiser irpraticandosemterquecompilarclasseporclasse,vocêpodedizerparaojavaccompilar
todososarquivosjavadeumavez:
javac*.java
3. CrieummétodorecuperaDadosParaImpressao(),quenãorecebeparâmetromasdevolveotexto
comtodasasinformaçõesdanossacontaparaefetuarmosaimpressão.
Dessamaneira,vocênãoprecisaficarcopiandoecolandoummontedeSystem.out.println()
paracadamudançaetestequefizercomcadaumdeseusfuncionários,vocêsimplesmentevaifazer:
Contac1=newConta();//brincadeirascomc1....System.out.println(c1.recuperaDadosParaImpressao());
VeremosmaisafrenteométodotoString,queéumasoluçãomuitomaiseleganteparamostrara
representaçãodeumobjetocomoString,alémdenãojogartudoproSystem.out (sósevocê
4.12EXERCÍCIOS:ORIENTAÇÃOAOBJETOS 55
desejar).
Oesqueletodométodoficariaassim:
classConta{
//seusoutrosatributosemétodos
StringrecuperaDadosParaImpressao(){Stringdados="Titular:"+this.titular;dados+="\nNúmero:"+this.numero;//imprimiraquiosoutrosatributos...//tambémpodeimprimirthis.calculaRendimento()returndados;}}
4. Construaduascontascomonewecompare-oscomo==.Eseelestiveremosmesmosatributos?
Paraissovocêvaiprecisarcriaroutrareferência:
Contac1=newConta();c1.titular="Danilo";c1.saldo=100;
Contac2=newConta();c2.titular="Danilo";c2.saldo=100;
if(c1==c2){System.out.println("iguais");}else{System.out.println("diferentes");}
5. Crieduasreferênciasparaamesmaconta,compare-oscomo==.Tiresuasconclusões.Paracriarduasreferênciaspramesmaconta:
Contac1=newConta():c1.titular="Hugo";c1.saldo=100;
c2=c1;
Oqueacontececomoifdoexercícioanterior?
6. (opcional)EmvezdeutilizarumaStringpararepresentaradata,crieumaoutraclasse,chamada
Data.Elapossui3camposint,paradia,mêseano.Façacomquesuacontapasseausá-la.(é
parecidocomoúltimoexemplodaexplicação,emqueaConta passoua ter referênciaparaum
Cliente).
classConta{DatadataDeAbertura;//qualéovalordefaultaqui?//seusoutrosatributosemétodos}
classData{
56 4.12EXERCÍCIOS:ORIENTAÇÃOAOBJETOS
intdia;intmes;intano;}
ModifiquesuaclasseTestaContaparaquevocêcrieumaDataeatribuaelaaConta:
Contac1=newConta();//...Datadata=newData();//ligação!c1.dataDeAbertura=data;
FaçaodesenhodoestadodamemóriaquandocriarmosumConta.
7. (opcional)ModifiqueseumétodorecuperaDadosParaImpressaoparaqueeledevolvaovalorda
dataDeAberturadaquelaConta:
classConta{
//seusoutrosatributosemétodosDatadataDeAbertura;
StringrecuperaDadosParaImpressao(){Stringdados="\nTitular:"+this.titular;//imprimiraquiosoutrosatributos...
dados+="\nDia:"+this.dataDeAbertura.dia;dados+="\nMês:"+this.dataDeAbertura.mes;dados+="\nAno:"+this.dataDeAbertura.ano;returndados;}}
Teste-o. O que acontece se chamarmos o método recuperaDadosParaImpressao antes de
atribuirmosumadataparaestaConta?
8. (opcional) O que acontece se você tentar acessar um atributo diretamente na classe? Como, porexemplo:
Conta.saldo=1234;
Essecódigofazsentido?Eeste:
Conta.calculaRendimento();
FazsentidoperguntarparaoesquemadaContaseuvaloranual?
9. (opcional-avançado)CrieummétodonaclasseDataquedevolvaovalorformatadodadata,istoé,
devolvaumaStringcom"dia/mes/ano".IssoparaqueométodorecuperaDadosParaImpressaoda
classeContapossaficarassim:
classConta{//atributosemetodos
StringrecuperaDadosParaImpressao(){//imprimeoutrosatributos...
4.12EXERCÍCIOS:ORIENTAÇÃOAOBJETOS 57
dados+="\nDatadeabertura:"+this.dataDeAbertura.formatada();returndados;}}
1. Ummétodopodechamarelemesmo.Chamamos issoderecursão.Vocêpode resolver a série deFibonacciusandoummétodoquechamaelemesmo.Oobjetivoévocêcriarumaclasse,quepossaserusadadaseguintemaneira:
Fibonaccifibonacci=newFibonacci();for(inti=1;i<=6;i++){intresultado=fibonacci.calculaFibonacci(i);System.out.println(resultado);}
AquiimprimiráasequênciadeFibonacciatéasextaposição,istoé:1,1,2,3,5,8.
Estemétodo calculaFibonacci não pode ter nenhum laço, só pode chamar elemesmo como
método.Pensenelecomoumafunção,queusaaprópriafunçãoparacalcularoresultado.
2. Porqueomodoacimaéextremamentemaislentoparacalcularasériedoqueomodoiterativo(queseusaumlaço)?
3. Escreva o método recursivo novamente, usando apenas uma linha. Para isso, pesquise sobre ooperadorcondicionalternário.(ternaryoperator)
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Oobjetivodosexercíciosaseguiréfixaroconceitodeclasseseobjetos,métodoseatributos.Dadaaestruturadeumaclasse,bastatraduzi-laparaalinguagemJavaefazerusodeumobjetodamesmaem
4.13DESAFIOS
Seuslivrosdetecnologiaparecemdoséculopassado?
4.14FIXANDOOCONHECIMENTO
58 4.13DESAFIOS
umprogramasimples.
Sevocêestácomdificuldadeemalgumapartedessecapítulo,aproveiteetreinetudooquevimosnospequenosprogramasabaixo:
Programa1
Classe:PessoaAtributos:nome,idade.Método:voidfazAniversario()
Crieumapessoa,coloqueseunomeeidadeiniciais,façaalgunsaniversários(aumentandoaidade)eimprimaseunomeesuaidade.
Programa2
Classe:PortaAtributos:aberta,cor,dimensaoX,dimensaoY,dimensaoZMétodos:voidabre()voidfecha()voidpinta(Strings)booleanestaAberta()
Crie uma porta, abra e feche amesma, pinte-a de diversas cores, altere suas dimensões e use ométodoestaAbertaparaverificarseelaestáaberta.
Programa3
Classe:CasaAtributos:cor,porta1,porta2,porta3Método:voidpinta(Strings),intquantasPortasEstaoAbertas()
Crie uma casa e pinte-a. Crie três portas e coloque-as na casa; abra e feche as mesmas comodesejar. Utilize o método quantasPortasEstaoAbertas para imprimir o número de portas
abertas.
4.14FIXANDOOCONHECIMENTO 59
CAPÍTULO5
"Amarcadohomemimaturoéqueelequermorrernobrementeporumacausa,enquantoamarcadohomemmaduroéquerervivermodestamenteporuma."--J.D.Salinger
Aotérminodessecapítulo,vocêserácapazde:
controlaroacessoaosseusmétodos,atributoseconstrutoresatravésdosmodificadoresprivateepublic;escrevermétodosdeacessoaatributosdotipogettersesetters;escreverconstrutoresparasuasclasses;utilizarvariáveisemétodosestáticos.
Um dos problemasmais simples que temos no nosso sistema de contas é que o método saca
permite sacar mesmo que o saldo seja insuficiente. A seguir você pode lembrar como está a classeConta:
classConta{Stringtitular;intnumero;doublesaldo;
//..
voidsaca(doublevalor){this.saldo=this.saldo-valor;}}
Aclasseaseguirmostracomoépossívelultrapassarolimitedesaqueusandoométodosaca:
classTestaContaEstouro1{publicstaticvoidmain(String[]args){ContaminhaConta=newConta();minhaConta.saldo=1000.0;minhaConta.saca(50000);//saldoésó1000!!}}
MODIFICADORESDEACESSOEATRIBUTOSDECLASSE
5.1CONTROLANDOOACESSO
60 5MODIFICADORESDEACESSOEATRIBUTOSDECLASSE
Podemosincluirumifdentrodonossométodosaca()paraevitarasituaçãoqueresultariaem
umacontaemestadoinconsistente,comseusaldoabaixode0.Fizemosissonocapítulodeorientaçãoaobjetosbásica.
Apesardemelhorarbastante,aindatemosumproblemamaisgrave:ninguémgarantequeousuárioda classe vai sempre utilizar o método para alterar o saldo da conta. O código a seguir faz issodiretamente:
classTestaContaEstouro2{publicstaticvoidmain(String[]args){ContaminhaConta=newConta();minhaConta.saldo=-200;//saldoestáabaixode0}}
Comoevitarisso?Umaideiasimplesseriatestarsenãoestamossacandoumvalormaiorqueosaldotodavezqueformosalterá-lo:
classTestaContaEstouro3{
publicstaticvoidmain(String[]args){//aContaContaminhaConta=newConta();minhaConta.saldo=100;
//queromudarosaldopara-200doublenovoSaldo=-200;
//testaseonovoSaldoéválidoif(novoSaldo<0){//System.out.println("Nãopossomudarparaessesaldo");}else{minhaConta.saldo=novoSaldo;}}}
Essecódigoiriaserepetiraolongodetodanossaaplicaçãoe,pior,alguémpodeesquecerdefazeressacomparaçãoemalgummomento,deixandoacontanasituação inconsistente.AmelhorformaderesolverissoseriaforçarquemusaaclasseContaainvocarométodosacaenãopermitiroacesso
diretoaoatributo.ÉomesmocasodavalidaçãodeCPF.
Parafazer issonoJava,bastadeclararqueosatributosnãopodemseracessadosdeforadaclasseatravésdapalavrachaveprivate:
classConta{privatedoublesaldo;//...}
privateéummodificadordeacesso(tambémchamadodemodificadordevisibilidade).
Marcando um atributo comoprivado, fechamos o acesso aomesmo em relação a todas as outras
5.1CONTROLANDOOACESSO 61
classes,fazendocomqueoseguintecódigonãocompile:
classTestaAcessoDireto{publicstaticvoidmain(String[]args){ContaminhaConta=newConta();//nãocompila!vocênãopodeacessaroatributoprivadodeoutraclasseminhaConta.saldo=1000;}}
TesteAcessoDireto.java:5saldohasprivateaccessinContaminhaConta.saldo=1000;^1error
Na orientação a objetos, é prática quase que obrigatória proteger seus atributos com private.
(discutiremosoutrosmodificadoresdeacessoemoutroscapítulos).
Cadaclasseéresponsávelporcontrolarseusatributos,portantoeladevejulgarseaquelenovovaloréválidoounão!Estavalidaçãonãodevesercontroladaporquemestáusandoaclasseesimporelamesma, centralizando essa responsabilidade e facilitando futurasmudançasno sistema.Muitas outrasvezes nem mesmo queremos que outras classes saibam da existência de determinado atributo,escondendo-oporcompleto,jáqueeledizrespeitoaofuncionamentointernodoobjeto.
Repareque,queminvocaométodosacanãofazamenorideiadequeexisteumaverificaçãopara
ovalordosaque.Paraquemforusaressaclasse,bastasaberoqueométodofazenãocomoexatamenteeleofaz(oqueummétodofazésempremaisimportantedoquecomoelefaz:mudaraimplementaçãoéfácil,jámudaraassinaturadeummétodovaigerarproblemas).
A palavra chave private também pode ser usada para modificar o acesso a um método. Tal
funcionalidade é utilizada em diversos cenários: quando existe um método que serve apenas paraauxiliar a própria classe e quando há código repetido dentro de doismétodos da classe são osmaiscomuns. Sempre devemos expôr o mínimo possível de funcionalidades, para criar um baixoacoplamentoentreasnossasclasses.
Damesmamaneira que temosoprivate, temosomodificadorpublic, que permite a todos
acessaremumdeterminadoatributooumétodo:
classConta{//...publicvoidsaca(doublevalor){//possosacaratésaldoif(valor>this.saldo){System.out.println("Nãopossosacarumvalormaiorqueosaldo!");}else{this.saldo=this.saldo-valor;}}}
62 5.1CONTROLANDOOACESSO
EQUANDONÃOHÁMODIFICADORDEACESSO?
Atéagora,tínhamosdeclaradovariáveisemétodossemnenhummodificadorcomoprivatee
public . Quando isto acontece, o seu método ou atributo fica num estado de visibilidade
intermediárioentreoprivateeopublic,queveremosmaisprafrente,nocapítulodepacotes.
Émuitocomum,efaztodosentido,queseusatributossejamprivateequasetodosseusmétodos
sejampublic(nãoéumaregra!).Destaforma,todaconversadeumobjetocomoutroéfeitaportroca
demensagens,istoé,acessandoseusmétodos.Algomuitomaiseducadoquemexerdiretamenteemumatributoquenãoéseu!
Melhorainda!OdiaemqueprecisarmosmudarcomoérealizadoumsaquenanossaclasseConta,
adivinhe onde precisaríamosmodificar? Apenas nométodo saca, o que faz pleno sentido. Como
exemplo,imaginecobrarCPMFdecadasaque:bastavocêmodificarali,enenhumoutrocódigo,foraaclasseConta,precisaráserrecompilado.Mais:asclassesqueusamessemétodonemprecisamficar
sabendode talmodificação!Vocêprecisaapenas recompilar aquelaclassee substituir aquele arquivo.class.Ganhamosmuitoemesconderofuncionamentodonossométodonahoradedarmanutençãoe
fazermodificações.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Oquecomeçamosavernessecapítuloéaideiadeencapsular,istoé,escondertodososmembrosdeumaclasse(comovimosacima),alémdeescondercomofuncionamasrotinas(nocasométodos)donossosistema.
Encapsular é fundamental para que seu sistema seja suscetível a mudanças: não precisaremos
Agoraéamelhorhoradeaprenderalgonovo
5.2ENCAPSULAMENTO
5.2ENCAPSULAMENTO 63
mudarumaregradenegócioemvárioslugares,massimemapenasumúnicolugar, jáqueessaregraestáencapsulada.(vejaocasodométodosaca)
Oconjuntodemétodospúblicosdeumaclasseétambémchamadodeinterfacedaclasse,poisestaéaúnicamaneiraaqualvocêsecomunicacomobjetosdessaclasse.
PROGRAMANDOVOLTADOPARAAINTERFACEENÃOPARAAIMPLEMENTAÇÃO
É sempre bomprogramar pensandona interface da sua classe, como seus usuários a estarãoutilizando,enãosomenteemcomoelavaifuncionar.
A implementação em si, o conteúdo dosmétodos, não tem tanta importância para o usuáriodessaclasse,umavezqueelesóprecisasaberoquecadamétodopretendefazer,enãocomoelefaz,poisistopodemudarcomotempo.
EssafrasevemdolivroDesignPatterns,deEricGammaetal.Umlivrocultuadonomeiodaorientaçãoaobjetos.
Semprequevamosacessarumobjeto,utilizamossuainterface.Existemdiversasanalogiasfáceisnomundoreal:
Quandovocêdirigeumcarro,oqueteimportasãoospedaiseovolante(interface)enãoomotorque você está usando (implementação). É claro que um motor diferente pode te dar melhoresresultados,masoqueelefazéomesmoqueummotormenospotente,adiferençaestáemcomoele faz. Para trocar umcarro a álcool para uma gasolina você não precisa reaprender a dirigir!(trocar a implementaçãodosmétodos não precisamudar a interface, fazendo comque as outrasclassescontinuemusandoelesdamesmamaneira).
64 5.2ENCAPSULAMENTO
Todososcelulares fazemamesmacoisa (interface),elespossuemmaneiras (métodos)dediscar,ligar,desligar,atender,etc.Oquemudaécomoelesfazem(implementação),masreparequeparaefetuar uma ligação pouco importa se o celular é iPhone ou Android, isso fica encapsulado naimplementação(queaquisãooscircuitos).
JátemosconhecimentossuficientespararesolveraqueleproblemadavalidaçãodeCPF:
classCliente{privateStringnome;privateStringendereco;privateStringcpf;privateintidade;
publicvoidmudaCPF(Stringcpf){validaCPF(cpf);this.cpf=cpf;}
privatevoidvalidaCPF(Stringcpf){//sériederegrasaqui,falhacasonãosejaválido}
//..}
SealguémtentarcriarumClienteenãousaromudaCPFparaalterarumcpfdiretamente,vai
receberumerrodecompilação,jáqueoatributoCPFéprivado.EodiaquevocênãoprecisarverificaroCPFdequemtemmaisde60anos?Seumétodoficaoseguinte:
publicvoidmudaCPF(Stringcpf){if(this.idade<=60){validaCPF(cpf);}this.cpf=cpf;}
OcontrolesobreoCPFestácentralizado:ninguémconsegueacessá-losempassarporaí,aclasse
Clienteéaúnicaresponsávelpelosseusprópriosatributos!
Omodificadorprivate fazcomqueninguémconsigamodificar,nemmesmoler,oatributoem
questão.Comisso,temosumproblema:comofazerparamostrarosaldodeumaConta,jáquenem
mesmopodemosacessá-loparaleitura?
Precisamosentãoarranjarumamaneiradefazeresseacesso.Semprequeprecisamosarrumarumamaneiradefazeralgumacoisacomumobjeto,utilizamosdemétodos!Vamosentãocriarummétodo,digamospegaSaldo,pararealizaressasimplestarefa:
classConta{
5.3GETTERSESETTERS
5.3GETTERSESETTERS 65
privatedoublesaldo;
//outrosatributosomitidos
publicdoublepegaSaldo(){returnthis.saldo;}
//deposita()esaca()omitidos}
Paraacessarmososaldodeumaconta,podemosfazer:
classTestaAcessoComPegaSaldo{publicstaticvoidmain(String[]args){ContaminhaConta=newConta();minhaConta.deposita(1000);System.out.println("Saldo:"+minhaConta.pegaSaldo());}}
Parapermitiroacessoaosatributos(jáqueelessãoprivate)deumamaneiracontrolada,aprática
maiscomumécriardoismétodos,umqueretornaovaloreoutroquemudaovalor.
Aconvençãoparaessesmétodosédecolocarapalavragetousetantesdonomedoatributo.
Porexemplo,anossacontacomsaldo,limiteetitularficaassim,nocasodagentedesejardar
acessoaleituraeescritaatodososatributos:
classConta{
privateStringtitular;privatedoublesaldo;
publicdoublegetSaldo(){returnthis.saldo;}
publicvoidsetSaldo(doublesaldo){this.saldo=saldo;}
publicStringgetTitular(){returnthis.titular;}
publicvoidsetTitular(Stringtitular){this.titular=titular;}}
É uma má prática criar uma classe e, logo em seguida, criar getters e setters para todos seusatributos.Vocêsódevecriarumgetterousettersetiverarealnecessidade.ReparequenesseexemplosetSaldonãodeveriatersidocriado,jáquequeremosquetodosusemdeposita()esaca().
Outrodetalheimportante,ummétodogetXnãonecessariamenteretornaovalordeumatributoque
chama X do objeto em questão. Isso é interessante para o encapsulamento. Imagine a situação:
66 5.3GETTERSESETTERS
queremosqueobancosempremostrecomosaldo ovalordo limite somadoao saldo (umaprática
comumdosbancosquecostuma iludir seus clientes).Poderíamos sempre chamarc.getLimite()+
c.getSaldo(), mas isso poderia gerar uma situação de "replace all" quando precisássemos mudarcomoo saldo émostrado.Podemos encapsular isso emummétodo e, porquenão, dentrodoprópriogetSaldo?Repare:
classConta{
privateStringtitular;privatedoublesaldo;privatedoublelimite;//adicionandoumlimiteaconta
publicdoublegetSaldo(){returnthis.saldo+this.limite;}
//deposita()saca()etransfere()omitidos
publicStringgetTitular(){returnthis.titular;}
publicvoidsetTitular(Stringtitular){this.titular=titular;}}
OcódigoacimanempossibilitaachamadadométodogetLimite(),elenãoexiste.Enemdeve
existir enquanto não houver essa necessidade.OmétodogetSaldo() não devolve simplesmente o
saldo...esimoquequeremosquesejamostradocomosefosseosaldo.Utilizargettersesettersnão
sóajudavocêaprotegerseusatributos,comotambémpossibilita terdemudaralgoemumsólugar...chamamosissodeencapsulamento,poisescondeamaneiracomoosobjetosguardamseusdados.Éumapráticamuitoimportante.
Nossaclasseestátotalmentepronta?Istoé,existeachancedelaficarcomsaldomenorque0?Podeparecerquenão,mas,esedepositarmosumvalornegativonaconta?Ficaríamoscommenosdinheiroqueopermitido, jáquenãoesperávamospor isso.Paranosprotegerdissobastamudarmosométododeposita()paraqueeleverifiqueseovalorénecessariamentepositivo.
Depois disso precisaríamos mudar mais algum outro código? A resposta é não, graças aoencapsulamentodosnossosdados.
5.3GETTERSESETTERS 67
CUIDADOCOMOSGETTERSESETTERS!
Comojádito,nãodevemoscriargettersesetterssemummotivoexplicito.NoblogdaCaelumháumartigoqueilustrabemessescasos:
http://blog.caelum.com.br/2006/09/14/nao-aprender-oo-getters-e-setters/
Quandousamosapalavrachavenew,estamosconstruindoumobjeto.Semprequandoonew é
chamado, ele executa o construtor da classe. O construtor da classe é um bloco declarado com omesmonomequeaclasse:
classConta{Stringtitular;intnumero;doublesaldo;
//construtorConta(){System.out.println("Construindoumaconta.");}
//..}
Então,quandofizermos:
Contac=newConta();
Amensagem"construindoumaconta"aparecerá.Écomoumarotinadeinicializaçãoqueéchamadasemprequeumnovoobjetoécriado.Umconstrutorpodeparecer,masnãoéummétodo.
OCONSTRUTORDEFAULT
Atéagora,asnossasclassesnãopossuíamnenhumconstrutor.Entãocomoéqueerapossíveldarnew,setodonewchamaumconstrutorobrigatoriamente?
Quando você não declara nenhum construtor na sua classe, o Java cria um para você. Esseconstrutoréoconstrutordefault,elenãorecebenenhumargumentoeocorpodeleévazio.
Apartirdomomentoquevocêdeclaraumconstrutor,oconstrutordefaultnãoémaisfornecido.
O interessante é queumconstrutor pode receber umargumento, podendo assim inicializar algum
5.4CONSTRUTORES
68 5.4CONSTRUTORES
tipodeinformação:
classConta{Stringtitular;intnumero;doublesaldo;
//construtorConta(Stringtitular){this.titular=titular;}
//..}
Esse construtor recebe o titular da conta. Assim, quando criarmos uma conta, ela já terá umdeterminadotitular.
Stringcarlos="Carlos";Contac=newConta(carlos);System.out.println(c.titular);
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Tudoestavafuncionandoatéagora.Paraqueutilizamosumconstrutor?
Aideiaébemsimples.Setodacontaprecisadeumtitular,comoobrigartodososobjetosqueforemcriadosaterumvalordessetipo?BastacriarumúnicoconstrutorquerecebeessaString!
O construtor se resume a isso! Dar possibilidades ou obrigar o usuário de uma classe a passarargumentosparaoobjetoduranteoprocessodecriaçãodomesmo.
Porexemplo,nãopodemosabrirumarquivopara leiturasemdizerqualéonomedoarquivoquedesejamos ler! Portanto, nada mais natural que passar uma String representando o nome de um
arquivonahoradecriarumobjetodotipodeleituradearquivo,equeissosejaobrigatório.
EditoraCasadoCódigocomlivrosdeumaformadiferente
5.5ANECESSIDADEDEUMCONSTRUTOR
5.5ANECESSIDADEDEUMCONSTRUTOR 69
Vocêpodetermaisdeumconstrutornasuaclassee,nomomentodonew,oconstrutorapropriado
seráescolhido.
CONSTRUTOR:UMMÉTODOESPECIAL?
Umconstrutornão é ummétodo.Algumas pessoas o chamam de ummétodo especial,masdefinitivamentenãoé,jáquenãopossuiretornoesóéchamadoduranteaconstruçãodoobjeto.
CHAMANDOOUTROCONSTRUTOR
Um construtor só pode rodar durante a construção do objeto, isto é, você nunca conseguiráchamaroconstrutoremumobjetojáconstruído.Porém,duranteaconstruçãodeumobjeto,vocêpodefazercomqueumconstrutorchameoutro,paranãoterdeficarcopiandoecolando:
classConta{Stringtitular;intnumero;doublesaldo;
//construtorConta(Stringtitular){//fazmaisumasériedeinicializaçõeseconfiguraçõesthis.titular=titular;}
Conta(intnumero,Stringtitular){this(titular);//chamaoconstrutorquefoideclaradoacimathis.numero=numero;}
//..}
Existeumoutromotivo,ooutroladodosconstrutores:facilidade.Àsvezes,criamosumconstrutorquerecebediversosargumentosparanãoobrigarousuáriodeumaclasseachamardiversosmétodosdotipo'set'.
NonossoexemplodoCPF,podemosforçarqueaclasseClienterecebanomínimooCPF,dessa
maneiraumClientejáseráconstruídoecomumCPFválido.
70 5.5ANECESSIDADEDEUMCONSTRUTOR
JAVABEAN
Quando criamos uma classe com todos os atributos privados, seus getters e setters e umconstrutorvazio(padrão),naverdadeestamoscriandoumJavaBean(masnãoconfundacomEJB,queéEnterpriseJavaBeans).
Nossobancotambémquercontrolaraquantidadedecontasexistentesnosistema.Comopoderíamosfazeristo?Aideiamaissimples:
Contac=newConta();totalDeContas=totalDeContas+1;
Aqui, voltamos em um problema parecido com o da validação de CPF. Estamos espalhando umcódigo por toda aplicação, e quem garante que vamos conseguir lembrar de incrementar a variáveltotalDeContastodavez?
Tentamosentão,passarparaaseguinteproposta:
classConta{privateinttotalDeContas;//...
Conta(){this.totalDeContas=this.totalDeContas+1;}}
Quandocriarmosduascontas,qualseráovalordototalDeContasdecadaumadelas?Vaiser1.
Poiscadaumatemessavariável.Oatributoédecadaobjeto.
Seria interessante então, que essa variável fosseúnica, compartilhada por todos os objetos dessaclasse.Dessamaneira,quandomudasseatravésdeumobjeto,ooutroenxergariaomesmovalor.Parafazerissoemjava,declaramosavariávelcomostatic.
privatestaticinttotalDeContas;
Quandodeclaramosumatributocomostatic,elepassaanãosermaisumatributodecadaobjeto,
esimumatributodaclasse,a informaçãoficaguardadapelaclasse,nãoémaisindividualparacadaobjeto.
Paraacessarmosumatributoestático,nãousamosapalavrachavethis,massimonomedaclasse:
classConta{privatestaticinttotalDeContas;//...
5.6ATRIBUTOSDECLASSE
5.6ATRIBUTOSDECLASSE 71
Conta(){Conta.totalDeContas=Conta.totalDeContas+1;}}
Já que o atributo é privado, como podemos acessar essa informação a partir de outra classe?Precisamosdeumgetterparaele!
classConta{privatestaticinttotalDeContas;//...
Conta(){Conta.totalDeContas=Conta.totalDeContas+1;}
publicintgetTotalDeContas(){returnConta.totalDeContas;}}
Comofazemosentãoparasaberquantascontasforamcriadas?
Contac=newConta();inttotal=c.getTotalDeContas();
Precisamoscriarumacontaantesdechamarométodo!Issonãoélegal,poisgostaríamosdesaberquantascontasexistemsemprecisarteracessoaumobjetoconta.Aideiaaquiéamesma,transformaressemétodoquetodoobjetocontatememummétododetodaaclasse.Usamosapalavrastaticde
novo,mudandoométodoanterior.
publicstaticintgetTotalDeContas(){returnConta.totalDeContas;}
Paraacessaressenovométodo:
inttotal=Conta.getTotalDeContas();
ReparequeestamoschamandoummétodonãocomumareferênciaparaumaConta,esimusando
onomedaclasse.
MÉTODOSEATRIBUTOSESTÁTICOS
Métodoseatributosestáticossópodemacessaroutrosmétodoseatributosestáticosdamesmaclasse,oquefaztodosentidojáquedentrodeummétodoestáticonãotemosacessoàreferênciathis,poisummétodoestáticoéchamadoatravésdaclasse,enãodeumobjeto.
Ostaticrealmentetrazum"cheiro"procedural,porémemmuitasvezesénecessário.
72 5.6ATRIBUTOSDECLASSE
Emalgumasempresas,oUMLéamplamenteutilizado.Àsvezes,oprogramadorrecebeoUMLjápronto, completo, e só deve preencher a implementação, devendo seguir à risca oUML.O quevocêachadessaprática?Quaisasvantagensedesvantagens.
Se uma classe só tem atributos e métodos estáticos, que conclusões podemos tirar? O que lhepareceummétodoestáticoemcasoscomoesses?
Nocasodeatributosbooleanos,pode-seusarnolugardogetosufixois.Dessamaneira,caso
tivéssemosumatributobooleanoligado,emvezdegetLigadopoderíamosterisLigado.
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
1. Adicioneomodificadordevisibilidade(private, senecessário)paracadaatributo emétododa
classeConta.TentecriarumaContanomainemodificaroulerumdeseusatributosprivados.
Oqueacontece?
2. CrieapenasosgettersesettersnecessáriosdasuaclasseConta.Pensesempreseéprecisocriar
cadaumdeles.Porexemplo:
classConta{privateStringtitular;
//...
publicStringgetTitular(){returnthis.titular;}
publicvoidsetTitular(Stringtitular){this.titular=titular;
5.7UMPOUCOMAIS...
JáconheceoscursosonlineAlura?
5.8EXERCÍCIOS:ENCAPSULAMENTO,CONSTRUTORESESTATIC
5.7UMPOUCOMAIS... 73
}}
Nãocopieecole!Aproveiteparapraticarsintaxe.LogopassaremosausaroEclipseeaísimteremosprocedimentosmaissimplesparaestetipodetarefa.
ReparequeométodocalculaRendimentoparecetambémumgetter.Aliás,seriacomumalguém
nomeá-lodegetRendimento.Gettersnãoprecisamapenasretornaratributos.Elespodemtrabalhar
comessesdados.
3. ModifiquesuasclassesqueacessamemodificamatributosdeumaContaparautilizarosgetterse
settersrecémcriados.
Porexemplo,ondevocêencontra:
c.titular="Batman";System.out.println(c.titular);
passapara:
c.setTitular("Batman");System.out.println(c.getTitular());
4. FaçacomquesuaclasseContapossareceber,opcionalmente,onomedotitulardaContadurante
acriaçãodoobjeto.Utilizeconstrutoresparaobteresseresultado.
Dica:utilizeumconstrutorsemargumentos também,paraocasodeapessoanãoquererpassarotitulardaConta.
Seriaalgocomo:
classConta{publicConta(){//construtorsemargumentos}
publicConta(Stringtitular){//construtorquerecebeotitular}}
Porquevocêprecisadoconstrutorsemargumentosparaqueapassagemdonomesejaopcional?
5. (opcional)AdicioneumatributonaclasseContade tipointquese chama identificador.Esse
identificador deve ter um valor único para cada instância do tipo Conta. A primeira Conta
instanciada tem identificador 1, a segunda 2, e assim por diante. Você deve utilizar os recursosaprendidosaquipararesolveresseproblema.
Crieumgetterparaoidentificador.Devemosterumsetter?
6. (opcional)Comogarantirquedatascomo31/2/2012nãosejamaceitaspelasuaclasseData?
74 5.8EXERCÍCIOS:ENCAPSULAMENTO,CONSTRUTORESESTATIC
7. (opcional) Suponha que temos a classe PessoaFisica que tem um CPF como atributo. Como
garantir que pessoa física alguma tenhaCPF invalido, nem seja criada PessoaFisica sem cpf
inicial?(Suponhaquejáexisteumalgoritmodevalidaçãodecpf:bastapassarocpfporummétodovalida(Stringx)...)
1. Porqueessecódigonãocompila?
classTeste{intx=37;publicstaticvoidmain(String[]args){System.out.println(x);}}
2. ImaginequetenhaumaclasseFabricaDeCarroequerogarantirquesóexisteumobjetodessetipo
emtodaamemória.NãoexisteumapalavrachaveespecialparaistoemJava,entãoteremosdefazernossa classe de talmaneira que ela respeite essa nossa necessidade. Como fazer isso? (pesquise:singletondesignpattern)
5.9DESAFIOS
5.9DESAFIOS 75
CAPÍTULO6
"Dá-seimportânciaaosantepassadosquandojánãotemosnenhum."--FrançoisChateaubriand
Neste capítulo, você será apresentado aoAmbiente deDesenvolvimentoEclipse e suas principaisfuncionalidades.
OEclipse(http://www.eclipse.org)éumaIDE(integrateddevelopmentenvironment).DiferentedeumaRAD,ondeoobjetivoédesenvolveromaisrápidopossívelatravésdoarrastar-e-soltardomouse,onde montanhas de código são gerados em background, uma IDE te auxilia no desenvolvimento,evitandoseintrometerefazermuitamágica.
O Eclipse é a IDE líder de mercado. Formada por um consórcio liderado pela IBM, possui seucódigolivre.
Veremos aqui os principais recursos do Eclipse. Você perceberá que ele evita ao máximo teatrapalhareapenasgeratrechosdecódigosóbvios,sempreaoseucomando.Existemtambémcentenasde plugins gratuitos para gerar diagramasUML, suporte a servidores de aplicação, visualizadores debancodedadosemuitosoutros.
BaixeoEclipsedo siteoficialhttp://www.eclipse.org.Apesarde ser escrito emJava, abibliotecagráficausadanoEclipse,chamadaSWT,usacomponentesnativosdosistemaoperacional.Porissovocêdevebaixaraversãocorrespondenteaoseusistemaoperacional.
Descompacteoarquivoepronto,bastarodaroexecutável.
OUTRASIDES
UmaoutraIDEopensourcefamosaéoNetbeans,daOracle.(http://www.netbeans.org).
Alémdessas,Oracle,Borland e a própria IBMpossuem IDEs comerciais e algumas versõesmaisrestritasdeusolivre.
AempresaJetBrainsdesenvolveoIntelliJIDEA,umaIDEpagaquetemganhomuitosadeptos.
ECLIPSEIDE
6.1OECLIPSE
76 6ECLIPSEIDE
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoJavaeOrientaçãoaObjetos
CliquenoíconedoEclipsenoseuDesktop.
Aprimeiraperguntaqueeletefazéqueworkspacevocêvaiusar.Workspacedefineodiretórioemqueassuasconfiguraçõespessoaiseseusprojetosserãogravados.
Vocêpodedeixarodiretóriopré-definido.
Logoemseguida,umateladeWelcomeseráaberta,ondevocê temdiversos linkspara tutoriaiseajuda.CliqueemWorkbench.
VocêpodetambémfazerocursodatadessaapostilanaCaelum
6.2APRESENTANDOOECLIPSE
6.2APRESENTANDOOECLIPSE 77
Feche a tela deWelcome e você verá a tela abaixo. Nesta tela, destacamos as Views (em linhacontínua)easPerspectives(emlinhapontilhada)doEclipse.
6.3VIEWSEPERSPECTIVE
78 6.3VIEWSEPERSPECTIVE
Mude para a perspectiva Resource, clicando no ícone ao lado da perspectiva Java, selecionandoOtheredepoisResource.Nestemomento,trabalharemoscomestaperspectiva,antesdadeJava,poiselapossuiumconjuntodeViewsmaissimples.
AViewNavigatormostraaestruturadediretórioassimcomoestánosistemadearquivos.AViewOutlinemostraumresumodasclasses,interfaceseenumeraçõesdeclaradasnoarquivojavaatualmenteeditado(servetambémparaoutrostiposdearquivos).
No menuWindow -> Show View -> Other, você pode ver as dezenas de Views que já vem
6.3VIEWSEPERSPECTIVE 79
embutidasnoEclipse.Acostume-seasempreprocurarnovasViews,elaspodemteajudaremdiversastarefas.
VáemFile->New->Project.SelecionaJavaProjectecliqueemNext.
6.4CRIANDOUMPROJETONOVO
80 6.4CRIANDOUMPROJETONOVO
Crieumprojetochamadofj11-contas.
VocêpodechegarnessamesmatelaclicandocomobotãodadiretanoespaçodaViewNavigatoreseguindoomesmomenu.Nestatela,configureseuprojetocomonatelaabaixo:
Isto é, marque "create separate source and output folders", desta maneira seus arquivos java earquivosclassestarãoemdiretóriosdiferentes,paravocêtrabalhardeumamaneiramaisorganizada.
6.4CRIANDOUMPROJETONOVO 81
Clique em Finish. O Eclipse pedirá para trocar a perspectiva para Java; escolha "No" parapermaneceremResource.NaViewNavigator,vocêveráonovoprojetoesuaspastasearquivos:
VamosiniciarnossoprojetocriandoaclasseConta.Paraisso,váemFile->New->Other->Class.CliqueemNextecrieaclasseseguindoatelaabaixo:
CliqueemFinish.OEclipsepossuidiversoswizards,masusaremosomínimodeles.Ointeressanteé usar o codeassist e quick fixes que a ferramenta possui e veremos em seguida. Não se atente àsmilharesdeopçõesdecadawizard,apartemaisinteressantedoEclipsenãoéessa.
EscrevaométododepositacomoabaixoenotequeoEclipsereclamadeerroemthis.saldo
poisesteatributonãoexiste.
82 6.4CRIANDOUMPROJETONOVO
VamosusarorecursodoEclipsedequickfix.ColoqueocursoremcimadoerroeaperteCtrl+1.
O Eclipse sugerirá possíveis formas de consertar o erro; uma delas é, justamente, criar o camposaldonaclasseConta,queénossoobjetivo.Cliquenestaopção.
Este recurso de quick fixes, acessível pelo Ctrl+1, é uma das grandes facilidades do Eclipse e éextremamentepoderoso.Atravésdele épossível corrigirboapartedoserrosnahoradeprogramare,comofizemos,economizaradigitaçãodecertoscódigosrepetitivos.Nonossoexemplo,nãoprecisamoscriarocampoantes;oEclipsefazissoparanós.Eleatéacertaatipagem,jáqueestamossomandoeleaumdouble.Oprivateécolocadopormotivosquejáestudamos.
VáaomenuFile->Saveparagravar.Control+Stemomesmoefeito.
6.4CRIANDOUMPROJETONOVO 83
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Seuslivrosdetecnologiaparecemdoséculopassado?
6.5CRIANDOOMAIN
84 6.5CRIANDOOMAIN
CrieumanovaclassechamadaPrincipal.Vamos colocar ummétodomain para testar nossa
Conta.Emvezdedigitartodoométodomain,vamosusarocodeassistdoEclipse.EscrevasómaineaperteCtrl+Espaçologoemseguida.
OEclipsesugeriráacriaçãodométodomaincompleto;selecioneestaopção.Ocontrol+espaçoé
chamadodecodeassist.Assimcomoosquick fixessãodeextrema importância.Experimenteusarocodeassistemdiversoslugares.
Dentrodométodomain,comeceadigitaroseguintecódigo:
Contaconta=newConta();conta.deposita(100.0);
Observe que, na hora de invocar o método sobre o objeto conta, o Eclipse sugere os métodospossíveis.Esterecursoébastanteútil,principalmentequandoestivermosprogramandocomclassesquenãosãoasnossas,comodaAPIdoJava.OEclipseacionaesterecursoquandovocêdigitaopontologoapósumobjeto(evocêpodeusaroCtrl+Espaçoparaacioná-lo).
Vamos imprimir o saldo com System.out.println. Mas, mesmo nesse código, o Eclipse nos
ajuda.EscrevasysoeaperteCtrl+EspaçoqueoEclipseescreveráSystem.out.println()paravocê.
Paraimprimir,chameoconta.getSaldo():
System.out.println(conta.getSaldo());
NotequeoEclipseacusaráerroemgetSaldo()porqueestemétodonãoexistenaclasseConta.
VamosusarCtrl+1emcimadoerroparacorrigiroproblema:
6.5CRIANDOOMAIN 85
OEclipsesugerecriarummétodogetSaldo()naclasseConta.Selecioneestaopçãoeométodo
seráinseridoautomaticamente.
publicObjectgetSaldo(){//TODOAuto-generatedmethodstubreturnnull;}
Elegeraummétodonãoexatamentecomoqueríamos,poisnemsemprehácomooEclipse terdeantemãoinformaçõessuficientesparaqueeleacerteaassinaturadoseumétodo.ModifiqueométodogetSaldocomosegue:
publicdoublegetSaldo(){returnthis.saldo;}
EssespequenosrecursosdoEclipsesãodeextremautilidade.Dessamaneira,vocêpodeprogramarsem se preocupar commétodos que ainda não existem, já que a qualquermomento ele pode gerar oesqueleto(apartedaassinaturadométodo).
Vamosrodarométodomaindessanossaclasse.NoEclipse,cliquecomobotãodireitonoarquivo
Principal.javaeváemRunas...JavaApplication.
6.6EXECUTANDOOMAIN
86 6.6EXECUTANDOOMAIN
OEclipseabriráumaViewchamadaConsoleondeseráapresentadaasaídadoseuprograma:
Quando você precisar rodar de novo, basta clicar no ícone verde de play na toolbar, que roda oprogramaanterior.Aoladodesseíconetemumasetinhaondesãolistadosos10últimosexecutados.
OEclipse possuimuitos atalhos úteis para o programador. Semdúvida os 3mais importantes deconheceredepraticarsão:
Ctrl+1Acionaoquickfixescomsugestõesparacorreçãodeerros.
Ctrl+EspaçoCompletacódigos
Ctrl+3Acionamododedescobertademenu.ExperimentedigitarCtrl+3edepoisdigitarggaseenter.OuentãodeCtrl+3edigitenewclass.
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/
6.7PEQUENOSTRUQUES
6.7PEQUENOSTRUQUES 87
Existemdezenasdeoutros.DentreosmaisutilizadospelosdesenvolvedoresdaCaelum,escolhemososseguintesparacomentar:
Ctrl+F11rodaaúltimaclassequevocêrodou.Éomesmoqueclicarnoíconeverdequepareceumbotãodeplaynabarradeferramentas.
Ctrl + PgUp eCtrl + PgDown Navega nas abas abertas. Útil quando estiver editando váriosarquivosaomesmotempo.
Ctrl+Shift+FFormataocódigosegundoasconvençõesdoJava
Ctrl+MExpande aViewatual para a tela toda (mesmoefeito dedar dois cliquesno títulodaView)
Ctrl+Shift+LExibetodososatalhospossíveis.
Ctrl+OExibeumoutlinepararápidanavegação
Alt+Shift+XedepoisJRodaomaindaclasseatual.Péssimoparapressionar!Maisfácilvocê
digitarControl+3edepoisdigitarRun!.AbusedesdejádoControl+3
Veremosmaisnodecorrerdocurso,emespecialquandovirmospacotes.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
1. Crieoprojetofj11-contas.Vocêpodeusaroatalhocontrol+nouentãoirnomenuFile->New
->Project...->JavaProject.
2. Dentro do projeto fj11-contas , crie a classe Conta . Uma conta deve ter as seguintes
informações:saldo(double),titular(String),numero (int)eagencia (String).Na classe
Conta, crie osmétodosdeposita esaca comonos capítulos anteriores.Crie tambémuma
Agoraéamelhorhoradeaprenderalgonovo
6.8EXERCÍCIOS:ECLIPSE
88 6.8EXERCÍCIOS:ECLIPSE
classeTesteDaContacomomain e instancieumaconta.Destavez, tenteabusardocontrol+
espaçoecontrol+1.
Porexemplo:
publ<ctrlespaco>v<ctrlespaco>deposita(do<ctrlespaço>valor){
Reparequeatémesmonomesdevariáveis,elecriaparavocê!Acompanheasdicasdoinstrutor.
Muitasvezes,aocriarmosumobjeto,nemmesmodeclaramosavariável:
newConta();
Vánessalinhaedêcontrol+1.Elevaisugeriredeclararáavariávelpravocê.
3. Imaginequequeremoscriarumsetterdo titularparaaclasseConta.Dentroda classeConta,
digite:
setTit<ctrl+espaco>
OutraformaparacriarosgetterseossettersparaosatributosdaclasseConta,éutilizaroatalho
control+3enacaixadeseleçãodigiteggas,iniciaisdeGenerateGettersandSetters!
OBS:Nãocrieumsetterparaoatributosaldo!
4. Váparaaclasseque temomain e segureoCONTROLapertadoenquantovocêpassaomouse
sobreoseucódigo.Reparequetudovirouhyperlink.CliqueemummétodoquevocêestáinvocandonaclasseConta.
Vocêpodeconseguiromesmoefeito,deabriroarquivonoqualométodo foideclarado, deumamaneira ainda mais prática: sem usar o mouse, quando o cursor estiver sobre o que você queranalisar,simplesmentecliqueF3.
5. Dêumcliquedadireitaemumarquivononavigator.EscolhaCompareWith->LocalHistory.Oqueéestatela?
6.8EXERCÍCIOS:ECLIPSE 89
6. UseoControl+Shift+Fparaformataroseucódigo.Dessamaneira,elevaiarrumarabagunçadeespaçamentoeentersdoseucódigo.
7. (opcional)Oquesãoosarquivos.projecte.classpath?Leiaoconteúdodeles.
8. (opcional)Cliquedadireitanoprojeto,propriedades.ÉumadastelasmaisimportantesdoEclipse,onde você pode configurar diversas informações para o seu projeto, como compilador, versões,formatadoreoutros.
90 6.8EXERCÍCIOS:ECLIPSE
ExisteummenunoEclipsechamadoRefactor.Eletemopçõesbastanteinteressantesparaauxiliarnaalteraçãodecódigoparamelhorarorganizaçãoouclareza.Porexemplo,umadesuasfuncionalidadesétornarpossívelmudaronomedeumavariável,métodooumesmoclassedeformaqueumaalteração(emumlugarsódosistema)atualizetodasasoutrasvezesqueusavamonomeantigo.
Usar bons nomes no seu código é um excelente começo para mantê-lo legível e fácil de darmanutenção! Mas o assunto "Refatoração" não para por aí: quebrar métodos grandes em menores,dividirclassesgrandesemalgumaspequenasemaisconcisas,melhoraroencapsulamento...todasessassãoformasderefatoração.EessemenudoEclipsenosajudaafazerváriasdelas.
6.9DISCUSSÃOEMAULA:REFACTORING
6.9DISCUSSÃOEMAULA:REFACTORING 91
CAPÍTULO7
"Umadiscussãoprolongadasignificaqueambasaspartesestãoerradas"--Voltaire
Aotérminodessecapítulo,vocêserácapazde:
separarsuasclassesempacotes;preparararquivossimplesparadistribuição.
Nestecapítulo,aconselhamosquevocêpasseausaroEclipse.VocêjátemconhecimentosuficientedoserrosdecompilaçãodojavaceagorapodeaprenderasfacilidadesqueoEclipsetetrazaoajudar
vocênocódigocomoschamadosquickfixesequickassists.
Quando um programador utiliza as classes feitas por outro, surge um problema clássico: comoescreverduasclassescomomesmonome?
Porexemplo:podeserqueaminhaclassedeDatafuncionedeumcertojeito,eaclasseDatade
umcolega,deoutro jeito.PodeserqueaclassedeDatadeumabiblioteca funcione aindadeumaterceiramaneiradiferente.
Comopermitir que tudo isso realmente funcione?Como controlar quemquer usar qual classe deData?
Pensando um pouco mais, notamos a existência de um outro problema e da própria solução: osistema operacional não permite a existência de dois arquivos com o mesmo nome sob o mesmodiretório,portantoprecisamosorganizarnossasclassesemdiretóriosdiferentes.
Osdiretóriosestãodiretamenterelacionadosaoschamadospacotesecostumamagruparclassesdefuncionalidadessimilaresourelacionadas.
Por exemplo, no pacote java.util temos as classes Date , SimpleDateFormat e
GregorianCalendar;todaselastrabalhamcomdatasdeformasdiferentes.
PACOTES-ORGANIZANDOSUASCLASSESEBIBLIOTECAS
7.1ORGANIZAÇÃO
92 7PACOTES-ORGANIZANDOSUASCLASSESEBIBLIOTECAS
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
SeaclasseClienteestánopacotecontas,eladeveráestarnodiretóriocomomesmonome:
contas. Se ela se localiza no pacote br.com.caelum.contas , significa que está no diretório
br/com/caelum/contas.
AclasseCliente,queselocalizanesseúltimodiretóriomencionado,deveserescritadaseguinte
forma:
packagebr.com.caelum.contas;
classCliente{//...}
Ficafácilnotarqueapalavrachavepackageindicaqualopacote/diretóriocontémestaclasse.
Umpacotepodeconternenhumoumaissubpacotese/ouclassesdentrodele.
EditoraCasadoCódigocomlivrosdeumaformadiferente
7.2DIRETÓRIOS
7.2DIRETÓRIOS 93
PADRÃODANOMENCLATURADOSPACOTES
Opadrãodasunparadarnomeaospacotesérelativoaonomedaempresaquedesenvolveuaclasse:
br.com.nomedaempresa.nomedoprojeto.subpacotebr.com.nomedaempresa.nomedoprojeto.subpacote2br.com.nomedaempresa.nomedoprojeto.subpacote2.subpacote3
Ospacotessópossuemletrasminúsculas,nãoimportaquantaspalavrasestejamcontidasnele.Essepadrãoexisteparaevitaraomáximooconflitodepacotesdeempresasdiferentes.
Asclassesdopacotepadrãodebibliotecasnãoseguemessanomenclatura,que foidadaparabibliotecasdeterceiros.
Para usar uma classe do mesmo pacote, basta fazer referência a ela como foi feito até agorasimplesmenteescrevendoopróprionomedaclasse.SequisermosqueaclasseBancofiquedentrodo
pacotebr.com.caelum.contas,eladeveserdeclaradaassim:
packagebr.com.caelum.contas;
classBanco{Stringnome;}
ParaaclasseClienteficarnomesmopacote,seguimosamesmafórmula:
packagebr.com.caelum.contas;
classCliente{Stringnome;Stringendereco;}
AnovidadechegaaotentarutilizaraclasseBanco(ouCliente)emumaoutraclassequeesteja
foradessepacote,porexemplo,nopacotebr.com.caelum.contas.main:
packagebr.com.caelum.contas.main;
classTesteDoBanco{
publicstaticvoidmain(String[]args){br.com.caelum.contas.BancomeuBanco=newbr.com.caelum.contas.Banco();meuBanco.nome="BancodoBrasil";System.out.println(meuBanco.nome);}
}
7.3IMPORT
94 7.3IMPORT
ReparequeprecisamosreferenciaraclasseBancocomtodoonomedopacotenasuafrente.Esseé
oconhecidoFullyQualifiedNamedeumaclasse.Emoutraspalavras,esseéoverdadeironomedeumaclasse,porissoduasclassescomomesmonomeempacotesdiferentesnãoconflitam.
Mesmoassim,aotentarcompilaraclasseanterior,surgeumerroreclamandoqueaclasseBanco
nãoestávisível.
Acontecequeasclassessósãovisíveisparaoutrasnomesmopacotee,parapermitirqueaclasseTesteDoBanco veja e acesse a classe Banco em outro pacote, precisamos alterar essa última e
transformá-laempública:
packagebr.com.caelum.contas;
publicclassBanco{Stringnome;}
Apalavra chavepublic libera o acesso para classes de outros pacotes.Domesmo jeito que o
compilador reclamou que a classe não estava visível, ele reclama que o atributo/variável membrotambém não está. É fácil deduzir como resolver o problema: utilizando novamente o modificadorpublic:
packagebr.com.caelum.contas;
publicclassBanco{publicStringnome;}
Podemos testar nosso exemplo anterior, lembrando que utilizar atributos como público não trazencapsulamentoeestáaquicomoilustração.
VoltandoaocódigodoTesteDoBanco, é necessário escrever todoopacote para identificar qual
classequeremosusar?Oexemploqueusamosficoubemcomplicadodeler:
br.com.caelum.contas.BancomeuBanco=newbr.com.caelum.contas.Banco();
Existe umamaneiramais simples de se referenciar a classeBanco: basta importá-la dopacotebr.com.caelum.contas:
packagebr.com.caelum.contas.main;
//parapodermosreferenciar//aBancodiretamenteimportbr.com.caelum.contas.Banco;
publicclassTesteDoBanco{
publicstaticvoidmain(String[]args){BancomeuBanco=newBanco();meuBanco.nome="BancodoBrasil";}
7.3IMPORT 95
}
Issofazcomquenãoprecisemosnosreferenciarutilizandoofullyqualifiedname,podendoutilizarBancodentrodonossocódigoemvezdeescreverolongobr.com.caelum.contas.Banco.
PACKAGE,IMPORT,CLASS
Émuito importantemanter aordem!Primeiro, apareceuma (ounenhuma)vezopackage;
depois,podeaparecerumoumaisimports;e,porúltimo,asdeclaraçõesdeclasses.
IMPORTX.Y.Z.*;
É possível "importar um pacote inteiro" (todas as classes do pacote, exceto os subpacotes)atravésdocoringa*:
importjava.util.*;
Importar todas as classes de umpacote não implica em perda de performance em tempo deexecução,maspode trazerproblemascomclassesdemesmonome!Alémdisso, importardeumemuméconsideradoboaprática,poisfacilitaaleituraparaoutrosprogramadores.UmaIDEcomooEclipsejávaifazerissoporvocê,assimcomoaorganizaçãoemdiretórios.
OsmodificadoresdeacessoexistentesemJavasãoquatro,eatéomomentojávimostrês,massóexplicamosdois.
public - Todos podem acessar aquilo que for definido como public . Classes, atributos,
construtoresemétodospodemserpublic.
protected-Aquiloqueéprotectedpodeseracessadoportodasasclassesdomesmopacotee
por todas as classes que o estendam,mesmoque essas não estejamnomesmopacote. Somenteatributos,construtoresemétodospodemserprotected.
padrão(semnenhummodificador) -Senenhummodificador forutilizado, todas as classesdomesmopacotetêmacessoaoatributo,construtor,métodoouclasse.
private - A única classe capaz de acessar os atributos, construtores e métodos privados é a
própriaclasse.Classes,comoconhecemos,nãopodemserprivate,masatributos,construtorese
7.4ACESSOAOSATRIBUTOS,CONSTRUTORESEMÉTODOS
96 7.4ACESSOAOSATRIBUTOS,CONSTRUTORESEMÉTODOS
métodossim.
CLASSESPÚBLICAS
Paramelhororganizarseucódigo,oJavanãopermitemaisdeumaclassepúblicaporarquivoeoarquivodeveserNomeDaClasse.java.
Umavezqueoutrosprogramadoresirãoutilizaressaclasse,quandoprecisaremolharocódigodamesma,ficamaisfácilencontrá-lasabendoqueelaestánoarquivodemesmonome.
Classesaninhadaspodemserprotectedouprivate,masesseéumtópicoavançadoque
nãoseráestudadonessemomento.
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
VocêpodeusaraperspectivaJavadoEclipse.AviewprincipaldenavegaçãoéoPackageExplorer,queagrupaclassespelospacotesemvezdediretórios(vocêpodeusá-laemconjuntocomaNavigator,bastatambémabri-lapeloWindow/ShowView/PackageExplorer).
JáconheceoscursosonlineAlura?
7.5USANDOOECLIPSECOMPACOTES
7.5USANDOOECLIPSECOMPACOTES 97
Antes de movermos nossas classes, declare-as como públicas e coloque-as em seus respectivosarquivos:umarquivoparacadaclasse.
Vocêpodemoverumaclassedepacotearrastando-aparaodestinodesejado.ReparequeoEclipsejádeclarapackageseimportsnecessários:
98 7.5USANDOOECLIPSECOMPACOTES
NoEclipsenuncaprecisamosdeclararumimport,poiselesemprevaisugeririssoquandousarmos
oCtrl+Espaçononomedeumaclasse.
VocêtambémpodeusaroCtrl+1nocasodadeclaraçãodepacotepossuiralgumerro.
Atenção: utilize os recursos do Eclipse para realizar essas mudanças. Use a view package-
explorer,quevaiauxiliarbastanteamanipulaçãodosarquivosediretórios.Tambémutilizeosquick
fixesquandooEclipsereclamardosdiversosproblemasdecompilaçãoqueaparecerão.Épossívelfazeresse exercício inteiro semmodificar uma linhade códigomanualmente. Aproveite para praticar edescobriroEclipse,eviteusá-loapenascomoumeditordetexto.
Por exemplo, com o Eclipse nunca precisamos nos preocupar com os imports: ao usar o autocomplete,elejájogaoimportláemcima.E,sevocênãofezisso,elesugerecolocaroimport.
1. Selecionandoosrcdoseuprojeto,façactrl+NeescrevaPackageparaoseusistemadeContascomeçar a utilizar pacotes. Na janela de criação de pacotes escreva o nome completo do pacoteseguindo a convençãode códigodaSun, desdeobr, e oEclipse tratará de fazer a separaçãodaspastascorretamente.Cuidado:paraessecurso,osnomesdospacotesprecisamserosseguintes:
br.com.caelum.contas.main:colocaraclassecomométodomainaqui(oTeste)
7.6EXERCÍCIOS:PACOTES
7.6EXERCÍCIOS:PACOTES 99
br.com.caelum.contas.modelo:colocaraclasseConta
Antesdecorrigirqualquererrodecompilação,primeiromovatodasassuasclasses,semdeixarnenhumanopacotedefault.
2. Sevocêaindanãotiverseparadocadaclasseemumarquivo,essaéahorademudarisso.Coloquecadaclasseemseurespectivoarquivo.java.Façaissoindependentedeelaserpública:éumaboa
prática.
3. Casoocódigonãocompileprontamente, reparequepelomenosalgummétodoquedeclaramosépackage-private quando, na verdade, precisamos que ele seja public. O mesmo vale para as
classes:algumasdelasprecisarãoserpúblicas.
Se houver algumerro de compilação, use o recurso de quick fix doEclipse aqui: elemesmovaisugerirqueomodificadordeacessodeveserpúblico.Paraisso,useoctrl+1emcadaumdoserros,escolhendooquickfixmaisadequadoparaseuproblema.
4. (Opcional)AbraaviewNavigatorparavercomoficouosarquivosnosistemadearquivosdoseu
sistemaoperacional.Paraisso,usectrl+3,comeceadigitarNavigatoreescolhaaopçãodeabriressaview..
100 7.6EXERCÍCIOS:PACOTES
CAPÍTULO8
"Perdertempoemaprendercoisasquenãointeressam,priva-nosdedescobrircoisasinteressantes"--CarlosDrummonddeAndrade
Aotérminodessecapítulo,vocêserácapazde:
criaroJARdoseuaplicativo;colocarumJARnobuildpathdoseuprojeto;lerumjavadoc;criarojavadocdoseuaplicativo.
Assimqueumprogramaficapronto,émeiocomplicadoenviardezenasoucentenasdeclassesparacadaclientequequerutilizá-lo.
Ojeitomaissimplesdetrabalharcomumconjuntodeclassesécompactá-losemumarquivosó.OformatodecompactaçãopadrãoéoZIPcomaextensãodoarquivocompactadoJAR.
OARQUIVO.JAR
OarquivojarouJavaARchive,possuiumconjuntodeclasses(earquivosdeconfigurações)compactados, no estilo de um arquivo zip. O arquivo jar pode ser criado com qualquer
compactadorzipdisponívelnomercado,inclusiveoprogramajarquevemjuntocomoJDK.
Paracriarumarquivojardonossoprogramadebanco,bastairaodiretórioondeestãocontidasasclasseseusarocomandoaseguirparacriaroarquivobanco.jarcomtodasasclassesdospacotes
br.com.caelum.utilebr.com.caelum.banco:
jar-cvfbanco.jarbr/com/caelum/util/*.classbr/com/caelum/banco/*.class
Parausaressearquivobanco.jarpararodaroTesteDoBancobastarodarojavacomoarquivo
jarcomoargumento:
FERRAMENTAS:JAREJAVADOC
8.1ARQUIVOS,BIBLIOTECASEVERSÕES
8FERRAMENTAS:JAREJAVADOC 101
java-classpathbanco.jarbr.com.caelum.contas.main.TesteDoBanco
Paraadicionarmaisarquivos.jar,quepodemserbibliotecas,aoprogramabastarodarojavada
seguintemaneira:
java-classpathbiblioteca1.jar;biblioteca2.jarNomeDaClasse
ValelembrarqueopontoevírgulautilizadosóéválidoemambienteWindows.EmLinux,MaceoutrosUnix,éodoispontos(variadeacordocomosistemaoperacional).
Hátambémumarquivodemanifestoquecontéminformaçõesdoseujarcomo,porexemplo,qualclasseelevairodarquandoojarforchamado.Masnãosepreocupepois,comoEclipse,essearquivoégeradoautomaticamente.
BIBLIOTECAS
Diversas bibliotecas podem ser controladas de acordo com a versão por estarem semprecompactadasemumarquivo.jar.Bastaverificaronomedabiblioteca (porexemplolog4j-
1.2.13.jar)paradescobriraversãodela.
Então é possível rodar dois programas aomesmo tempo, cada umutilizando uma versão dabibliotecaatravésdoparâmetro-classpathdojava.
CRIANDOUM.JARAUTOMATICAMENTE
Existemdiversasferramentasqueservemparaautomatizaroprocessodedeploy,queconsisteemcompilar,gerardocumentação,bibliotecasetc.AsduasmaisfamosassãooANTeoMAVEN,ambossãoprojetosdogrupoApache.
OEclipsepodegerarfacilmenteumjar,porém,seoseubuildécomplexoeprecisaprepararecopiar uma série de recursos, as ferramentas indicadas acima possuem sofisticadasmaneiras derodarumscriptbatch.
102 8.1ARQUIVOS,BIBLIOTECASEVERSÕES
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoJavaeOrientaçãoaObjetos
Nesteexemplo,vamosgeraroarquivoJARdonossoprojetoapartirdoEclipse:
CliquecomobotãodireitoemcimadonomedoseuprojetoeselecioneaopçãoExport.
Na tela Export (como mostra a figura abaixo), selecione a opção "JAR file" e aperte o botão"Next".
VocêpodetambémfazerocursodatadessaapostilanaCaelum
8.2GERANDOOJARPELOECLIPSE
8.2GERANDOOJARPELOECLIPSE 103
Naopção"JARfile:",selecioneolocalquevocêdesejasalvaroarquivoJAR.Eaperte"Next".
Napróximatela,simplesmentecliqueemnext,poisnãohánenhumaconfiguraçãoaserfeita.
104 8.2GERANDOOJARPELOECLIPSE
Natelaabaixo,naopção"selecttheclassoftheapplicationentrypoint",vocêdeveescolherqualclasseseráaclassequevairodarautomaticamentequandovocêexecutaroJAR.
Entrenalinhadecomando:java-jarbanco.jar
É comum dar um nome mais significativo aos JARs, incluindo nome da empresa, do projeto eversão,comocaelum-banco-1.0.jar.
ComovamossaberoquecadaclassetemnoJava?Quaissãoseusmétodos,oqueelesfazem?
E, a partir da Internet, você pode acessar através do link:http://download.java.net/jdk8/docs/api/index.html
No site da Oracle, você pode (e deve) baixar a documentação das bibliotecas do Java,frequentementereferidacomo"javadoc"ouAPI(sendonaverdadeadocumentaçãodaAPI).
8.3JAVADOC
8.3JAVADOC 105
Nestadocumentação,noquadrosuperioresquerdo,vocêencontraospacotese,noinferioresquerdo,está a listagem das classes e interfaces do respectivo pacote (ou de todos, caso nenhum tenha sidoespecificado). Clicando-se em uma classe ou interface, o quadro da direita passa a detalhar todosatributosemétodos.
Reparequemétodoseatributosprivadosnãoestãoaí.Oimportanteédocumentaroquesuaclassefaz,enãocomoelafaz:detalhesdeimplementação,comoatributosemétodosprivados,nãointeressamaodesenvolvedorqueusaráasuabiblioteca(ou,aomenos,nãodeveriaminteressar).
Vocêtambémconseguegeraressejavadocapartirdalinhadecomando,comocomando:javadoc.
ParageraroJavadocapartirdoEclipseémuitosimples,sigaospassosabaixo:
Na barra de menu, selecione o menu Project, depois a opção "Generate Javadoc...". (apenasdisponívelseestivernaperspectivaJava,masvocêpodeacessaromesmowizardpeloexportdoprojeto).
8.4GERANDOOJAVADOC
106 8.4GERANDOOJAVADOC
Emseguida, aparecerãoasopçõesparageraradocumentaçãodoseu sistema, selecione todasasclassesdoseusistemaedeixeasoutrasopçõescomoestão.Nãoesqueçademarcarocaminhodaopção"Destination",poiséláqueestarásuadocumentação.
8.4GERANDOOJAVADOC 107
Abraadocumentaçãoatravésdocaminhoquevocêmarcoueabraoarquivo index.html,quevaichamarumapáginasemelhanteaessadafiguraabaixo.
Para colocarmos comentários na documentação, devemos adicionar ao código, sob forma decomentário,abrindootextocom/**efechandocom*/e,nasoutraslinhas,apenascolocando*.
Tambémpodemosdefiniroutrasinformaçõesnestetexto,como:autor,versão,parâmetros,retorno,etc.Adicionealgunscomentáriosaoseuprojetocomoabaixo:
/***ClasseresponsávelpormoldarasContasdoBanco**@authorManoelSantosdaSilva*/
publicclassConta{...}
Ouadicionealgunscomentáriosemalgummétodoseu:
/***Metodoqueincrementaosaldo.*@paramvalor*/
publicvoiddeposita(doublevalor){
108 8.4GERANDOOJAVADOC
...}
Vejacomoficou:
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Seuslivrosdetecnologiaparecemdoséculopassado?
8.5EXERCÍCIOS:JAREJAVADOC
8.5EXERCÍCIOS:JAREJAVADOC 109
1. Gereumjardoseusistemacomoarquivodemanifesto.Execute-ocomjava-jar:
java-jarcaelum-banco-1.0.jar
SeoWindowsouoLinux foi configuradopara trabalhar comaextensão .jar,bastavocêdarumduplo clique no arquivo, que ele será "executado": o arquivo Manifest será lido para que ele
descubraqualéaclassecommainqueoJavadeveprocessar.
2. GereoJavadocdoseusistema.Paraisso,váaomenuProject,depoisàopçãoGenerateJavadoc,seestivernaperspectivaJava.Senão,dêumcliquecomobotãodireitonoseuprojeto,escolhaExportedepoisjavadocesigaoprocedimentodescritonaúltimaseçãodestecapítulo.
IndependentedaperspectivaquevocêusanoEclipse,vocêtambémpodeusaroctrl+3ecomeçaraescreverJavaDoc,atéqueaopçãodeexportaroJavaDocapareça.
INTERFACEVERSUSIMPLEMENTAÇÃONOVAMENTE!
Repare que a documentação gerada não mostra o conteúdo dos métodos, nem atributos emétodosprivados!Issofazpartedaimplementação,eoqueimportaparaquemusaumabibliotecaéainterface:oqueelafaz.
Jásabemoscomodocumentarnossoprojetoegerarumjarparadistribuí-lomaselaaindanãotemuma interface gráfica do usuário. Se quisermos rodar o nosso sistema temos que executá-lo peloterminal com os valores hard-coded. Seria mais interessante que tivéssemos uma interface maisamigávelparaqueousuáriopudesse interagircomonossosistema.Aomesmotempo,nãoqueremosnospreocuparnessemomentoemcriartodasasclassespararepresentaressainterfacegráfica,queremosapenasutilizaralgojápronto.
Para isso, vamos importar uma biblioteca externa. O próprio Eclipse já nos dá suporte para aimportaçãodejars.Parafazerisso,bastairnomenuProject->Properties,selecionaraopçãoJavaBuildPath,depoisselecionaraabaLibrariese,finalmente,clicarnobotãoAddExternalJars... .Agoraésóselecionar o jar a ser importado e clicar emOpen.Clique emOknovamente para fechar a janela deimportaçãoepronto!Nossabibliotecajáestáprontaparaserutilizada.
1. Vamosimportarumjarquecontémainterfacegráficadousuárioparaonossosistemadecontas.
8.6IMPORTANDOUMJAREXTERNO
8.7EXERCÍCIOS:IMPORTANDOUMJAR
110 8.6IMPORTANDOUMJAREXTERNO
VánomenuProject->PropertiesSelecioneaopçãoJavaBuildPath
SelecioneaabaLibraries
CliquenobotãoAddExternalJars...
Selecioneoarquivofj11-lib-contas.jarlocalizadonapastadosarquivosdoscursos/11
CliquenobotãoOkparafecharajaneladeimportação
2. Para verificarmos que a importação deu certo, vamos chamar uma classe da biblioteca importadaparaexibirumajaneladeboas-vindas.
CrieumaclasseTestaJarnopacotebr.com.caelum.contas.main.
Crietambémométodomain.
3. Dentrodométodocriado,vamosinvocarométodomaindaclasseOlaMundo que existe no jar
importado.Seucódigodeveficardessamaneira:
packagebr.com.caelum.contas.main;
importbr.com.caelum.javafx.api.main.OlaMundo;
publicclassTestaJar{
publicstaticvoidmain(String[]args){OlaMundo.main(args);}}
NãoesqueçadeimportaraclasseOlaMundodopacotebr.com.caelum.javafx.api.main.Useo
atalhoctrl+shift+O.
8.7EXERCÍCIOS:IMPORTANDOUMJAR 111
4. Executeasuaaplicaçãoevejaseapareceuumajaneladeboas-vindascomoaseguir:
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
AgoraquejáimportamosoJarquecontémainterfacegráfica,vamosdarumaolhadanaprimeirateladonossosistema:
Agoraéamelhorhoradeaprenderalgonovo
8.8MANIPULANDOACONTAPELAINTERFACEGRÁFICA
112 8.8MANIPULANDOACONTAPELAINTERFACEGRÁFICA
Nestatela,podemosperceberquetemosbotõesparaasaçõesdecriaçãodeconta,saqueedepósito,quedevemutilizaraimplementaçãoexistenteemnossaclasseConta.
Se quisermos visualizar a tela, podemos criar um main que chamará a classe TelaDeContas
responsávelpelasuaexibição:
packagebr.com.caelum.contas.main;
importbr.com.caelum.javafx.api.main.TelaDeContas;
publicclassTestaContas{
publicstaticvoidmain(String[]args){TelaDeContas.main(args);}}
8.8MANIPULANDOACONTAPELAINTERFACEGRÁFICA 113
Aoexecutarmosaaplicaçãoocorreráumerro:
Masporqueesteerroocorreu?Acontecequeatelaprecisaconheceralguémquesaibaexecutarasaçõesdesaqueedepósitonaconta,queconsigabuscarosdadosdatelaparapopularaconta.Comonãotemosninguémquesaibafazeristoainda,ocorreuoerro.
VamosentãocriaraclasseManipuladorDeContasqueseráresponsávelporfazeresta"ponte"entre
atelaeaclassedeConta:
packagebr.com.caelum.contas;
publicclassManipuladorDeContas{
}
Agora,aoexecutarmosaaplicação,veremosqueatelaaparececomsucesso:
114 8.8MANIPULANDOACONTAPELAINTERFACEGRÁFICA
Esetentarmosclicarnobotãodecriaçãodeconta?Tambémocorreumerro!
8.8MANIPULANDOACONTAPELAINTERFACEGRÁFICA 115
DestavezoerroindicaquefaltaométodocriaContadentrodaclasseManipuladorDeContas.
Vamosentãocriá-lo:
publicclassManipuladorDeContas{
publicvoidcriaConta(){Contaconta=newConta();conta.setAgencia("1234");conta.setNumero(56789);conta.setTitular("Batman");}}
Paraconseguirmosobterasinformaçõesdatela,todososmétodosquecriaremosprecisamreceberumparâmetrodotipoEventoqueconteráasinformaçõesdigitadas.Mesmoquenãoutilizemoseste
parâmetro,precisamosrecebê-lo.
importbr.com.caelum.javafx.api.util.Evento;
publicclassManipuladorDeContas{
publicvoidcriaConta(Eventoevento){Contaconta=newConta();conta.setAgencia("1234");conta.setNumero(56789);conta.setTitular("Batman");}}
Setentarmosexecutaraaplicaçãoeclicarnobotãocriaconta,vemosqueagoranãoocorremaisnenhumerromasaomesmotempoosdadosdacontanãosãopopuladosna tela. Istoacontecepoisavariávelconta é apenas local,ou seja, ela sóexistedentrodométodocriaConta.Alémdisso se
quiséssemosdepositarumvalornaconta,emqualcontadepositaríamos?Elanãoévisívelparanenhum
116 8.8MANIPULANDOACONTAPELAINTERFACEGRÁFICA
outrométodo!
PrecisamosqueestavariávelsejaumatributodoManipuladorDeContas.Vamosalterar:
importbr.com.caelum.javafx.api.util.Evento;
publicclassManipuladorDeContas{
privateContaconta;
publicvoidcriaConta(Eventoevento){this.conta=newConta();this.conta.setAgencia("1234");this.conta.setNumero(56789);this.conta.setTitular("Batman");}}
Testandoagoraconseguimosverosdadosdacontanatela!
8.8MANIPULANDOACONTAPELAINTERFACEGRÁFICA 117
Só falta criarmos os métodos saca e deposita. Vamos começar implementando o método
deposita. Nele precisamos do valor digitado pelo usuário na tela e é pra isto que serve a classe
Evento. Se quisermos buscar um valor do tipo double, podemos invocar o método double
passandoonomedocampoquequeremosrecuperarcomoparâmetro.Comovaloremmãos,podemosentãopassá-loparaométododesejado.Nossométodofica:
importbr.com.caelum.javafx.api.util.Evento;
publicclassManipuladorDeContas{
//...
publicvoiddeposita(Eventoevento){doublevalorDigitado=evento.getDouble("valor");this.conta.deposita(valorDigitado);}}
Podemosfazeromesmoparaométodosaca:
importbr.com.caelum.javafx.api.util.Evento;
publicclassManipuladorDeContas{
//...
publicvoiddeposita(Eventoevento){doublevalorDigitado=evento.getDouble("valor");this.conta.deposita(valorDigitado);}
publicvoidsaca(Eventoevento){doublevalorDigitado=evento.getDouble("valor");this.conta.saca(valorDigitado);}}
Agoraconseguimosrodaraaplicaçãoechamarasaçõesdesaqueedepósitoqueosaldoéatualizadocomsucesso!
118 8.8MANIPULANDOACONTAPELAINTERFACEGRÁFICA
1. CrieaclasseManipuladorDeContasdentrodopacotebr.com.caelum.contas.Reparequeos
pacotes br.com.caelum.contas.main e br.com.caelum.contas.modelo são subpacotes do
pacotebr.com.caelum.contas,portantoopacotebr.com.caelum.contasjáexiste.Paracriara
classenestepacote,bastaselecioná-lonajaneladecriaçãodaclasse:
8.9EXERCÍCIOS:MOSTRANDOOSDADOSDACONTANATELA
8.9EXERCÍCIOS:MOSTRANDOOSDADOSDACONTANATELA 119
A classe ManipuladorDeContas fará a ligação da Conta com a tela, por isso precisaremos
declararumatributodotipoConta.
2. CrieométodocriaContaquerecebecomoparâmetroumobjetodotipoEvento.Instancieuma
contaparaoatributocontaecoloqueosvaloresdenumero,agenciaetitular.Algocomo:
publicvoidcriaConta(Eventoevento){this.conta=newConta();this.conta.setTitular("Batman");//façaomesmoparaosoutrosatributos}
3. Comacontainstanciada,agorapodemosimplementarasfuncionalidadesdesaqueedepósito.CrieométododepositaquerecebeumEvento,queéaclassequeretornaosdadosdatelanostipos
queprecisamos.Porexemplo,sequisermosovaloradepositarsabemosqueeleédotipodoublee
queonomedocamponatelaévalorentãopodemosfazer:
publicvoiddeposita(Eventoevento){doublevalorDigitado=evento.getDouble("valor");this.conta.deposita(valorDigitado);}
120 8.9EXERCÍCIOS:MOSTRANDOOSDADOSDACONTANATELA
4. Crie agora o método saca. Ele também deve receber um Evento nos mesmos moldes do
deposita.
5. Precisamos agora testar nossa aplicação, crie a classe TestaContas dentro do pacote
br.com.caelum.contascomummain.NelavamoschamaromaindaclasseTelaDeContas
quemostraráateladenossosistema.Nãoseesqueçadefazeroimportdestaclasse!
importbr.com.caelum.javafx.api.main.TelaDeContas;
publicclassTestaContas{
publicstaticvoidmain(String[]args){TelaDeContas.main(args);}}
Rodeaaplicação,crieacontaetentefazerasoperaçõesdesaqueedepósito.Tudodevefuncionarnormalmente.
8.9EXERCÍCIOS:MOSTRANDOOSDADOSDACONTANATELA 121
CAPÍTULO9
"Ohomemabsurdoéaquelequenuncamuda."--GeorgesClemenceau
Aotérminodessecapítulo,vocêserácapazde:
dizeroqueéherançaequandoutilizá-la;reutilizarcódigoescritoanteriormente;criarclassesfilhasereescrevermétodos;usartodoopoderqueopolimorfismodá.
Comotodaempresa,nossoBancopossuifuncionários.VamosmodelaraclasseFuncionario:
publicclassFuncionario{privateStringnome;privateStringcpf;privatedoublesalario;//métodosdevemviraqui}
Alémdeumfuncionáriocomum,hátambémoutroscargos,comoosgerentes.Osgerentesguardama mesma informação que um funcionário comum, mas possuem outras informações, além de terfuncionalidadesumpoucodiferentes.Umgerentenonossobancopossuitambémumasenhanuméricaquepermiteoacessoaosistemainternodobanco,alémdonúmerodefuncionáriosqueelegerencia:
publicclassGerente{privateStringnome;privateStringcpf;privatedoublesalario;privateintsenha;privateintnumeroDeFuncionariosGerenciados;
publicbooleanautentica(intsenha){if(this.senha==senha){System.out.println("AcessoPermitido!");returntrue;}else{System.out.println("AcessoNegado!");returnfalse;}
HERANÇA,REESCRITAEPOLIMORFISMO
9.1REPETINDOCÓDIGO?
122 9HERANÇA,REESCRITAEPOLIMORFISMO
}
//outrosmétodos}
PRECISAMOSMESMODEOUTRACLASSE?
PoderíamosterdeixadoaclasseFuncionariomaisgenérica,mantendonelasenhadeacesso,
e o número de funcionários gerenciados.Caso o funcionário não fosse umgerente, deixaríamosestesatributosvazios.
Essaéumapossibilidade,porémpodemoscomeçaratermuitoatributosopcionais,eaclasseficariaestranha.Eemrelaçãoaosmétodos?AclasseGerente temométodoautentica, que
nãofazsentidoexistiremumfuncionárioquenãoégerente.
Se tivéssemos um outro tipo de funcionário que tem características diferentes do funcionáriocomum,precisaríamoscriarumaoutraclasseecopiarocódigonovamente!
Além disso, se um dia precisarmos adicionar uma nova informação para todos os funcionários,precisaremospassarportodasasclassesdefuncionárioeadicionaresseatributo.Oproblemaacontecenovamentepornãocentralizarmosasinformaçõesprincipaisdofuncionárioemumúnicolugar!
Existeumjeito,emJava,derelacionarmosumaclassedetalmaneiraqueumadelasherdatudoqueaoutratem.Istoéumarelaçãodeclassemãeeclassefilha.Nonossocaso,gostaríamosdefazercomqueoGerentetivessetudoqueumFuncionariotem,gostaríamosqueelafosseumaextensão deFuncionario.Fazemosistoatravésdapalavrachaveextends.
publicclassGerenteextendsFuncionario{privateintsenha;privateintnumeroDeFuncionariosGerenciados;
publicbooleanautentica(intsenha){if(this.senha==senha){System.out.println("AcessoPermitido!");returntrue;}else{System.out.println("AcessoNegado!");returnfalse;}}
//setterdasenhaomitido}
Em todo momento que criarmos um objeto do tipo Gerente, este objeto possuirá também os
atributosdefinidosnaclasseFuncionario,poisumGerenteéumFuncionario:
9.1REPETINDOCÓDIGO? 123
publicclassTestaGerente{publicstaticvoidmain(String[]args){Gerentegerente=newGerente();
//podemoschamarmétodosdoFuncionario:gerente.setNome("JoãodaSilva");
//etambémmétodosdoGerente!gerente.setSenha(4231);}}
DizemosqueaclasseGerenteherdatodososatributosemétodosdaclassemãe,nonossocaso,aFuncionario.Para sermaispreciso, ela tambémherdaosatributosemétodosprivados,porémnão
consegue acessá-los diretamente. Para acessar um membro privado na filha indiretamente, serianecessárioqueamãeexpusesseumoutrométodovisívelqueinvocasseesseatributooumétodoprivado.
SUPERESUBCLASSE
A nomenclatura mais encontrada é que Funcionario é a superclasse de Gerente , eGerente é a subclasse de Funcionario . Dizemos também que todo Gerente é umFuncionário.OutraformaédizerqueFuncionarioéclassemãedeGerenteeGerenteéclassefilhadeFuncionario.
E se precisamos acessar os atributos que herdamos? Não gostaríamos de deixar os atributos deFuncionario,public,poisdessamaneiraqualquerumpoderiaalterarosatributosdosobjetosdeste
tipo.Existeumoutromodificadordeacesso,oprotected,queficaentreoprivateeopublic.
Umatributoprotectedsópodeseracessado(visível)pelaprópriaclasse,porsuassubclasses,epelas
classesqueseencontramnomesmopacote.
publicclassFuncionario{protectedStringnome;protectedStringcpf;protecteddoublesalario;//métodosdevemviraqui}
124 9.1REPETINDOCÓDIGO?
SEMPREUSARPROTECTED?
Entãoporqueusarprivate?Depoisdeumtempoprogramandoorientadoaobjetos,vocêvai
começarasentirquenemsempreéumaboaideiadeixarqueaclassefilhaacesseosatributosdaclassemãe, pois isso quebra um pouco a ideia de que só aquela classe deveriamanipular seusatributos.Essaéumadiscussãoumpoucomaisavançada.
Alémdisso,nãosóassubclasses,mastambémasoutrasclassesqueseencontramnomesmopacote, podem acessar os atributos protected. Veja outras alternativas ao protected no
exercíciodediscussãoemsaladeaulajuntamentecomoinstrutor.
Da mesma maneira, podemos ter uma classe Diretor que estenda Gerente e a classe
PresidentepodeestenderdiretamentedeFuncionario.
Fique claro que essa é uma decisão de negócio. Se Diretor vai estender de Gerente ou não, vaidependerse,paravocê,DiretoréumGerente.
Umaclassepodeterváriasfilhas,maspodeterapenasumamãe,éachamadaherançasimplesdojava.
9.1REPETINDOCÓDIGO? 125
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Todofimdeano,osfuncionáriosdonossobancorecebemumabonificação.Osfuncionárioscomunsrecebem10%dovalordosalárioeosgerentes,15%.
VamosvercomoficaaclasseFuncionario:
publicclassFuncionario{protectedStringnome;protectedStringcpf;protecteddoublesalario;
publicdoublegetBonificacao(){returnthis.salario*0.10;}//métodos}
SedeixarmosaclasseGerentecomoelaestá,elavaiherdarométodogetBonificacao.
Gerentegerente=newGerente();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ônusnesse 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 bastante quem for usar essa classe, além de que cada um da uma resposta
diferente.
NoJava,quandoherdamosummétodo,podemosalterarseucomportamento.Podemosreescrever(reescrever,sobrescrever,override)estemétodo:
publicclassGerenteextendsFuncionario{
EditoraCasadoCódigocomlivrosdeumaformadiferente
9.2REESCRITADEMÉTODO
126 9.2REESCRITADEMÉTODO
intsenha;intnumeroDeFuncionariosGerenciados;
publicdoublegetBonificacao(){returnthis.salario*0.15;}//...}
AgoraométodoestácorretoparaoGerente.Refaçaotesteevejaqueovalorimpressoéocorreto
(750):
Gerentegerente=newGerente();gerente.setSalario(5000.0);System.out.println(gerente.getBonificacao());
AANOTAÇÃO@OVERRIDE
Hácomodeixarexplícitonoseucódigoquedeterminadométodoéareescritadeummétododasua classe mãe. Fazemos isso colocando @Override em cima do método. Isso é chamado
anotação.Existemdiversasanotaçõesecadaumavaiterumefeitodiferentesobreseucódigo.
@OverridepublicdoublegetBonificacao(){returnthis.salario*0.15;}
Repare que, por questões de compatibilidade, isso não é obrigatório. Mas caso ummétodoesteja anotado com @Override, ele necessariamente precisa estar reescrevendo um método daclassemãe.
Depoisde reescrito,nãopodemosmais chamarométodoantigoque foraherdadodaclassemãe:realmente alteramos o seu comportamento. Mas podemos invocá-lo no caso de estarmos dentro daclasse.
Imaginequepara calcular abonificaçãodeumGerente devemos fazer igual ao cálculodeum
FuncionarioporémadicionandoR$1000.Poderíamosfazerassim:
publicclassGerenteextendsFuncionario{intsenha;intnumeroDeFuncionariosGerenciados;
publicdoublegetBonificacao(){returnthis.salario*0.10+1000;}//...}
9.3INVOCANDOOMÉTODOREESCRITO
9.3INVOCANDOOMÉTODOREESCRITO 127
Aquiteríamosumproblema:odiaqueogetBonificacaodoFuncionariomudar,precisaremos
mudar o método do Gerente para acompanhar a nova bonificação. Para evitar isso, o
getBonificacaodoGerentepodechamarodoFuncionarioutilizandoapalavrachavesuper.
publicclassGerenteextendsFuncionario{intsenha;intnumeroDeFuncionariosGerenciados;
publicdoublegetBonificacao(){returnsuper.getBonificacao()+1000;}//...}
Essa invocação vai procurar o método com o nome getBonificacao de uma super classe de
Gerente.NocasoelelogovaiencontraressemétodoemFuncionario.
Essaéumapráticacomum,poismuitoscasosométodoreescritogeralmentefaz"algoamais"queométododaclassemãe.Chamarounãoométododecimaéumadecisãosuaedependedoseuproblema.Algumasvezesnãofazsentidoinvocarométodoquereescrevemos.
OqueguardaumavariáveldotipoFuncionario?UmareferênciaparaumFuncionario,nuncao
objetoemsi.
Naherança,vimosquetodoGerenteéumFuncionario,poiséumaextensãodeste.Podemos
nos referir a um Gerente como sendo um Funcionario . Se alguém precisa falar com um
Funcionariodobanco,podefalarcomumGerente!Porque?PoisGerenteéumFuncionario.
Essaéasemânticadaherança.
Gerentegerente=newGerente();Funcionariofuncionario=gerente;funcionario.setSalario(5000.0);
Polimorfismo é a capacidade de um objeto poder ser referenciado de várias formas. (cuidado,polimorfismonãoquerdizerqueoobjetoficasetransformando,muitopelocontrário,umobjetonascedeumtipoemorredaqueletipo,oquepodemudaréamaneiracomonosreferimosaele).
9.4POLIMORFISMO
128 9.4POLIMORFISMO
Atéaquitudobem,maseseeutentar:
funcionario.getBonificacao();
Qual é o retorno desse método? 500 ou 750? No Java, a invocação de método sempre vai serdecidida em tempo de execução. O Java vai procurar o objeto na memória e, aí sim, decidir qualmétododeveserchamado,semprerelacionandocomsuaclassedeverdade,enãocomaqueestamosusando para referenciá-lo. Apesar de estarmos nos referenciando a esse Gerente como sendo um
Funcionario,ométodoexecutadoéodoGerente.Oretornoé750.
Parece estranho criar um gerente e referenciá-lo como apenas um funcionário. Por que faríamosisso?Naverdade,asituaçãoquecostumaapareceréaquetemosummétodoquerecebeumargumentodotipoFuncionario:
classControleDeBonificacoes{privatedoubletotalDeBonificacoes=0;
publicvoidregistra(Funcionariofuncionario){this.totalDeBonificacoes+=funcionario.getBonificacao();}
publicdoublegetTotalDeBonificacoes(){returnthis.totalDeBonificacoes;}}
E,emalgumlugardaminhaaplicação(ounomain,seforapenasparatestes):
ControleDeBonificacoescontrole=newControleDeBonificacoes();
Gerentefuncionario1=newGerente();funcionario1.setSalario(5000.0);controle.registra(funcionario1);
Funcionariofuncionario2=newFuncionario();funcionario2.setSalario(1000.0);controle.registra(funcionario2);
System.out.println(controle.getTotalDeBonificacoes());
ReparequeconseguimospassarumGerenteparaummétodoquerecebeumFuncionariocomo
argumento. Pense como numa porta na agência bancária com o seguinte aviso: "Permitida a entradaapenas de Funcionários". Um gerente pode passar nessa porta? Sim, pois Gerente é umFuncionario.
Qual será o valor resultante? Não importa que dentro do método registra doControleDeBonificacoesrecebaFuncionario.Quandoelereceberumobjetoquerealmenteéum
Gerente,oseumétodoreescritoseráinvocado.Reafirmando:nãoimportacomonosreferenciamosaumobjeto,ométodoqueseráinvocadoésempreoqueédele.
No dia emque criarmos uma classeSecretaria, por exemplo, que é filha deFuncionario,
9.4POLIMORFISMO 129
precisaremos mudar a classe de ControleDeBonificacoes? Não. Basta a classe Secretaria
reescrever os métodos que lhe parecerem necessários. É exatamente esse o poder do polimorfismo,juntamentecomareescritademétodo:diminuiroacoplamentoentreasclasses,paraevitarquenovoscódigosresultememmodificaçõeseminúmeroslugares.
ReparequequemcriouControleDeBonificacoespodenunca ter imaginadoacriaçãodaclasse
Secretaria ouEngenheiro. Contudo, não será necessário reimplementar esse controle em cada
novaclasse:reaproveitamosaquelecódigo.
HERANÇAVERSUSACOPLAMENTO
Notequeousodeherançaaumentaoacoplamentoentreasclasses,istoé,oquantoumaclassedependedeoutra.Arelaçãoentreclassemãeefilhaémuitoforteeissoacabafazendocomqueoprogramadordasclassesfilhas tenhaqueconhecera implementaçãodaclassemãeevice-versa-ficadifícilfazerumamudançapontualnosistema.
Por exemplo, imagine se tivermos quemudar algo na nossa classeFuncionario,masnão
quiséssemosquetodososfuncionáriossofressemamesmamudança.Precisaríamospassarporcadauma das filhas de Funcionario verificando se ela se comporta como deveria ou se devemos
sobrescreverotalmétodomodificado.
Esseéumproblemadaherança,enãodopolimorfismo,que resolveremosmais tardecomaajudadeInterfaces.
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
JáconheceoscursosonlineAlura?
9.5UMOUTROEXEMPLO
130 9.5UMOUTROEXEMPLO
Imaginequevamosmodelarumsistemaparaafaculdadequecontroleasdespesascomfuncionárioseprofessores.Nossofuncionárioficaassim:
publicclassEmpregadoDaFaculdade{privateStringnome;privatedoublesalario;publicdoublegetGastos(){returnthis.salario;}publicStringgetInfo(){return"nome:"+this.nome+"comsalário"+this.salario;}//métodosdeget,seteoutros}
Ogastoquetemoscomoprofessornãoéapenasseusalário.Temosdesomarumbônusde10reaisporhora/aula.Oquefazemosentão?Reescrevemosométodo.AssimcomoogetGastosédiferente,o
getInfotambémserá,poistemosdemostrarashoras/aulatambém.
publicclassProfessorDaFaculdadeextendsEmpregadoDaFaculdade{privateinthorasDeAula;publicdoublegetGastos(){returnthis.getSalario()+this.horasDeAula*10;}publicStringgetInfo(){StringinformacaoBasica=super.getInfo();Stringinformacao=informacaoBasica+"horasdeaula:"+this.horasDeAula;returninformacao;}//métodosdeget,seteoutrosqueforemnecessários}
Anovidade,aqui,éapalavrachavesuper.Apesardométodo ter sido reescrito,gostaríamosde
acessar ométodo da classemãe, para não ter de copiar e colocar o conteúdo dessemétodo e depoisconcatenarcomainformaçãodashorasdeaula.
Comotiramosproveitodopolimorfismo?Imaginequetemosumaclassederelatório:
publicclassGeradorDeRelatorio{publicvoidadiciona(EmpregadoDaFaculdadef){System.out.println(f.getInfo());System.out.println(f.getGastos());}}
Podemos passar para nossa classe qualquer EmpregadoDaFaculdade! Vai funcionar tanto para
professor,quantoparafuncionáriocomum.
Umcertodia,muitodepoisdeterminaressaclassederelatório,resolvemosaumentarnossosistema,e colocar uma classe nova, que representa o Reitor . Como ele também é um
EmpregadoDaFaculdade,seráquevamosprecisaralteraralgonanossaclassedeRelatorio?Não.
Essa é a ideia!Quemprogramou a classeGeradorDeRelatorio nunca imaginou que existiria uma
9.5UMOUTROEXEMPLO 131
classeReitore,mesmoassim,osistemafunciona.
publicclassReitorextendsEmpregadoDaFaculdade{//informaçõesextraspublicStringgetInfo(){returnsuper.getInfo()+"eeleéumreitor";}//nãosobrescrevemosogetGastos!!!}
SenãohouvesseherançaemJava,comovocêpoderiareaproveitarocódigodeoutraclasse?
Uma discussãomuito atual é sobre o abuso no uso da herança.Algumas pessoas usam herançaapenas para reaproveitar o código, quando poderiam ter feito uma composição. Procure sobreherançaversuscomposição.
Mesmodepoisdereescreverummétododaclassemãe,aclassefilhaaindapodeacessarométodoantigo. Isto é feito através da palavra chave super.método(). Algo parecido ocorre entre os
construtoresdasclasses,oque?
MAISSOBREOMAUUSODAHERANÇA
NoblogdaCaelumexisteumartigointeressanteabordandoessetópico:
http://blog.caelum.com.br/2006/10/14/como-nao-aprender-orientacao-a-objetos-heranca/
JamesGosling,umdoscriadoresdoJava,éumcríticodomauusodaherança.Nestaentrevistaelediscuteapossibilidadedeseutilizarapenasinterfacesecomposição,eliminandoanecessidadedaherança:
http://www.artima.com/intv/gosling3P.html
1. Vamostermaisdeumtipodecontanonossosistemaentãovamosprecisardeumanovatelaparacadastrarosdiferentestiposdeconta.Essatelajáestáprontaeparautilizá-lasóprecisamosalteraraclassequeestamoschamandonométodomain()noTestaContas.java:
packagebr.com.caelum.contas.main;
importbr.com.caelum.javafx.api.main.SistemaBancario;
publicclassTestaContas{
9.6UMPOUCOMAIS...
9.7EXERCÍCIOS:HERANÇAEPOLIMORFISMO
132 9.6UMPOUCOMAIS...
publicstaticvoidmain(String[]args){SistemaBancario.mostraTela(false);//TelaDeContas.main(args);}}
2. AorodaraclasseTestaContasagora,teremosatelaabaixo:
Vamosentrarna teladecriaçãodecontasparavermosoqueprecisamos implementarparaqueosistemafuncione.Paraisso,cliquenobotãoNovaConta.Aseguintetelaaparecerá:
Podemos perceber que além das informações que já tínhamos na conta, temos agora o tipo: sequeremosumacontacorrenteouumacontapoupança.Vamosentãocriarasclassescorrespondentes.
CrieaclasseContaCorrentenopacotebr.com.caelum.contas.modeloe façacomqueela
sejafilhadaclasseConta
CrieaclasseContaPoupancanopacotebr.com.caelum.contas.modeloe façacomqueela
sejafilhadaclasseConta
9.7EXERCÍCIOS:HERANÇAEPOLIMORFISMO 133
3. Precisamos pegar os dados da tela para conseguirmos criar a conta correspondente. NoManipuladorDeContas vamos alterar ométodocriaConta.Atualmente, apenas criamos uma
novacontacomosdadosdiretonocódigo.Vamosfazercomqueagoraosdadossejamrecuperadosdatelaparacolocarmosnanovaconta,faremosissoutilizandooobjetoevento:
publicvoidcriaConta(Eventoevento){this.conta=newConta();this.conta.setAgencia(evento.getString("agencia"));this.conta.setNumero(evento.getInt("numero"));this.conta.setTitular(evento.getString("titular"));}
Masprecisamosdizer qual tipode conta quequeremos criar!Devemos então recuperar o tipodacontaescolhidoecriaracontacorrespondente.Paraisso,aoinvésdecriarumobjetodotipo'Conta',vamosusarométodogetSelecionadoNoRadiodoobjetoeventoparapegarotipo,fazerumif
paraverificaresse tipoesódepoiscriaroobjetodotipocorrespondente.Apósessasmudanças,ométodocriaContaficarácomoabaixo:
publicvoidcriaConta(Eventoevento){Stringtipo=evento.getSelecionadoNoRadio("tipo");if(tipo.equals("ContaCorrente")){this.conta=newContaCorrente();}elseif(tipo.equals("ContaPoupança")){this.conta=newContaPoupanca();}this.conta.setAgencia(evento.getString("agencia"));this.conta.setNumero(evento.getInt("numero"));this.conta.setTitular(evento.getString("titular"));}
4. Apesarde jáconseguirmoscriarosdois tiposdecontas,nossa listanãoconsegueexibiro tipodecadacontanalistadatelainicial.Pararesolverisso,podemoscriarummétodogetTipoemcada
umadenossascontasfazendocomqueacontacorrentedevolvaastring"ContaCorrente"eacontapoupançadevolvaastring"ContaPoupança":
publicclassContaCorrenteextendsConta{publicStringgetTipo(){return"ContaCorrente";}}
publicclassContaPoupancaextendsConta{publicStringgetTipo(){return"ContaPoupança";}}
5. AltereosmétodossacaedepositaparabuscaremocampovalorOperacaoaoinvésdeapenas
valornaclasseManipuladorDeContas.
6. Vamosmudaro comportamentodaoperaçãode saquede acordo como tipode contaque estiversendo utilizada.Na classeManipuladorDeContas vamos alterar ométodo saca para tirar 10
134 9.7EXERCÍCIOS:HERANÇAEPOLIMORFISMO
centavosdecadasaqueemumacontacorrente:
publicvoidsaca(Eventoevento){doublevalor=evento.getDouble("valorOperacao");if(this.conta.getTipo().equals("ContaCorrente")){this.conta.saca(valor+0.10);}else{this.conta.saca(valor);}}
AotentarmoschamarométodogetTipo,oEclipsereclamouqueessemétodonãoexistenaclasse
Contaapesardeexistirnasclassesfilhas.Comoestamostratandotodasascontasgenericamente,
sóconseguimosacessarosmétodosdaclassemãe.Vamosentãocolocá-lonaclasseConta:
publicclassConta{publicStringgetTipo(){return"Conta";}}
7. Agoraocódigocompilamastemosumoutroproblema.AlógicadonossosaquevazouparaaclasseManipuladorDeContas.Sealgumdiaprecisarmosalterarovalordataxanosaque, teríamosque
mudar em todos os lugares onde fazemos uso do método saca . Esta lógica deveria estar
encapsuladadentrodométodosacadecadaconta.Vamosentãosobrescreverométododentroda
classeContaCorrente:
publicclassContaCorrenteextendsConta{@Overridepublicvoidsaca(doublevalor){this.saldo-=(valor+0.10);}
//restantedaclasse}
Repareque,paraacessaroatributo saldoherdadodaclasseConta,vocêvaiprecisarmudaromodificadordevisibilidadedesaldoparaprotected.
Agora que a lógica está encapsulada, podemos corrigir o método saca da classe
ManipuladorDeContas:
publicvoidsaca(Eventoevento){doublevalor=evento.getDouble("valorOperacao");this.conta.saca(valor);}
Percebaqueagoratratamosacontadeformagenérica!
8. Rode a classe TestaContas, adicione uma conta de cada tipo e veja se o tipo é apresentado
corretamentenalistadecontasdatelainicial.
Agora,cliquenacontacorrenteapresentadanalistaparaabrirateladedetalhesdecontas.Testeas
9.7EXERCÍCIOS:HERANÇAEPOLIMORFISMO 135
operações de saque e depósito e perceba que a conta apresenta o comportamento de uma contacorrenteconformeoesperado.
Esetentarmosrealizarumatransferênciadacontacorrenteparaacontapoupança?Oqueacontece?
9. VamoscomeçarimplementandoométodotransferenaclasseConta:
publicvoidtransfere(doublevalor,Contaconta){this.saca(valor);conta.deposita(valor);}
Tambémprecisamos implementar ométodotransfere na classeManipuladorDeContas para
fazerovínculoentreatelaeaclasseConta:
publicvoidtransfere(Eventoevento){Contadestino=(Conta)evento.getSelecionadoNoCombo("destino");conta.transfere(evento.getDouble("valorTransferencia"),destino);}
Rodedenovoaaplicaçãoetesteaoperaçãodetransferência.
10. Considereocódigoabaixo:
Contac=newConta();ContaCorrentecc=newContaCorrente();ContaPoupancacp=newContaPoupanca();
Semudarmosessecódigopara:
Contac=newConta();Contacc=newContaCorrente();Contacp=newContaPoupanca();
Compila?Roda?Oquemuda?Qualéautilidadedisso?Realmente,essanãoéamaneiramaisútildo polimorfismo. Porém existe uma utilidade de declararmos uma variável de um tipo menosespecíficodoqueoobjetorealmenteé,comofazemosnaclasseManipuladorDeContas.
Éextremamenteimportanteperceberquenãoimportacomonosreferimosaumobjeto,ométodoqueserá invocadoésempreomesmo!AJVMvaidescobriremtempodeexecuçãoqualdeveserinvocado,dependendodequetipoéaqueleobjeto,nãoimportandocomonosreferimosaele.
11. (Opcional)AnossaclasseContadevolveapalavra"Conta"nométodogetTipo.Useapalavra
chavesuper nos métodos getTipo reescritos nas classes filhas, para não ter de reescreve a
palavra"Conta"aodevolverostipos"ContaCorrente"e"ContaPoupança".
12. (Opcional)SevocêprecisassecriarumaclasseContaInvestimento,e seumétodosaca fosse
complicadíssimo,vocêprecisariaalteraraclasseManipuladorDeContas?
136 9.7EXERCÍCIOS:HERANÇAEPOLIMORFISMO
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoJavaeOrientaçãoaObjetos
Discuta com o instrutor e seus colegas alternativas ao uso do atributo protected na herança.
Preciso realmente afrouxar o encapsulamento do atributo por causa da herança? Como fazer para oatributocontinuarprivatenamãeeasfilhasconseguiremdealgumaformartrabalharcomele?
VocêpodetambémfazerocursodatadessaapostilanaCaelum
9.8 DISCUSSÕES EM AULA: ALTERNATIVAS AO ATRIBUTOPROTECTED
9.8DISCUSSÕESEMAULA:ALTERNATIVASAOATRIBUTOPROTECTED 137
CAPÍTULO10
"Dá-seimportânciaaosantepassadosquandojánãotemosnenhum."--FrançoisChateaubriand
Aotérminodessecapítulo,vocêserácapazdeutilizarclassesabstratas,quandonecessário.
VamosrecordaremcomopodeestarnossaclasseFuncionario:
publicclassFuncionario{
protectedStringnome;protectedStringcpf;protecteddoublesalario;
publicdoublegetBonificacao(){returnthis.salario*1.2;}
//outrosmétodosaqui
}
ConsidereonossoControleDeBonificacao:
publicclassControleDeBonificacoes{
privatedoubletotalDeBonificacoes=0;
publicvoidregistra(Funcionariof){System.out.println("Adicionandobonificaçãodofuncionario:"+f);this.totalDeBonificacoes+=f.getBonificacao();}
publicdoublegetTotalDeBonificacoes(){returnthis.totalDeBonificacoes;}}
Nossométodoregistra recebe qualquer referência do tipo Funcionario, isto é, podem ser
objetosdo tipoFuncionario e qualquer de seus subtipos:Gerente,Diretor e, eventualmente,
alguma nova subclasse que venha ser escrita, sem prévio conhecimento do autor daControleDeBonificacao.
EstamosutilizandoaquiaclasseFuncionarioparaopolimorfismo.Senãofosseela,teríamosum
CLASSESABSTRATAS
10.1REPETINDOMAISCÓDIGO?
138 10CLASSESABSTRATAS
grande prejuízo: precisaríamos criar um método registra para receber cada um dos tipos de
Funcionario,umparaGerente,umparaDiretor,etc.Reparequeperderessepoderémuitopiordoqueapequenavantagemqueaherançatrazemherdarcódigo.
Porém,emalgunssistemas,comoéonossocaso,usamosumaclassecomapenasessesintuitos:deeconomizar um pouco código e ganhar polimorfismo para criar métodos mais genéricos, que seencaixemadiversosobjetos.
Faz sentido ter uma referência do tipoFuncionario?Essapergunta é diferente de saber se faz
sentidoterumobjetodotipoFuncionario:nessecaso,fazsimeémuitoútil.
ReferenciandoFuncionariotemosopolimorfismodereferência,jáquepodemosreceberqualquer
objetoquesejaumFuncionario.Porém,darnewemFuncionariopodenãofazersentido,istoé,
não queremos receber umobjeto do tipoFuncionario,mas sim que aquela referência seja ou um
Gerente,ouumDiretor,etc.AlgomaisconcretoqueumFuncionario.
ControleDeBonificacoescdb=newControleDeBonificacoes();Funcionariof=newFuncionario();cdb.adiciona(f);//fazsentido?
Vejamosumoutrocasoemquenãofazsentidoterumobjetodaqueletipo,apesardaclasseexistir:imagineaclassePessoa eduas filhas,PessoaFisica ePessoaJuridica.Quandopuxamosum
relatóriodenossosclientes(umaarraydePessoaporexemplo),queremosquecadaumdelessejaou
umaPessoaFisica,ouumaPessoaJuridica.AclassePessoa, nesse caso, estaria sendousada
apenasparaganharopolimorfismoeherdaralgumascoisas:nãofazsentidopermitirinstanciá-la.
Pararesolveressesproblemas,temosasclassesabstratas.
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Seuslivrosdetecnologiaparecemdoséculopassado?
10.2CLASSEABSTRATA
10.2CLASSEABSTRATA 139
O que, exatamente, vem a ser a nossa classe Funcionario ? Nossa empresa tem apenas
Diretores,Gerentes,Secretárias, etc.Ela é uma classeque apenas idealiza um tipo, define
apenasumrascunho.
Paraonossosistema,éinadmissívelqueumobjetosejaapenasdotipoFuncionario(podeexistir
umsistemaemquefaçasentidoterobjetosdotipoFuncionarioouapenasPessoa,mas,nonosso
caso,não).
Usamosapalavrachaveabstractparaimpedirqueelapossaserinstanciada.Esseéoefeitodireto
deseusaromodificadorabstractnadeclaraçãodeumaclasse:
publicabstractclassFuncionario{
protecteddoublesalario;
publicdoublegetBonificacao(){returnthis.salario*1.2;}
//outrosatributosemétodoscomunsatodosFuncionarios
}
E,nomeiodeumcódigo:
Funcionariof=newFuncionario();//nãocompila!!!
Ocódigoacimanãocompila.Oproblemaéinstanciaraclasse-criarreferência,vocêpode.Seelanãopodeserinstanciada,paraqueserve?Serveparaopolimorfismoeherançadosatributosemétodos,quesãorecursosmuitopoderosos,comojávimos.
Vamosentãoherdardessaclasse,reescrevendoométodogetBonificacao:
publicclassGerenteextendsFuncionario{
publicdoublegetBonificacao(){returnthis.salario*1.4+1000;}}
140 10.2CLASSEABSTRATA
Mas qual é a real vantagem de uma classe abstrata? Poderíamos ter feito isto com uma herançacomum. Por enquanto, a única diferença é que não podemos instanciar um objeto do tipoFuncionario,quejáédegrandevalia,dandomaisconsistênciaaosistema.
FiqueclaroqueanossadecisãodetransformarFuncionarioemumaclasseabstratadependeudo
nossodomínio.Podeserque,emumsistemacomclassessimilares,façasentidoqueumaclasseanálogaaFuncionariosejaconcreta.
SeométodogetBonificacaonãofossereescrito,eleseriaherdadodaclassemãe,fazendocom
quedevolvesseosaláriomais20%.
Levando em consideração que cada funcionário em nosso sistema tem uma regra totalmentediferente para ser bonificado, faz algum sentido ter essemétodona classeFuncionario? Será que
existeumabonificaçãopadrãoparatodotipodeFuncionario?Parecequenão,cadaclassefilhaterá
ummétodo diferente de bonificação pois, de acordo comnosso sistema, não existe uma regra geral:queremos que cada pessoa que escreve a classe de um Funcionario diferente (subclasses de
Funcionario)reescrevaométodogetBonificacaodeacordocomassuasregras.
Poderíamos,então,jogarforaessemétododaclasseFuncionario?Oproblemaéque,seelenão
existisse, não poderíamos chamar o método apenas com uma referência a um Funcionario, pois
ninguém garante que essa referência aponta para um objeto que possui essemétodo. Será que entãodevemosretornarumcódigo,comoumnúmeronegativo?Issonãoresolveoproblema:seesquecermosdereescreveressemétodo,teremosdadoserradossendoutilizadoscomobônus.
10.3MÉTODOSABSTRATOS
10.3MÉTODOSABSTRATOS 141
ExisteumrecursoemJavaque,emumaclasseabstrata,podemosescreverquedeterminadométodoserásempreescritopelasclassesfilhas.Istoé,ummétodoabstrato.
Eleindicaquetodasasclassesfilhas(concretas,istoé,quenãoforemabstratas)devemreescreveressemétodoounãocompilarão.Écomosevocêherdassearesponsabilidadedeteraquelemétodo.
COMODECLARARUMMÉTODOABSTRATO
Àsvezes,nãoficaclarocomodeclararummétodoabstrato.
Basta escrever a palavra chave abstract na assinatura do mesmo e colocar um ponto e
vírgulaemvezdeabreefechachaves!
publicabstractclassFuncionario{
publicabstractdoublegetBonificacao();
//outrosatributosemétodos
}
Reparequenãocolocamosocorpodométodoeusamosapalavrachaveabstractparadefiniro
mesmo. Por que não colocar corpo algum?Porque essemétodo nunca vai ser chamado, sempre quealguémchamarométodogetBonificacao,vaicairemumadassuasfilhas,querealmenteescreveram
ométodo.
Qualquer classe que estender a classe Funcionario será obrigada a reescrever este método,
tornando-o"concreto".Senãoreescreveremessemétodo,umerrodecompilaçãoocorrerá.
OmétododoControleDeBonificacaoestavaassim:
publicvoidregistra(Funcionariof){System.out.println("Adicionandobonificaçãodofuncionario:"+f);this.totalDeBonificacoes+=f.getBonificacao();}
ComopossoacessarométodogetBonificacaoseelenãoexistenaclasseFuncionario?
Jáqueométodoéabstrato,comcertezasuassubclassestêmessemétodo,oquegarantequeessainvocação demétodo não vai falhar. Basta pensar que uma referência do tipoFuncionario nunca
apontaparaumobjetoquenão temométodogetBonificacao, pois não é possível instanciar uma
classe abstrata, apenas as concretas.Ummétodo abstrato obriga a classe em que ele se encontra serabstrata,oquegaranteacoerênciadocódigoacimacompilar.
10.4AUMENTANDOOEXEMPLO
142 10.4AUMENTANDOOEXEMPLO
Ese,nonossoexemplodeempresa, tivéssemoso seguintediagramadeclasses comos seguintesmétodos:
Ouseja,tenhoaclasseabstrataFuncionario,comométodoabstratogetBonificacao;asclasses
GerenteePresidenteestendendoFuncionarioeimplementandoométodogetBonificacao;e,
porfim,aclasseDiretor,queestendeGerente,masnãoimplementaométodogetBonificacao.
Essasclassesvãocompilar?Vãorodar?
Arespostaésim.E,alémdetudo,farãoexatamenteoquenósqueremos,pois,quandoGerentee
Presidentepossuemosmétodosperfeitamenteimplementados,aclasseDiretor,quenãopossuio
métodoimplementado,vaiusaraimplementaçãoherdadadeGerente.
10.4AUMENTANDOOEXEMPLO 143
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,porsuavez,implementamométodogetBonificacao,vaicompilar?Vai
rodar?
Denovo,arespostaésim,poisSecretariaéumaclasseabstratae,porisso,oJavatemcertezade
que ninguém vai conseguir instanciá-la e, muito menos, chamar o método getBonificacao dela.
Lembrando que, nesse caso, não precisamos nem ao menos escrever o método abstratogetBonificacaonaclasseSecretaria.
Seeunãoreescreverummétodoabstratodaminhaclassemãe,ocódigonãocompilará.Masposso,emvezdisso,declararaclassecomoabstrata!
JAVA.IO
Classes abstratas não possuem nenhum segredo no aprendizado,mas quem está aprendendoorientaçãoaobjetospodeterumaenormedificuldadeparasaberquandoutilizá-las,oqueémuitonormal.
Estudaremosopacote java.io,queusabastantes classesabstratas, sendoumexemplo realdeusodesserecurso,quevaimelhoraroentendimentodelas.(classeInputStreamesuasfilhas)
144 10.4AUMENTANDOOEXEMPLO
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Uma classe que estende uma classe normal também pode ser abstrata! Ela não poderá serinstanciada,massuaclassepaisim!
Umaclasseabstratanãoprecisanecessariamenteterummétodoabstrato.
1. ReparequeanossaclasseContaéumaexcelentecandidataparaumaclasseabstrata.Porquê?Que
métodosseriaminteressantescandidatosaseremabstratos?
TransformeaclasseContaemabstrata:
publicabstractclassConta{//...}
2. ComoaclasseContaagoraéabstrata,nãoconseguimosdarnewnelamais.Senãopodemosdar
newemConta,qualéautilidadedeterummétodoquerecebeumareferênciaaConta como
argumento?Aliás,possoterisso?
3. Apenasparaentendermelhoroabstract,comenteométodogetTipo()daContaPoupanca,
dessaformaeleherdaráométododiretamentedeConta.
TransformeométodogetTipo()daclasseContaemabstrato.Repareque,aocolocarapalavra
chaveabstractaoladodométodo,oEclipserapidamentevaisugerirquevocêdeveremovero
corpo(body)dométodocomumquickfix.
SuaclasseContadeveficarparecidacom:
Agoraéamelhorhoradeaprenderalgonovo
10.5PARASABERMAIS...
10.6EXERCÍCIOS:CLASSESABSTRATAS
10.5PARASABERMAIS... 145
publicabstractclassConta{//atributosemétodosquejáexistiam
publicabstractStringgetTipo();}
QualéoproblemacomaclasseContaPoupanca?
4. DescomenteométodogetTipo na classeContaPoupanca, e se necessário altere-opara que a
classepossacompilarnormalmente.
5. (opcional) Existe outramaneira de a classeContaPoupanca compilar se você não reescrever o
métodoabstrato?
6. (opcional)PraqueterométodogetTiponaclasseContaseelenãofaznada?Oqueacontecese
simplesmenteapagarmosessemétododaclasseContaedeixarmosométodogetTiponasfilhas?
7. (opcional) Posso chamar um método abstrato de dentro de um outro método da própria classeabstrata?Porexemplo,imaginequeexistaoseguintemétodonaclasseConta:
publicStringrecuperaDadosParaImpressao(){Stringdados="Titular:"+this.titular;dados+="\nNúmero:"+this.numero;dados+="\nAgência:"+this.agencia;dados+="\nSaldo:R$"+this.saldo;returndados;}
PodemosinvocarogetTipodentrodestemétodo?Algocomo:
dados+="\nTipo:"+this.getTipo();
146 10.6EXERCÍCIOS:CLASSESABSTRATAS
CAPÍTULO11
"Umaimagemvalemilpalavras.Umainterfacevalemilimagens."--BenShneiderman
Aotérminodessecapítulo,vocêserácapazde:
dizeroqueéumainterfaceeasdiferençasentreherançaeimplementação;escreverumainterfaceemJava;utilizá-lascomoumpoderosorecursoparadiminuiracoplamentoentreasclasses.
ImaginequeumSistemadeControledoBancopode seracessado, alémdepelosGerentes,pelosDiretoresdoBanco.Então,teríamosumaclasseDiretor:
publicclassDiretorextendsFuncionario{
publicbooleanautentica(intsenha){//verificaaquiseasenhaconferecomarecebidacomoparametro}
}
EaclasseGerente:
publicclassGerenteextendsFuncionario{
publicbooleanautentica(intsenha){//verificaaquiseasenhaconferecomarecebidacomoparametro//nocasodogerenteverificatambémseodepartamentodele//temacesso}
}
INTERFACES
11.1AUMENTANDONOSSOEXEMPLO
11INTERFACES 147
ReparequeométododeautenticaçãodecadatipodeFuncionariopodevariarmuito.Masvamos
aosproblemas.Considere oSistemaInterno e seu controle: precisamos receber umDiretor ou
Gerentecomoargumento,verificarseeleseautenticaecolocá-lodentrodosistema.
publicclassSistemaInterno{
publicvoidlogin(Funcionariofuncionario){//invocarométodoautentica?//nãoda!NemtodoFuncionariotem}}
OSistemaInterno aceitaqualquer tipodeFuncionario, tendo ele acesso ao sistemaounão,
masnotequenemtodoFuncionariopossuiométodoautentica.Issonosimpededechamaresse
método com uma referência apenas a Funcionario (haveria um erro de compilação). O que fazer
então?
publicclassSistemaInterno{
publicvoidlogin(Funcionariofuncionario){funcionario.autentica(...);//nãocompila}}
UmapossibilidadeécriardoismétodosloginnoSistemaInterno:umparareceberDiretore
outroparareceberGerente.Jávimosqueessanãoéumaboaescolha.Porquê?
publicclassSistemaInterno{
//designproblemáticopublicvoidlogin(Diretorfuncionario){funcionario.autentica(...);}
//designproblemáticopublicvoidlogin(Gerentefuncionario){funcionario.autentica(...);}
}
148 11.1AUMENTANDONOSSOEXEMPLO
Cada vez que criarmos uma nova classe de Funcionario que é autenticável, precisaríamos
adicionarumnovométododeloginnoSistemaInterno.
MÉTODOSCOMMESMONOME
EmJava,métodospodemteromesmonomedesdequenãosejamambíguos,istoé,queexistaumamaneiradedistinguirnomomentodachamada.
Issosechamasobrecargademétodo.(Overloading.Nãoconfundircomoverriding,queéumconceitomuitomaispoderoso).
Uma solução mais interessante seria criar uma classe no meio da árvore de herança,FuncionarioAutenticavel:
publicclassFuncionarioAutenticavelextendsFuncionario{
publicbooleanautentica(intsenha){//fazautenticacaopadrão}
//outrosatributosemétodos
}
As classes Diretor e Gerente passariam a estender de FuncionarioAutenticavel, e o
SistemaInternoreceberiareferênciasdessetipo,comoaseguir:
publicclassSistemaInterno{
publicvoidlogin(FuncionarioAutenticavelfa){
intsenha=//pegasenhadeumlugar,oudeumscannerdepolegar
//aquieupossochamaroautentica!//PoistodoFuncionarioAutenticaveltembooleanok=fa.autentica(senha);
}}
11.1AUMENTANDONOSSOEXEMPLO 149
Repare que FuncionarioAutenticavel é uma forte candidata a classe abstrata.Mais ainda, o
métodoautenticapoderiaserummétodoabstrato.
O uso de herança resolve esse caso,mas vamos a uma outra situação umpoucomais complexa:precisamosquetodososclientestambémtenhamacessoaoSistemaInterno.Oquefazer?Umaopção
écriaroutrométodologinemSistemaInterno:masjádescartamosessaanteriormente.
Uma outra, que é comum entre os novatos, é fazer uma herança sem sentido para resolver oproblema,porexemplo, fazerClienteextendsFuncionarioAutenticavel.Realmente, resolveo
problema,mastrarádiversosoutros.ClientedefinitivamentenãoéFuncionarioAutenticavel.Sevocê fizer isso,oCliente terá, por exemplo, ummétodogetBonificacao, umatributo salario e
outrosmembrosquenãofazemomenorsentidoparaestaclasse!Nãofaçaherançaquandoarelaçãonãoéestritamente"éum".
150 11.1AUMENTANDONOSSOEXEMPLO
Como resolver essa situação? Note que conhecer a sintaxe da linguagem não é o suficiente,precisamosestruturar/desenharbemanossaestruturadeclasses.
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
O que precisamos para resolver nosso problema? Arranjar uma forma de poder referenciarDiretor,GerenteeClientedeumamesmamaneira,istoé,acharumfatorcomum.
Seexistisseumaformanaqualessasclassesgarantissemaexistênciadeumdeterminadométodo,
EditoraCasadoCódigocomlivrosdeumaformadiferente
11.2INTERFACES
11.2INTERFACES 151
atravésdeumcontrato,resolveríamosoproblema.
Todaclassedefine2itens:
oqueumaclassefaz(asassinaturasdosmétodos)comoumaclassefazessastarefas(ocorpodosmétodoseatributosprivados)
Podemos criar um "contrato" que define tudo o que uma classe deve fazer se quiser ter umdeterminadostatus.Imagine:
contratoAutenticavel:
quemquiserserAutenticavelprecisasaberfazer:1.autenticardadaumasenha,devolvendoumbooleano
Quemquiser, pode "assinar" esse contrato, sendo assim obrigado a explicar como será feita essaautenticação.Avantageméque,seumGerenteassinaressecontrato,podemosnosreferenciaraum
GerentecomoumAutenticavel.
PodemoscriaressecontratoemJava!
publicinterfaceAutenticavel{
booleanautentica(intsenha);
}
Chama-seinterfacepoiséamaneirapelaqualpoderemosconversarcomumAutenticavel.
Interfaceéamaneiraatravésdaqualconversamoscomumobjeto.
Lemos a interface da seguinte maneira: "quem desejar ser autenticável precisa saber autenticardadouminteiroeretornandoumbooleano".Elaéumcontratoondequemassinaseresponsabilizaporimplementaressesmétodos(cumprirocontrato).
Uma interfacepodedefinirumasériedemétodos,masnuncaconter implementaçãodeles.Ela sóexpõeoqueoobjetodevefazer,enãocomoelefaz,nemoqueeletem.Comoelefazvaiserdefinidoemumaimplementaçãodessainterface.
EoGerentepode"assinar"ocontrato,ouseja,implementarainterface.Nomomentoemqueeleimplementaessainterface,eleprecisaescreverosmétodospedidospelainterface(muitoparecidocomoefeitodeherdarmétodosabstratos,aliás,métodosdeumainterfacesãopúblicoseabstratos,sempre).Paraimplementarusamosapalavrachaveimplementsnaclasse:
publicclassGerenteextendsFuncionarioimplementsAutenticavel{
privateintsenha;
//outrosatributosemétodos
publicbooleanautentica(intsenha){
152 11.2INTERFACES
if(this.senha!=senha){returnfalse;}//podefazeroutraspossíveisverificações,comosaberseesse//departamentodogerentetemacessoaoSistema
returntrue;}
}
Oimplementspodeserlidodaseguintemaneira:"AclasseGerentesecomprometeasertratada
comoAutenticavel,sendoobrigadaaterosmétodosnecessários,definidosnestecontrato".
Apartirdeagora,podemostratarumGerentecomosendoumAutenticavel.Ganhamosmais
polimorfismo!TemosmaisumaformadereferenciaraumGerente.Quandocrioumavariáveldotipo
Autenticavel, estou criando uma referência paraqualquer objeto de uma classe que implementeAutenticavel,diretaouindiretamente:
Autenticavela=newGerente();//possoaquichamarométodoautentica!
Novamente, a utilização mais comum seria receber por argumento, como no nossoSistemaInterno:
publicclassSistemaInterno{
publicvoidlogin(Autenticavela){intsenha=//pegasenhadeumlugar,oudeumscannerdepolegarbooleanok=a.autentica(senha);
//aquieupossochamaroautentica!//nãonecessariamenteéumFuncionario!//Maisainda,eunãoseiqueobjetoa//referência"a"estáapontandoexatamente!Flexibilidade.}
11.2INTERFACES 153
}
Pronto!EjápodemospassarqualquerAutenticavelparaoSistemaInterno.Entãoprecisamos
fazercomqueoDiretortambémimplementeessainterface.
publicclassDiretorextendsFuncionarioimplementsAutenticavel{
//métodoseatributos,alémdeobrigatoriamenteteroautentica
}
PodemospassarumDiretor.Nodiaemquetivermosmaisumfuncionáriocomacessoaosistema,
bastaqueeleimplementeessainterface,paraseencaixarnosistema.
QualquerAutenticavelpassadoparaoSistemaInternoestábomparanós.Reparequepouco
importa quem o objeto referenciado realmente é, pois ele tem um método autentica que é o
necessário para nosso SistemaInterno funcionar corretamente. Aliás, qualquer outra classe que
futuramenteimplementeessainterfacepoderáserpassadacomoargumentoaqui.
Autenticaveldiretor=newDiretor();Autenticavelgerente=newGerente();
Ou,seachamosqueoFornecedorprecisateracesso,bastaqueeleimplementeAutenticavel.
Olhesóotamanhododesacoplamento:quemescreveuoSistemaInternosóprecisasaberqueeleé
Autenticavel.
publicclassSistemaInterno{
publicvoidlogin(Autenticavela){//nãoimportaseeleéumgerenteoudiretor//seráqueéumfornecedor?//Eu,oprogramadordoSistemaInterno,nãomepreocupo//Invocareiométodoautentica}
}
154 11.2INTERFACES
NãofazdiferençaseéumDiretor,Gerente,Cliente ouqualquer classequevenhapor aí.
Basta seguir o contrato! Mais ainda, cada Autenticavel pode se autenticar de uma maneira
completamentediferentedeoutro.
Lembre-se: a interface define que todos vão saber se autenticar (o que ele faz), enquanto aimplementaçãodefinecomoexatamentevaiserfeito(comoelefaz).
Amaneiracomoosobjetossecomunicamnumsistemaorientadoaobjetosémuitomaisimportantedoquecomoelesexecutam.Oqueumobjetofazémaisimportantedoquecomoelefaz.Aquelesqueseguemessaregra,terãosistemasmaisfáceisdemanteremodificar.Comovocêjápercebeu,estaéumadasideiasprincipaisquequeremospassare,provavelmente,amaisimportantedetodoessecurso.
MAISSOBREINTERFACES:HERANÇAEMÉTODOSDEFAULT
Diferentementedasclasses,umainterfacepodeherdardemaisdeumainterface.Écomoumcontrato que depende que outros contratos sejam fechados antes deste valer. Você não herdamétodoseatributos,massimresponsabilidades.
Um outro recurso em interfaces são os métodos default a partir do Java 8. Você pode simdeclararummétodoconcreto,utilizandoapalavradefaultaolado,esuasimplementaçõesnão
precisamnecessariamente reescrevê-lo.Veremosque isso acontece, por exemplo, comométodoList.sort,duranteocapítulodecoleções.Éumtruquemuitoutilizadoparapoderevoluiruma
interfacesemquebrarcompatibilidadecomasimplementaçõesanteriores.
Interfaces representam uma barreira no aprendizado do Java: parece que estamos escrevendo umcódigoquenãoservepranada, jáque teremosessa linha (aassinaturadométodo)escritanasnossasclassesimplementadoras.Essaéumamaneiraerradadesepensar.Oobjetivodousodeumainterfaceédeixarseucódigomaisflexívelepossibilitaramudançadeimplementaçãosemmaiorestraumas.Nãoéapenasumcódigodeprototipação,umcabeçalho!
Osmais radicais dizem que toda classe deve ser "interfaceada", isto é, só devemos nos referir aobjetos através de suas interfaces. Se determinada classe não tem uma interface, ela deveria ter. Osautoresdestematerialachamtalmedidaradicaldemais,porémousodeinterfacesemvezdeherançaéamplamente aconselhado. Você pode encontrar mais informações sobre o assunto nos livrosDesignPatterns,RefactoringeEffectiveJava.
NolivroDesignPatterns,logonoinício,osautorescitam2regras"deouro".Umaé"eviteherança,prefiracomposição"eaoutra,"programevoltadoainterfaceenãoàimplementação".
11.3DIFICULDADENOAPRENDIZADODEINTERFACES
11.3DIFICULDADENOAPRENDIZADODEINTERFACES 155
Veremosousodeinterfacesnocapítulodecoleções,oquemelhoraoentendimentodoassunto.OexemplodainterfaceComparabletambémémuitoesclarecedor,ondeenxergamosoreaproveitamento
de código através das interfaces, além do encapsulamento. Para o método Collections.sort() ,
pouco importa quem vai ser passado como argumento. Para ele, basta que a coleção seja de objetoscomparáveis.ElepodeordenarElefante,ConexaoouContaCorrente, desdeque implementem
Comparable.
Comofazercomquetodasaschamadasparabancosdedadosdiferentesrespeitemamesmaregra?Usandointerfaces!
ImagineumainterfaceConexaocontendotodososmétodosnecessáriosparaacomunicaçãoetroca
dedadoscomumbancodedados.Cadabancodedadosficaencarregadodecriarasuaimplementaçãoparaessainterface.
QuemforusarumaConexaonãoprecisaseimportarcomqualobjetoexatamenteestátrabalhando,
jáqueelevaicumpriropapelque todaConexao deve ter.Não importa se éumaconexãocomum
OracleouMySQL.
Apesar do java.sql.Connection não trabalhar bem assim, a ideia é muito similar, porém as
conexõesvêmdeumafactorychamadaDriverManager.
Conexãoabancodedadosestáforadoescopodessetreinamento,maséumdosprimeirostópicosabordadosnocursoFJ-21,juntamentecomDAO.
11.4 EXEMPLO INTERESSANTE: CONEXÕES COM O BANCO DEDADOS
156 11.4EXEMPLOINTERESSANTE:CONEXÕESCOMOBANCODEDADOS
UMPOUCOMAIS...
Possosubstituirtodaminhaherançaporinterfaces?Qualéavantagemeadesvantagem?
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
1. Nossobancoprecisatributardinheirodealgunsbensquenossosclientespossuem.Paraissovamoscriarumainterfacenopacotebr.com.caelum.contas.modelodonossoprojetofj11-contasjá
existente:
publicinterfaceTributavel{publicdoublegetValorImposto();}
Lemos essa interface da seguinte maneira: "todos que quiserem ser tributável precisam saberretornarovalordoimposto,devolvendoumdouble".
Alguns bens são tributáveis e outros não, ContaPoupanca não é tributável, já para
ContaCorrentevocêprecisapagar1%dacontaeoSeguroDeVidatemumataxafixade42reais
mais2%dovalordoseguro.
AproveiteoEclipse!QuandovocêescreverimplementsTributavelnaclasseContaCorrente,
o quick fix do Eclipse vai sugerir que você reescreva o método; escolha essa opção e, depois,preenchaocorpodométodoadequadamente:
publicclassContaCorrenteextendsContaimplementsTributavel{
//outrosatributosemétodos
publicdoublegetValorImposto(){
JáconheceoscursosonlineAlura?
11.5EXERCÍCIOS:INTERFACES
11.5EXERCÍCIOS:INTERFACES 157
returnthis.getSaldo()*0.01;}}
CrieaclasseSeguroDeVida,aproveitandonovamentedoEclipse,paraobter:
publicclassSeguroDeVidaimplementsTributavel{privatedoublevalor;privateStringtitular;privateintnumeroApolice;
publicdoublegetValorImposto(){return42+this.valor*0.02;}
//gettersesettersparaosatributos}
Alémdisso,escrevaométodogetTipoparaqueotipodoprodutoapareçanainterfacegráfica:
publicStringgetTipo(){return"SegurodeVida";}
2. Vamos criar a classeManipuladorDeSeguroDeVida dentro do pacote br.com.caelum.contas
paravincularaclasseSeguroDeVida coma tela de criaçãode seguros.Esta classe deve ter um
atributodotipoSeguroDeVida.
Crie também o método criaSeguro que deve receber um parâmetro do tipo Evento para
conseguirobterosdadosda tela.Vocêdevepegarosparâmetros"numeroApolice"do tipoint,
"titular"dotipoStringe"valor"dotipodouble.
Ocódigofinaldeveficarparecidocomocódigoabaixo:
packagebr.com.caelum.contas;
importbr.com.caelum.contas.modelo.SeguroDeVida;importbr.com.caelum.javafx.api.util.Evento;
publicclassManipuladorDeSeguroDeVida{
privateSeguroDeVidaseguroDeVida;
publicvoidcriaSeguro(Eventoevento){this.seguroDeVida=newSeguroDeVida();this.seguroDeVida.setNumeroApolice(evento.getInt("numeroApolice"));this.seguroDeVida.setTitular(evento.getString("titular"));this.seguroDeVida.setValor(evento.getDouble("valor"));}}
3. ExecuteaclasseTestaContasetentecadastrarumnovosegurodevida.Osegurocadastradodeve
aparecernatabeladesegurosdevida.
4. Queremosagorasaberqualovalortotaldosimpostosdetodosostributáveis.Vamosentãocriara
158 11.5EXERCÍCIOS:INTERFACES
classeManipuladorDeTributaveis dentrodopacotebr.com.caelum.contas.Crie tambémo
métodocalculaImpostosquerecebeumparâmetrodotipoEvento:
packagebr.com.caelum.contas;
importbr.com.caelum.javafx.api.util.Evento;
publicclassManipuladorDeTributaveis{
publicvoidcalculaImpostos(Eventoevento){//aquicalcularemosototal}}
5. Agora que criamos o tributavel, vamos habilitar a última aba de nosso sistema. Altere a classeTestaContasparapassarovalortruenachamadadométodomostraTela.Observequeagora
que temos o seguro de vida funcionando, a tela de relatório já consegue imprimir o valor dosimpostosindividuaisdecadatipodeTributavel.
6. NométodocalculaImpostosprecisamosbuscarosvaloresdeimpostosdecadaTributavele
somá-los. Para saber a quantidade de tributáveis, a classe Evento possui ummétodo chamado
getTamanhoDaListaquedevereceberonomedalistadesejada,nocaso"listaTributaveis".Existe
tambémumoutrométodoqueretornaumTributaveldeumadeterminadaposiçãodeumalista,
ondeprecisamospassaronomedalistaeoíndicedoelemento.Precisamospercorreralistainteira,passandoporcadaposiçãoentãoutilizaremosumforparaisto.
packagebr.com.caelum.contas;
importbr.com.caelum.contas.modelo.Tributavel;importbr.com.caelum.javafx.api.util.Evento;
publicclassManipuladorDeTributaveis{
privatedoubletotal;
publicvoidcalculaImpostos(Eventoevento){total=0;inttamanho=evento.getTamanhoDaLista("listaTributaveis");for(inti=0;i<tamanho;i++){Tributavelt=evento.getTributavel("listaTributaveis",i);total+=t.getValorImposto();}}
publicdoublegetTotal(){returntotal;}}
Repare que, de dentro do ManipuladorDeTributaveis , você não pode acessar o método
getSaldo,porexemplo,poisvocênãotemagarantiadequeoTributavelquevaiserpassado
como argumento tem esse método. A única certeza que você tem é de que esse objeto tem os
11.5EXERCÍCIOS:INTERFACES 159
métodosdeclaradosnainterfaceTributavel.
Éinteressanteenxergarqueasinterfaces(comoaqui,nocaso,Tributavel)costumamligarclasses
muito distintas, unindo-as por uma característica que elas tem em comum. No nosso exemplo,SeguroDeVidaeContaCorrentesãoentidadescompletamentedistintas,porémambaspossuema
característicadeseremtributáveis.
SeamanhãogovernocomeçaratributaratémesmoPlanoDeCapitalizacao,bastaqueessaclasse
implemente a interface Tributavel! Repare no grau de desacoplamento que temos: a classe
GerenciadorDeImpostoDeRendanemimaginaquevaitrabalharcomoPlanoDeCapitalizacao.
Para ela, o único fato que importa é que o objeto respeite o contrato de um tributável, isso é, ainterfaceTributavel.Novamente:programevoltadoàinterface,nãoàimplementação.
Quaisosbenefíciosdemanterocódigocombaixoacoplamento?
7. (opcional)CrieaclasseTestaTributavelcomummétodomainparatestaronossoexemplo:
publicclassTestaTributavel{
publicstaticvoidmain(String[]args){ContaCorrentecc=newContaCorrente();cc.deposita(100);System.out.println(cc.getValorImposto());
//testandopolimorfismo:Tributavelt=cc;System.out.println(t.getValorImposto());}}
TentechamarométodogetSaldoatravésdareferênciat,oqueocorre?Porquê?
AlinhaemqueatribuímosccaumTributaveléapenasparavocêenxergarqueépossívelfazê-
lo.Nessenossocaso,issonãotemumautilidade.Essapossibilidadefoiútilnoexercícioanterior.
Atenção: casovocê faça esse exercício, faça issonumprojeto à parteconta-interface já que
usaremosaContacomoclasseemexercíciosfuturos.
1. (Opcional)TransformeaclasseContaemumainterface.
publicinterfaceConta{publicdoublegetSaldo();publicvoiddeposita(doublevalor);publicvoidsaca(doublevalor);publicvoidatualiza(doubletaxaSelic);}
11.6EXERCÍCIOSOPCIONAIS
160 11.6EXERCÍCIOSOPCIONAIS
AdapteContaCorrenteeContaPoupancaparaessamodificação:
publicclassContaCorrenteimplementsConta{//...}
publicclassContaPoupancaimplementsConta{//...}
Algumcódigovaiterdesercopiadoecolado?Issoétãoruim?
2. (Opcional)Àsvezes,éinteressantecriarmosumainterfacequeherdadeoutrasinterfaces:essas,sãochamadassubinterfaces.Essas,nadamaissãodoqueumagrupamentodeobrigaçõesparaaclassequeaimplementar.
publicinterfaceContaTributavelextendsConta,Tributavel{}
Dessamaneira, quem for implementar essa nova interface precisa implementar todos osmétodosherdadosdassuassuperinterfaces(etalvezaindanovosmétodosdeclaradosdentrodela):
publicclassContaCorrenteimplementsContaTributavel{//métodos}
Contac=newContaCorrente();Tributavelt=newContaCorrente();
Reparequeocódigopodeparecerestranho,poisainterfacenãodeclaramétodoalgum,sóherdaosmétodosabstratosdeclaradosnasoutrasinterfaces.
Aomesmotempoqueumainterfacepodeherdardemaisdeumaoutrainterface,classessópodempossuirumaclassemãe(herançasimples).
Discuta com o instrutor e seus colegas, alternativas à herança. Falaremos de herança versuscomposiçãoeporquêaherançaémuitasvezesconsideradamaléfica.
Numaentrevista,JamesGosling,"paidojava",falasobreumalinguagempuramentededelegaçãoechegaadizer:
Rather than subclassing, just use pure interfaces. It's not so much that class inheritance isparticularlybad.Itjusthasproblems.
(Traduçãolivre:"Emvezdefazersubclasses,usesimplesmenteinterfaces.Nãoéqueaherançadeclassessejaparticularmenteruim.Elasótemproblemas.")
11.7 DISCUSSÃO: FAVOREÇA COMPOSIÇÃO EM RELAÇÃO ÀHERANÇA
11.7DISCUSSÃO:FAVOREÇACOMPOSIÇÃOEMRELAÇÃOÀHERANÇA 161
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/
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoJavaeOrientaçãoaObjetos
VocêpodetambémfazerocursodatadessaapostilanaCaelum
162 11.7DISCUSSÃO:FAVOREÇACOMPOSIÇÃOEMRELAÇÃOÀHERANÇA
CAPÍTULO12
"Quempensapouco,erramuito"--LeonardodaVinci
Aotérminodessecapítulo,vocêserácapazde:
controlarerrosetomardecisõesbaseadasnosmesmos;criarnovostiposdeerrosparamelhorarotratamentodelesemsuaaplicaçãooubiblioteca;assegurarqueummétodofuncionoucomodizemseu"contrato".
VoltandoàsContasquecriamosnocapítulo6,oqueaconteceriaaotentarchamarométodosaca
comumvalorforadolimite?Osistemamostrariaumamensagemdeerro,masquemchamouométodosacanãosaberáqueissoaconteceu.
Comoavisaraquelequechamouométododequeelenãoconseguiufazeraquiloquedeveria?
Em Java, osmétodos dizem qual o contrato que eles devem seguir. Se, ao tentar sacar, ele nãoconseguefazeroquedeveria,eleprecisa,aomenos,avisaraousuárioqueosaquenãofoifeito.
Vejanoexemploabaixo:estamosforçandoumaContaaterumvalornegativo,istoé,estarnum
estadoinconsistentedeacordocomanossamodelagem.
ContaminhaConta=newConta();minhaConta.deposita(100);minhaConta.setLimite(100);minhaConta.saca(1000);//osaldoé-900?É100?É0?Achamadaaométodosacafuncionou?
Em sistemas de verdade, é muito comum que quem saiba tratar o erro é aquele que chamou ométodoenãoaprópriaclasse!Portanto,nadamaisnaturaldoqueaclassesinalizarqueumerroocorreu.
A solução mais simples utilizada antigamente é a de marcar o retorno de um método comobooleaneretornartrue,setudoocorreudamaneiraplanejada,oufalse,casocontrário:
booleansaca(doublequantidade){//possosacaratésaldo+limiteif(quantidade>this.saldo+this.limite){System.out.println("Nãopossosacarforadolimite!");returnfalse;}else{
EXCEÇÕESECONTROLEDEERROS
12.1MOTIVAÇÃO
12EXCEÇÕESECONTROLEDEERROS 163
this.saldo=this.saldo-quantidade;returntrue;}}
Umnovoexemplodechamadaaométodoacima:
ContaminhaConta=newConta();minhaConta.deposita(100);minhaConta.setLimite(100);if(!minhaConta.saca(1000)){System.out.println("Nãosaquei");}
Reparequetivemosdelembrardetestaroretornodométodo,masnãosomosobrigadosafazerisso.Esquecerdetestaroretornodessemétodoteriaconsequênciasdrásticas:amáquinadeautoatendimentopoderiaviraliberaraquantiadesejadadedinheiro,mesmoqueosistemanãotivesseconseguidoefetuarométodosacacomsucesso,comonoexemploaseguir:
ContaminhaConta=newConta();minhaConta.deposita(100);
//...doublevalor=5000;minhaConta.saca(valor);//vairetornarfalse,masninguémverifica!caixaEletronico.emite(valor);
Mesmo invocando o método e tratando o retorno de maneira correta, o que faríamos se fossenecessáriosinalizarquandoousuáriopassouumvalornegativocomoquantidade?Umasoluçãoseriaalteraroretornodebooleanparainte retornarocódigodoerroqueocorreu. Issoéconsiderado
umamáprática(conhecidatambémcomousode"magicnumbers").
Alémdevocêperderoretornodométodo,ovalordevolvidoé"mágico"esólegívelperanteextensadocumentação,alémdenãoobrigaroprogramadoratrataresseretornoe,nocasodeesquecerisso,seuprogramacontinuarárodandojánumestadoinconsistente.
Repareoqueaconteceriasefossenecessárioretornarumoutrovalor.Oexemploabaixomostraumcasoonde, atravésdo retorno, não serápossível descobrir seocorreuumerroounão, poisométodoretornaumcliente.
publicClienteprocuraCliente(intid){if(idInvalido){//avisaométodoquechamouestequeocorreuumerro}else{Clientecliente=newCliente();cliente.setId(id);//cliente.setNome("nomedocliente");returncliente;}}
Poresseseoutrosmotivos,utilizamosumcódigodiferenteemJavaparatrataraquiloquechamamosde exceções: os casos onde acontece algo que, normalmente, não iria acontecer. O exemplo do
164 12.1MOTIVAÇÃO
argumentodosaqueinválidooudoidinválidodeumclienteéumaexceçãoàregra.
EXCEÇÃO
Uma exceção representa uma situação que normalmente não ocorre e representa algo deestranhoouinesperadonosistema.
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Antesderesolvermosonossoproblema,vamosvercomoaJavaVirtualMachineageaosedepararcomsituaçõesinesperadas,comodivisãoporzeroouacessoaumíndicedaarrayquenãoexiste.
1. ParaaprendermososconceitosbásicosdasexceptionsdoJava,testeoseguintecódigovocêmesmo:
classTesteErro{publicstaticvoidmain(String[]args){System.out.println("iniciodomain");metodo1();System.out.println("fimdomain");}
staticvoidmetodo1(){System.out.println("iniciodometodo1");metodo2();System.out.println("fimdometodo1");}
staticvoidmetodo2(){System.out.println("iniciodometodo2");ContaCorrentecc=newContaCorrente();for(inti=0;i<=15;i++){cc.deposita(i+1000);
Seuslivrosdetecnologiaparecemdoséculopassado?
12.2EXERCÍCIOPARACOMEÇARCOMOSCONCEITOS
12.2EXERCÍCIOPARACOMEÇARCOMOSCONCEITOS 165
System.out.println(cc.getSaldo());if(i==5){cc=null;}}System.out.println("fimdometodo2");}}
Repareométodomainchamandometodo1eesse,porsuavez,chamandoometodo2.Cadaum
dessesmétodospodetersuasprópriasvariáveislocais,istoé:ometodo1nãoenxergaasvariáveis
declaradasdentrodomaineporaíemdiante.
ComooJava(emuitasdasoutraslinguagens)fazisso?Todainvocaçãodemétodoéempilhadaemuma estrutura de dados que isola a área de memória de cada um. Quando um método termina(retorna),elevoltaparaométodoqueo invocou.Eledescobre issoatravésdapilhade execução(stack):bastaremoveromarcadorqueestánotopodapilha:
Porém, o nosso metodo2 propositadamente possui um enorme problema: está acessando uma
referêncianulaquandooíndiceforiguala6!
Rodeocódigo.Qualéasaída?Oqueissorepresenta?Oqueelaindica?
Essa saída é o conhecido rastro da pilha (stacktrace). É uma saída importantíssima para oprogramador - tanto que, em qualquer fórum ou lista de discussão, é comum os programadoresenviarem,juntamentecomadescriçãodoproblema,essastacktrace.Masporqueissoaconteceu?
O sistema de exceções do Java funciona da seguinte maneira: quando uma exceção é lançada(throw), a JVMentra emestadode alerta evai ver seométodo atual tomaalgumaprecaução aotentarexecutaressetrechodecódigo.Comopodemosver,ometodo2nãotomanenhumamedida
166 12.2EXERCÍCIOPARACOMEÇARCOMOSCONCEITOS
diferentedoquevimosatéagora.
Comoometodo2nãoestá tratandoesseproblema,aJVMpáraaexecuçãodeleanormalmente,
sem esperar ele terminar, e volta um stackframe pra baixo, onde será feita nova verificação: "ometodo1estáseprecavendodeumproblemachamadoNullPointerException?""Não..."Volta
paraomain,ondetambémnãoháproteção,entãoaJVMmorre(naverdade,quemmorreéapenas
a Thread corrente; se quiser saber mais sobre, há um apêndice de Threads e Programação
Concorrentenofinaldaapostila).
Obviamente,aquiestamosforçandoessecasoenãofariasentidotomarmoscuidadocomele.Éfácilarrumar um problema desses: basta verificar antes de chamar osmétodos se a variável está comreferêncianula.
Porém,apenasparaentenderocontroledefluxodeumaException,vamoscolocarocódigoque
vaitentar(try)executaroblocoperigosoe,casooproblemasejadotipoNullPointerException,eleserápego(caught).ReparequeéinteressantequecadaexceçãonoJavatenhaumtipo...elapodeteratributosemétodos.
2. Adicioneumtry/catchemvoltadofor,pegandoNullPointerException.Oqueo código
imprime?
try{for(inti=0;i<=15;i++){cc.deposita(i+1000);System.out.println(cc.getSaldo());if(i==5){cc=null;}}}catch(NullPointerExceptione){System.out.println("erro:"+e);}
12.2EXERCÍCIOPARACOMEÇARCOMOSCONCEITOS 167
3. Emvezdefazerotryemtornodoforinteiro,tenteapenascomoblocodedentrodofor:
for(inti=0;i<=15;i++){try{cc.deposita(i+1000);System.out.println(cc.getSaldo());if(i==5){cc=null;}}catch(NullPointerExceptione){System.out.println("erro:"+e);}}
Qualéadiferença?
4. Retireotry/catchecoloqueeleemvoltadachamadadometodo2.
System.out.println("iniciodometodo1");try{metodo2();}catch(NullPointerExceptione){System.out.println("erro:"+e);}System.out.println("fimdometodo1");
168 12.2EXERCÍCIOPARACOMEÇARCOMOSCONCEITOS
5. Façaomesmo,retirandootry/catchnovamenteecolocandoemvoltadachamadadometodo1.
Rodeoscódigos,oqueacontece?
System.out.println("iniciodomain");try{metodo1();}catch(NullPointerExceptione){System.out.println("erro:"+e);}System.out.println("fimdomain");
Repareque,apartirdomomentoqueumaexceptionfoicatched(pega,tratada,handled),aexecuçãovoltaaonormalapartirdaqueleponto.
12.3EXCEÇÕESDERUNTIMEMAISCOMUNS
12.3EXCEÇÕESDERUNTIMEMAISCOMUNS 169
Quetaltentardividirumnúmeroporzero?SeráqueaJVMconseguefazeraquiloquenósdefinimosquenãoexiste?
publicclassTestandoADivisao{
publicstaticvoidmain(String[]args){inti=5571;i=i/0;System.out.println("Oresultado"+i);}}
Tenteexecutaroprogramaacima.Oqueacontece?
ReparequeumNullPointerExceptionpoderiaserfacilmenteevitadocomumifquechecaria
seareferênciaédiferentedenull.
Outrocasoemquetambémocorretaltipodeexceçãoéquandoumcasterradoéfeito(veremosmaisprafrente).Emtodososcasos,taisproblemasprovavelmentepoderiamserevitadospeloprogramador.É por esse motivo que o java não te obriga a dar o try/catch nessas exceptions e chamamos essasexceções de unchecked. Em outras palavras, o compilador não checa se você está tratando essasexceções.
ERROS
OserrosemJava sãoum tipodeexceçãoque tambémpodemser tratados.Eles representamproblemasnamáquinavirtualenãodevemsertratadosem99%doscasos,jáqueprovavelmenteomelhorasefazerédeixaraJVMencerrar(ouapenasaThreademquestão).
Ficaclaro,comosexemplosdecódigoacima,quenãoénecessáriodeclararquevocêestátentandofazeralgoondeumerropossaocorrer.Osdoisexemplos,comousemotry/catch, compilarame
rodaram.Emum,oerroterminouoprogramae,nooutro,foipossíveltratá-lo.
Mas não é só esse tipo de exceção que existe em Java. Um outro tipo, obriga a quem chama ométodo ou construtor a tratar essa exceção. Chamamos esse tipo de exceção de checked, pois ocompilador checará se ela está sendo devidamente tratada, diferente das anteriores, conhecidas como
12.4OUTROTIPODEEXCEÇÃO:CHECKEDEXCEPTIONS
170 12.4OUTROTIPODEEXCEÇÃO:CHECKEDEXCEPTIONS
unchecked.
Umexemplointeressanteéodeabrirumarquivoparaleitura,ondepodeocorreroerrodoarquivonãoexistir(veremoscomotrabalharcomarquivosemoutrocapítulo,nãosepreocupecomistoagora):
classTeste{publicstaticvoidmetodo(){newjava.io.FileInputStream("arquivo.txt");}}
O código acima não compila e o compilador avisa que é necessário tratar oFileNotFoundExceptionquepodeocorrer:
Paracompilarefazeroprogramafuncionar,temosduasmaneirasquepodemostrataroproblema.Oprimeiro,étratá-locomotryecatchdomesmojeitoqueusamosnoexemploanterior,dereferência
nula:
publicstaticvoidmetodo(){
try{newjava.io.FileInputStream("arquivo.txt");}catch(java.io.FileNotFoundExceptione){System.out.println("Naofoipossívelabriroarquivoparaleitura");}
}
Asegundaformadetrataresseerro,édelegareleparaquemchamouonossométodo,istoé,passarparaafrente.
publicstaticvoidmetodo()throwsjava.io.FileNotFoundException{
newjava.io.FileInputStream("arquivo.txt");
}
NoEclipseébemsimplesfazertantoumtry/catchcomoumthrows:
Tentedigitaressecódigonoeclipse:
publicclassTestaException{publicstaticvoidmain(String[]args){newjava.io.FileInputStream("arquivo.txt");}}
OEclipsevaireclamar:
12.4OUTROTIPODEEXCEÇÃO:CHECKEDEXCEPTIONS 171
Evocêtemduasopções:
Addthrowsdeclaration,quevaigerar:
publicclassTestaException{publicstaticvoidmain(String[]args)throwsFileNotFoundException{newjava.io.FileInputStream("arquivo.txt");}}
Surroundwithtry/catch,quevaigerar:
publicclassTestaException2{publicstaticvoidmain(String[]args){try{newjava.io.FileInputStream("arquivo.txt");}catch(FileNotFoundExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}}}
Noinício,existeumagrandetentaçãodesemprepassaroproblemaprafrenteparaoutrosotratarem.Podeserquefaçasentido,dependendodocaso,masnãoatéomain,porexemplo.Acontecequequemtenta abrir um arquivo sabe como lidar com um problema na leitura. Quem chamou ummétodo nocomeçodoprogramapodenãosaberou,piorainda, tentarabrircincoarquivosdiferentesenãosaberqualdelesteveumproblema!
Não há uma regra para decidir em que momento do seu programa você vai tratar determinadaexceção. Isso vai depender de em que ponto você tem condições de tomar uma decisão em relaçãoàqueleerro.Enquantonãoforomomento,vocêprovavelmentevaipreferirdelegararesponsabilidadeparaométodoqueteinvocou.
172 12.4OUTROTIPODEEXCEÇÃO:CHECKEDEXCEPTIONS
BOASPRÁTICASNOTRATAMENTODEEXCEÇÕES
NoblogdaCaelumháumextensoartigodiscutindoasboaspráticasemrelaçãoaotratamentodeexceções.
http://blog.caelum.com.br/2006/10/07/lidando-com-exceptions/
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
UmapequenapartedaFamíliaThrowable:
Agoraéamelhorhoradeaprenderalgonovo
12.5UMPOUCODAGRANDEFAMÍLIATHROWABLE
12.5UMPOUCODAGRANDEFAMÍLIATHROWABLE 173
Épossíveltratarmaisdeumerroquasequeaomesmotempo:
Comotryecatch:
try{objeto.metodoQuePodeLancarIOeSQLException();}catch(IOExceptione){//..}catch(SQLExceptione){//..}
Comothrows:
publicvoidabre(Stringarquivo)throwsIOException,SQLException{//..}
Vocêpode,também,escolhertrataralgumasexceçõesedeclararasoutrasnothrows:
publicvoidabre(Stringarquivo)throwsIOException{try{objeto.metodoQuePodeLancarIOeSQLException();}catch(SQLExceptione){//..}}
É desnecessário declarar no throws as exceptions que são unchecked, porém é permitido e às
vezes,facilitaaleituraeadocumentaçãodoseucódigo.
Lembre-sedométodosacadanossaclasseConta.Eledevolveumboolean casoconsigaou
nãosacar:
publicbooleansaca(doublevalor){if(this.saldo<valor){returnfalse;}else{this.saldo-=valor;returntrue;}}
Podemos,também,lançarumaException,oqueéextremamenteútil.Dessamaneira,resolvemos
oproblemadealguémpoderesquecerdefazerumifnoretornodeummétodo.
Apalavrachave throw, que está no imperativo, lançaumaException. Isto é bemdiferente dethrows,queestánopresentedoindicativo,equeapenasavisadapossibilidadedaquelemétodolançá-
la,obrigandoooutrométodoqueváutilizardestedesepreocuparcomessaexceçãoemquestão.
12.6MAISDEUMERRO
12.7LANÇANDOEXCEÇÕES
174 12.6MAISDEUMERRO
publicvoidsaca(doublevalor){if(this.saldo<valor){thrownewRuntimeException();}else{this.saldo-=valor;}}
Nonossocaso, lançaumadotipounchecked.RuntimeExceptionéaexceptionmãede todasas
exceptionsunchecked.Adesvantagem, aqui, é que ela émuito genérica; quem receber esse erro nãosabedizerexatamentequalfoioproblema.PodemosentãousarumaExceptionmaisespecífica:
publicvoidsaca(doublevalor){if(this.saldo<valor){thrownewIllegalArgumentException();}else{this.saldo-=valor;}}
IllegalArgumentExceptiondizumpoucomais:algofoipassadocomoargumentoeseumétodo
não gostou. Ela é uma Exception unchecked pois estende de RuntimeException e já faz parte da
bibliotecadojava.(IllegalArgumentExceptionéamelhorescolhaquandoumargumentosempreé
inválidocomo,porexemplo,númerosnegativos,referênciasnulas,etc).
Parapegaresseerro,nãousaremosumif/elseesimumtry/catch,porquefazmaissentidojá
queafaltadesaldoéumaexceção:
Contacc=newContaCorrente();cc.deposita(100);
try{cc.saca(100);}catch(IllegalArgumentExceptione){System.out.println("SaldoInsuficiente");}
PodíamosmelhoraraindamaisepassarparaoconstrutordaIllegalArgumentExceptionomotivo
daexceção:
publicvoidsaca(doublevalor){if(this.saldo<valor){thrownewIllegalArgumentException("Saldoinsuficiente");}else{this.saldo-=valor;}}
Ométodo getMessage() definido na classe Throwable (mãe de todos os tipos de erros e
exceptions)vairetornaramensagemquepassamosaoconstrutordaIllegalArgumentException.
try{cc.saca(100);}catch(IllegalArgumentExceptione){System.out.println(e.getMessage());
12.7LANÇANDOEXCEÇÕES 175
}
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Imaginequevamossacardinheirodediversascontas:
Contacc=newContaCorrente();cc.deposita(100);
Contacp=newContaPoupanca();cp.deposita(100);
//sacandodascontas:
cc.saca(50);System.out.println("conseguisacardacorrente!");
cp.saca(50);System.out.println("conseguisacardapoupança!");
Podemosescolhervárioslugaresparacolocartry/catch:
try{cc.saca(50);}catch(IllegalArgumentExceptione){System.out.println(e.getMessage());}System.out.println("conseguisacardacorrente!");
try{cp.saca(50);}catch(IllegalArgumentExceptione){System.out.println(e.getMessage());}System.out.println("conseguisacardapoupança!");
Essa não parece umaopção boa, pois amensagem "consegui sacar" será impressamesmo que ocatchsejaacionado.Semprequetemosalgoquedependedalinhadecimaparasercorreto,devemos
EditoraCasadoCódigocomlivrosdeumaformadiferente
12.8OQUECOLOCARDENTRODOTRY?
176 12.8OQUECOLOCARDENTRODOTRY?
agrupá-lonotry:
try{cc.saca(50);System.out.println("conseguisacardacorrente!");}catch(IllegalArgumentExceptione){System.out.println(e.getMessage());}
try{cp.saca(50);System.out.println("conseguisacardapoupança!");}catch(IllegalArgumentExceptione){System.out.println(e.getMessage());}
Mas há ainda uma outra opção: imagine que, para o nosso sistema, uma falha ao sacar da contapoupançadevepararoprocessodesaquesenemtentarsacardacontacorrente.Paraisso,agruparíamosmaisainda:
try{cc.saca(50);System.out.println("conseguisacardacorrente!");cp.saca(50);System.out.println("conseguisacardapoupança!");}catch(IllegalArgumentExceptione){System.out.println(e.getMessage());}
Oquevocêvaicolocardentrodotryinfluenciamuitoaexecuçãodoprograma!Pensedireitonaslinhasquedependemumadaoutraparaaexecuçãocorretadasualógicadenegócios.
Ébemcomumcriarumaprópriaclassedeexceçãoparacontrolarmelhorousodesuasexceções.Dessamaneira,podemospassarvaloresespecíficosparaelacarregar,quesejamúteisdealgumaforma.Vamoscriaranossa:
Voltamos para o exemplo das Contas , vamos criar a nossa Exceção de
SaldoInsuficienteException:
publicclassSaldoInsuficienteExceptionextendsRuntimeException{
publicSaldoInsuficienteException(Stringmessage){super(message);}}
Emvezde lançar umIllegalArgumentException, vamos lançar nossaprópria exception, com
umamensagemquedirá"SaldoInsuficiente":
publicvoidsaca(doublevalor){if(this.saldo<valor){thrownewSaldoInsuficienteException("SaldoInsuficiente,"+
12.9CRIANDOSEUPRÓPRIOTIPODEEXCEÇÃO
12.9CRIANDOSEUPRÓPRIOTIPODEEXCEÇÃO 177
"tenteumvalormenor");}else{this.saldo-=valor;}}
E,paratestar,crieumaclassequedepositeumvaloretentesacarumvalormaior:
publicstaticvoidmain(String[]args){Contacc=newContaCorrente();cc.deposita(10);
try{cc.saca(100);}catch(SaldoInsuficienteExceptione){System.out.println(e.getMessage());}}
PodemostransformaressaExceptiondeuncheckedparachecked,obrigandoaquemchamaesse
métodoadartry-catch,outhrows:
publicclassSaldoInsuficienteExceptionextendsException{
publicSaldoInsuficienteException(Stringmessage){super(message);}}
Osblocostryecatchpodemconterumaterceiracláusulachamadafinallyqueindicaoque
deveserfeitoapósotérminodoblocotryoudeumcatchqualquer.
É interessante colocar algo que é imprescindível de ser executado, caso o que você queria fazertenhadadocerto,ounão.Ocasomaiscomuméodeliberarumrecursonofinally,comoumarquivoouconexãocombancodedados,paraquepossamosteracertezadequeaquelearquivo(ouconexão)váserfechado,mesmoquealgotenhafalhadonodecorrerdocódigo.
Noexemploaseguir,oblocofinallyserásempreexecutado,independentementedetudoocorrer
bemoudeaconteceralgumproblema:
try{//blocotry}catch(IOExceptionex){//blococatch1}catch(SQLExceptionsqlex){//blococatch2}finally{//blocoqueserásempreexecutado,independente//sehouveounãoexceptioneseelafoitratadaounão}
Há também, no Java 7, um recurso poderoso conhecido como try-with-resources, que permite
12.10PARASABERMAIS:FINALLY
178 12.10PARASABERMAIS:FINALLY
utilizarasemânticadofinallydeumamaneirabemmaissimples.
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
1. Na classeConta,modifique ométododeposita(doublex): Ele deve lançar uma exception
chamadaIllegalArgumentException,quejáfazpartedabibliotecadoJava,semprequeovalor
passadocomoargumentoforinválido(porexemplo,quandofornegativo).
publicvoiddeposita(doublevalor){if(valor<0){thrownewIllegalArgumentException();}else{this.saldo+=valor;}}
2. Rodeaaplicação,cadastreumacontaetentedepositarumvalornegativo.Oqueacontece?
3. Ao lançar a IllegalArgumentException, passe via construtor uma mensagem a ser exibida.
LembrequeaStringrecebidacomoparâmetroéacessíveldepoisviaométodogetMessage()
herdadoportodasasExceptions.
publicvoiddeposita(doublevalor){if(valor<0){thrownewIllegalArgumentException("Vocêtentoudepositar"+"umvalornegativo");}else{this.saldo+=valor;}}
Rodeaaplicaçãonovamenteevejaqueagoraamensagemaparecenatela.
4. FaçaomesmoparaométodosacadaclasseContaCorrente,afinaloclientetambémnãopode
JáconheceoscursosonlineAlura?
12.11EXERCÍCIOS:EXCEÇÕES
12.11EXERCÍCIOS:EXCEÇÕES 179
sacarumvalornegativo!
5. Vamosvalidartambémqueoclientenãopodesacarumvalormaiordoqueosaldodisponívelemconta.CriesuaprópriaException,SaldoInsuficienteException.Paraisso,vocêprecisacriar
umaclassecomessenomequesejafilhadeRuntimeException.
publicclassSaldoInsuficienteExceptionextendsRuntimeException{
}
NométodosacadaclasseContaCorrentevamosutilizarestanovaException:
@Overridepublicvoidsaca(doublevalor){if(valor<0){thrownewIllegalArgumentException("Vocêtentousacarumvalornegativo");}if(this.saldo<valor){thrownewSaldoInsuficienteException();}this.saldo-=(valor+0.10);}
Atenção:nemsempreéinteressantecriarmosumnovotipodeexception!Dependedocaso.Nesteaqui,seriamelhoraindautilizarmosIllegalArgumentException.Aboapráticadizquedevemos
preferirusarasjáexistentesdoJavasemprequepossível.
6. (opcional)ColoqueumconstrutornaclasseSaldoInsuficienteExceptionquerecebaovalorque
eletentousacar(istoé,elevaireceberumdoublevalor).
Quandoestendemosumaclasse,nãoherdamosseusconstrutores,maspodemosacessá-losatravésdapalavra chave super de dentro de um construtor. As exceções do Java possuem uma série de
construtores úteis para poder populá-las já com uma mensagem de erro. Então vamos criar umconstrutoremSaldoInsuficienteExceptionquedelegueparaoconstrutordesuamãe.Essavai
guardaressamensagemparapodermostrá-laaoserinvocadoométodogetMessage:
publicclassSaldoInsuficienteExceptionextendsRuntimeException{
publicSaldoInsuficienteException(doublevalor){super("Saldoinsuficienteparasacarovalorde:"+valor);}}
Dessamaneira, na hora de dar o throw new SaldoInsuficienteException você vai precisar
passaressevalorcomoargumento:
if(this.saldo<valor){thrownewSaldoInsuficienteException(valor);}
Atenção: você pode se aproveitar do Eclipse para isso: comece já passando o valor como
180 12.11EXERCÍCIOS:EXCEÇÕES
argumentoparaoconstrutordaexceptioneoEclipsevaireclamarquenãoexistetalconstrutor.Oquickfix(ctrl+1)vaisugerirqueelesejaconstruindo,poupando-lhetempo!
Eagora,comoficaométodosacadaclasseContaCorrente?
7. (opcional)DeclareaclasseSaldoInsuficienteExceptioncomofilhadiretadeException em
vezdeRuntimeException.Elapassaaserchecked.Oqueissoresulta?
Vocêvaiprecisaravisarqueoseumétodosaca()throwsSaldoInsuficienteException,pois
elaéumacheckedexception.Alémdisso,quemchamaessemétodovaiprecisartomarumadecisãoentretry-catchouthrows.FaçausodoquickfixdoEclipsenovamente!
Depois, retorne a exception para unchecked, isto é, para ser filha de RuntimeException, pois
utilizaremoselaassimemexercíciosdoscapítulosposteriores.
1. Oqueaconteceseacabaramemóriadajavavirtualmachine?
Existeumapéssimapráticadeprogramaçãoemjavaqueéadeescreverocatcheothrowscom
Exception.
ExistemcódigosquesempreusamExceptionpoisissocuidadetodosospossíveiserros.Omaior
problemadissoégeneralizaroerro.Sealguém jogaalgodo tipoException para quemo chamou,
quemrecebenãosabequalotipoespecíficodeerroocorreuenãovaisabercomotrataromesmo.
Sim,hácasosondeotratamentodemaisdeumaexceptionpodeserfeitodeumamesmamaneira.Por exemplo, se queremos terminar a aplicação tanto no caso de IOException quanto em
SQLException . Se fizermos catch(Exception e) para pegar esses dois casos, teremos um
problema:aaplicaçãovaipararmesmoqueoutraexceçãosejalançada.Asoluçãocorretaseriaterdoiscatches,masaíteríamoscódigorepetido.Paraevitarocódigorepetido,podemosusaromulti-catchdoJava 7, que permite um mesmo catch cuidar de mais de 1 exceção, através da sintaxecatch(IOException|SQLExceptione){...}.
12.12DESAFIOS
12.13DISCUSSÃOEMAULA:CATCHETHROWSEMEXCEPTION
12.12DESAFIOS 181
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoJavaeOrientaçãoaObjetos
VocêpodetambémfazerocursodatadessaapostilanaCaelum
182 12.13DISCUSSÃOEMAULA:CATCHETHROWSEMEXCEPTION
CAPÍTULO13
"Nossascabeçassãoredondasparaqueospensamentospossammudardedireção."--FrancisPiacaba
Aotérminodessecapítulo,vocêserácapazde:
utilizarasprincipaisclassesdopacotejava.langeleradocumentaçãopadrãodeprojetosjava;
usaraclasseSystemparaobterinformaçõesdosistema;
utilizaraclasseStringdeumamaneiraeficienteeconhecerseusdetalhes;
utilizarosmétodosherdadosdeObjectparageneralizarseuconceitodeobjetos.
Jáusamos,pordiversasvezes,asclassesStringeSystem.VimososistemadepacotesdoJavae
nunca precisamos dar um import nessas classes. Isso ocorre porque elas estão dentro do pacote
java.lang,queéautomaticamenteimportadoparavocê.Éoúnicopacotecomestacaracterística.
Vamosverumpoucodesuasprincipaisclasses.
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
A classe System possui uma série de atributos e métodos estáticos. Já usamos o atributo
OPACOTEJAVA.LANG
13.1PACOTEJAVA.LANG
Seuslivrosdetecnologiaparecemdoséculopassado?
13.2UMPOUCOSOBREACLASSESYSTEM
13OPACOTEJAVA.LANG 183
System.out,paraimprimir.
Olhandoadocumentação,vocêvaiperceberqueoatributooutédotipoPrintStreamdopacote
java.io.Veremos sobre essa classemais adiante. Já podemos perceber que poderíamos quebrar o
System.out.printlnemduaslinhas:
PrintStreamsaida=System.out;saida.println("olamundo!");
OSystemcontatambémcomummétodoquesimplesmentedesligaavirtualmachine,retornando
umcódigodeerroparaosistemaoperacional,éoexit.
System.exit(0);
VeremostambémumpoucomaissobreaclasseSystemnospróximoscapítulosenoapêndicede
Threads.ConsulteadocumentaçãodoJavaevejaoutrosmétodosúteisdaSystem.
Todométodoque precisamos receber algumparâmetro temos que declarar o tipo domesmo.Porexemplo,nonossométodosacaprecisamospassarcomoparâmetroumvalordo tipodouble. Se
tentarmospassarqualquercoisadiferentedissoteremosumerrodecompilação.
AgoravamosobservaroseguintemétododopróprioJava:
System.out.println("Olámundo!");
Nestecaso,ométodoprintlnestárecebendoumaString epoderíamospensarqueo tipode
parâmetroqueelerecebeéString.Masaomesmo tempopodemospassarparaessemétodocoisas
completamente diferentes como int, Conta, Funcionario, SeguroDeVida, etc. Como esse
métodoconseguerecebertantosparâmetrosdetiposdiferentes?
Umapossibilidade seria o uso da sobrecarga, declarando umprintln para cada tipo de objeto
diferente.Mas claramente não é isso que acontece já que conseguimos criar uma classe qualquer einvocarométodoprintlnpassandoessanovaclassecomoparâmetroeelefuncionaria!
Paraentenderoqueestáacontecendo,vamosconsiderarummétodoquerecebeumaConta:
publicvoidimprimeDados(Contaconta){System.out.println(conta.getTitular()+"-"+conta.getSaldo());}
Esse método pode ser invocado passando como parâmetro qualquer tipo de conta que temos nonossosistema:ContaCorrenteeContaPoupancapoisambassãofilhasdeConta.Sequiséssemos
queonossométodoconseguissereceberqualquertipodeobjetoteríamosqueterumaclassequefossemãedetodosessesobjetos.ÉparaissoqueexisteaclasseObject!
13.3JAVA.LANG.OBJECT
184 13.3JAVA.LANG.OBJECT
Semprequandodeclaramosumaclasse,essaclasseéobrigadaaherdardeoutra.Istoé,paratodaclasse que declararmos, existe uma superclasse. Porém, criamos diversas classes sem herdar deninguém:
classMinhaClasse{
}
QuandooJavanãoencontraapalavrachaveextends, ele consideraquevocêestáherdandoda
classeObject,quetambémseencontradentrodopacotejava.lang.Vocêatémesmopodeescrever
essaherança,queéomesmo:
publicclassMinhaClasseextendsObject{
}
Todasasclasses,semexceção,herdamdeObject,sejadiretaouindiretamente,poiselaéamãe,vó,bisavó,etcdequalquerclasse.
Podemos tambémafirmarquequalquerobjeto emJavaéumObject, podendo ser referenciado
como tal. Então, qualquer objeto possui todos osmétodos declarados na classe Object e veremos
algunsdeleslogoapósocasting.
A habilidade de poder se referir a qualquer objeto como Object nos traz muitas vantagens.
Podemos criar um método que recebe um Object como argumento, isto é, qualquer objeto! Por
exemplo,ométodoprintlnpoderiaserimplementadodaseguintemaneira:
publicvoidprintln(Objectobj){write(obj.toString());//ométodowriteescreveumastringnoconsole}
Dessaforma,qualquerobjetoquepassarmoscomoparâmetropoderáserimpressonoconsoledesdequeelepossuaométodotoString.ParagarantirquetodososobjetosdoJavapossuamessemétodo,
elefoiimplementadonaclasseObject.
Por padrão, o método toString do Object retorna o nome da classe @ um número de
identidade:
Conta@34f5d74a
Masesequisermosimprimiralgodiferente?Nanossateladedetalhesdeconta,temosumacaixadeseleçãoondenossascontasestãosendoapresentadascomovalordopadrãodotoString.Sempreque
queremos modificar o comportamento de um método em relação a implementação herdada da
13.4MÉTODOSDOJAVA.LANG.OBJECT:EQUALSETOSTRING
toString
13.4MÉTODOSDOJAVA.LANG.OBJECT:EQUALSETOSTRING 185
superclasse,podemossobrescrevê-lonaclassefilha:
publicabstractclassConta{protecteddoublesaldo;//outrosatributos...
@OverridepublicStringtoString(){return"[titular="+titular+",numero="+numero+",agencia="+agencia+"]";}}
Agorapodemosusaressemétodoassim:
ContaCorrentecc=newContaCorrente();System.out.println(cc.toString());
E omelhor, se for apenas para jogar na tela, você nem precisa chamar o toString! Ele já é
chamadoparavocê:
ContaCorrentecc=newContaCorrente();System.out.println(cc);//OtoStringéchamadopelaclassePrintStream
Geraomesmoresultado!
VocêaindapodeconcatenarStringsemJavacomooperador+.SeoJavaencontraumobjetono
meiodaconcatenação,eletambémchamaotoStringdele.
ContaCorrentecc=newContaCorrente();System.out.println("Conta:"+cc);
Atéagoraestamosignorandoofatoquepodemosmaisdeumacontademesmonúmeroeagêncianonossosistema.Atualmente,quandoinserimosumanovaconta,osistemaverificaseacontainseridaéigualaalgumaoutracontajácadastrada.Masqualcritériodeigualdadeéutilizadoporpadrãoparafazeressaverificação?
Assim como no caso dotoString, todos objetos do Java possuem um outrométodo chamado
equalsqueéutilizadoparacompararobjetosdaqueletipo.Porpadrão,essemétodoapenascompara
asreferênciasdosobjetos.Comotodavezqueinserimosumanovacontanosistemaestamosfazendonewemalgumtipodeconta,asreferênciasnuncavãoseriguais,mesmoosdados(númeroeagência)
sendoiguais.
Mas,esefosseprecisocompararosatributos?Quaisatributoseledeveriacomparar?OJavaporsisónãofazisso,maspodemossobrescreveroequalsdaclasseObjectparacriarmosessecritériode
comparação.
OequalsrecebeumObjectcomoargumentoedeveverificarseelemesmoéigualaoObject
equals
186 13.4MÉTODOSDOJAVA.LANG.OBJECT:EQUALSETOSTRING
recebidopararetornarumboolean.Sevocênãoreescreveressemétodo,ocomportamentoherdadoé
fazerum==comoobjetorecebidocomoargumento.
publicabstractclassConta{protecteddoublesaldo;//outrosatributos...
publicbooleanequals(Objectobject){//primeiroverificaseooutroobjectnãoénuloif(object==null){returnfalse;}
if(this.numero==object.numero&&this.agencia.equals(object.agencia)){returntrue;}returnfalse;}}
NomomentoquerecebemosumareferênciaparaumObject,comovamosacessarosmétodose
atributosdesseobjetoqueimaginamosserumaConta?Seestamosreferenciando-ocomoObject,
nãopodemosacessá-locomosendoConta.Ocódigoacimanãocompila!
PoderíamosentãoatribuiressareferênciadeObjectparaContaparadepoisacessarosatributos
necessários?Tentemos:
ContaoutraConta=object;
NóstemoscertezadequeesseObject se refereaumaConta, jáqueanossa lista só imprime
contas.MasocompiladorJavanãotemgarantiassobreisso!Essalinhaacimanãocompila,poisnemtodoObjectéumaConta.
Pararealizaressaatribuição,paraissodevemos"avisar"ocompiladorJavaquerealmentequeremosfazer isso, sabendodo riscoquecorremos.Fazemosocastingdereferências, parecido comde tiposprimitivos:
ContaoutraConta=(Conta)object;
Ocódigopassaacompilar,masseráqueroda?Essecódigorodasemnenhumproblema,poisemtempodeexecuçãoaJVMverificaráseessareferênciarealmenteéparaumobjetodetipoConta, e
está!Senãoestivesse,umaexceçãodotipoClassCastExceptionserialançada.
Comisso,nossométodoequalsficariaassim:
publicabstractclassConta{protecteddoublesaldo;//outrosatributos...
Castingdereferências
13.4MÉTODOSDOJAVA.LANG.OBJECT:EQUALSETOSTRING 187
publicbooleanequals(Objectobject){if(object==null){returnfalse;}
ContaoutraConta=(Conta)object;if(this.numero==outraConta.numero&&this.agencia.equals(outraConta.agencia)){returntrue;}returnfalse;}}
VocêpoderiacriarummétodocomoutronomeemvezdereescreverequalsquerecebeObject,
mas ele é importante poismuitas bibliotecas o chamam através do polimorfismo, como veremos nocapítulodojava.util.
O método hashCode() anda de mãos dadas com o método equals() e é de fundamental
entendimento no caso de você utilizar suas classes com estruturas de dados que usam tabelas deespalhamento.Tambémfalaremosdelenocapítulodejava.util.
REGRASPARAAREESCRITADOMÉTODOEQUALS
Pelo contrato definido pela classe Object devemos retornar false também no caso do
objetopassadonãoserdetipocompatívelcomasuaclasse.Entãoantesdefazerocastingdevemosverificarisso,eparatalusamosapalavrachaveinstanceof,outeríamosumaexceptionsendo
lançada.
Alémdisso,podemosresumirnossoequalsdetalformaanãousarumif:
publicbooleanequals(Objectobject){if(object==null){returnfalse;}if(!(objectinstanceofConta)){returnfalse;}ContaoutraConta=(Conta)object;return(this.numero==outraConta.numero&&this.agencia.equals(outraConta.agencia));}
188 13.4MÉTODOSDOJAVA.LANG.OBJECT:EQUALSETOSTRING
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
1. Comoverificar seaclasseThrowable que é a superclassedeException também reescreveo
métodotoString?
AmaioriadasclassesdoJavaquesãomuitoutilizadasterãoseusmétodosequalsetoString
reescritosconvenientemente.
2. Utilize-sedadocumentaçãodoJavaedescubradequeclasseéoobjetoreferenciadopeloatributooutdaSystem.
Repareque,comodevidoimport,poderíamosescrever:
//faltaadeclaraçãodasaída________saida=System.out;saida.println("ola");
Avariávelsaida precisa ser declaradadeque tipo?É issoquevocêprecisa descobrir. Sevocê
digitaressecódigonoEclipse,elevaitesugerirumquickfixedeclararáavariávelparavocê.
Estudaremosessaclasseemumcapítulofuturo.
3. Rodeaaplicaçãoecadastreduascontas.Na teladedetalhesdeconta,verifiqueoqueaparecenacaixadeseleçãodecontaparatransferência.Porqueissoacontece?
4. Reescreva ométodo toString da sua classe Conta fazendo com que uma mensagem mais
explicativa seja devolvida. Lembre-se de aproveitar dos recursos do Eclipse para isto: digitandoapenasocomeçodonomedométodoaserreescritoepressionandoctrl+espaço,elevai sugerirreescrever o método, poupando o trabalho de escrever a assinatura do método e cometer algumengano.
publicabstractclassConta{
Agoraéamelhorhoradeaprenderalgonovo
13.5EXERCÍCIOS:JAVA.LANG.OBJECT
13.5EXERCÍCIOS:JAVA.LANG.OBJECT 189
protecteddoublesaldo;
@OverridepublicStringtoString(){return"[titular="+titular+",numero="+numero+",agencia="+agencia+"]";}//restantedaclasse
}
Rode a aplicação novamente, cadastre duas contas e verifique novamente a caixa de seleção datransferência.Oqueaconteceu?
5. Reescrevaométodoequals da classe Conta para que duas contas com omesmonúmero eagênciasejamconsideradasiguais.Esboço:
publicabstractclassConta{
publicbooleanequals(Objectobj){if(obj==null){returnfalse;}
ContaoutraConta=(Conta)obj;
returnthis.numero==outraConta.numero&&this.agencia.equals(outraConta.agencia);}}
Vocêpodeusar octrl+ espaço doEclipsepara escrever o esqueletodométodoequals, bastadigitardentrodaclasseequepressionarctrl+espaço.
Rodeaaplicaçãoetenteadicionarduascontascomomesmonúmeroeagência.Oqueacontece?
StringéumaclasseemJava.VariáveisdotipoStringguardamreferênciasaobjetos,enãoum
valor,comoacontececomostiposprimitivos.
Aliás,podemoscriarumaStringutilizandoonew:
Stringx=newString("fj11");Stringy=newString("fj11");
Criamosaqui,doisobjetosdiferentes.Oqueacontecequandocomparamosessasduas referênciasutilizandoo==?
if(x==y){System.out.println("referênciaparaomesmoobjeto");}else{System.out.println("referênciasparaobjetosdiferentes!");
13.6JAVA.LANG.STRING
190 13.6JAVA.LANG.STRING
}
Temosaquidoisobjetosdiferentes!E,então,comofaríamosparaverificarseoconteúdodoobjetoéomesmo?Utilizamosométodoequals,quefoireescritopelaString,parafazeracomparaçãode
charemchar.
if(x.equals(y)){System.out.println("consideramosiguaisnocritériodeigualdade");}else{System.out.println("consideramosdiferentesnocritériodeigualdade");}
Aqui,acomparaçãoretornaverdadeiro.Porquê?PoisquemimplementouaclasseStringdecidiu
queesteseriaomelhorcritériodecomparação.Vocêpodedescobriroscritériosdeigualdadedecadaclassepeladocumentação.
PodemostambémconcatenarStringsusandoo+.PodemosconcatenarStringscomqualquer
objeto,atémesmonúmeros:
inttotal=5;System.out.println("ototalgastoé:"+total);
O compilador utilizará os métodos apropriados da classe String e possivelmente métodos de
outrasclassespararealizartaltarefa.
SequisermoscompararduasStrings,utilizamosométodocompareTo,querecebeumaString
comoargumentoedevolveum inteiro indicandoseaString vemantes, é igual ouvemdepois da
Stringrecebida.Seforemiguais,édevolvido0;seforanterioràStringdoargumento,devolve
uminteironegativo;e,seforposterior,uminteiropositivo.
Fatoimportante:umaStringéimutável.OjavacriaumpooldeStringsparausarcomocachee,seaStringnãofosseimutável,mudandoovalordeumaStringafetariatodasasStringsdeoutras
classesquetivessemomesmovalor.
Reparenocódigoabaixo:
Stringpalavra="fj11";palavra.toUpperCase();System.out.println(palavra);
Pode parecer estranho,mas ele imprime "fj11" emminúsculo. Todométodo que parece alterar ovalordeumaString,naverdade,criaumanovaStringcomasmudançassolicitadasearetorna!
Tantoqueessemétodonãoévoid.Ocódigorealmenteútilficariaassim:
Stringpalavra="fj11";Stringoutra=palavra.toUpperCase();System.out.println(outra);
Ouvocêpodeeliminaracriaçãodeoutravariáveltemporária,seacharconveniente:
13.6JAVA.LANG.STRING 191
Stringpalavra="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 umaString.
Sevocêaindaquisertrocaronúmero1para2,faríamos:
Stringpalavra="fj11";palavra=palavra.toUpperCase();palavra=palavra.replace("1","2");System.out.println(palavra);
Ouaindapodemosconcatenaras invocaçõesdemétodo, jáqueumaString é devolvida a cada
invocação:
Stringpalavra="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ê podeencontrarmaisinformaçõessobreistonadocumentaçãodaclasseStringenoseumétodointern().
OUTROSMÉTODOSDACLASSESTRING
Existem diversos métodos da classe String que são extremamente importantes.
Recomendamos sempre consultar o javadoc relativo a essa classe para aprender cada vez maissobreamesma.
Porexemplo,ométodocharAt(i),retornaocaractereexistentenaposiçãoidaString,o
métodolengthretornaonúmerodecaracteresnamesmaeométodosubstringquerecebeumintedevolveaSubStringapartirdaposiçãopassadaporaqueleint.
OindexOf recebeumcharouumaStringedevolveoíndiceemqueaparecepelaprimeira
veznaStringprincipal(hátambémolastIndexOfquedevolveoíndicedaúltimaocorrência).
OtoUpperCaseeotoLowerCasedevolvemumanovaStringtodaemmaiúsculaetodaem
minúscula,respectivamente.
ApartirdoJava6,temosaindaométodoisEmpty,quedevolvetrueseaStringforvaziaou
falsecasocontrário.
Algunsmétodosúteisparabuscassãoocontainseomatches.
Hámuitosoutrosmétodos,recomendamosquevocêsempreconsulteojavadocdaclasse.
192 13.6JAVA.LANG.STRING
JAVA.LANGSTRINGBUFFERESTRINGBUILDER
ComoaclasseStringéimutável,trabalharcomumamesmaStringdiversasvezespodeter
um efeito colateral: gerar inúmeras Strings temporárias. Isto prejudica a performance da
aplicaçãoconsideravelmente.
NocasodevocêtrabalharmuitocomamanipulaçãodeumamesmaString (por exemplo,
dentrodeumlaço),oidealéutilizaraclasseStringBuffer.AclasseStringBufferrepresenta
umasequênciadecaracteres.DiferentementedaString,elaémutável,enãopossuiaquelepool.
AclasseStringBuildertemexatamenteosmesmosmétodos,comadiferençadelanãoser
thread-safe.VeremossobreesteconceitonocapítulodeThreads.String.
1. Queremosqueascontasapresentadasnacaixadeseleçãodatransferênciaapareçamcomonomedotitularemmaiúsculas.ParafazerissovamosalterarométodotoStringdaclasseConta.Utilize
ométodotoUpperCasedaStringparaisso.
2. Após alterarmosométodotoString, aconteceu algumamudança comonomedo titular que é
apresentadonalistadecontas?Porque?
3. Testeosexemplosdessecapítulo,paraverqueumaStringéimutável.Porexemplo:
publicclassTestaString{
publicstaticvoidmain(String[]args){Strings="fj11";s.replaceAll("1","2");System.out.println(s);}
}
Comofazerparaeleimprimirfj22?
4. Como fazerpara saber seumaString se encontra dentrodeoutra?Epara tirar os espaços em
brancodaspontasdeumaString?EparasaberseumaStringestávazia?Eparasaberquantos
caracterestemumaString?
TomecomohábitosemprepesquisaroJavaDoc!ConheceraAPI,aospoucos,é fundamentalparaquevocênãoprecisereescreveraroda!
5. (opcional)Escreva ummétodo que usa osmétodoscharAt elength de umaString para
13.7EXERCÍCIOS:JAVA.LANG.STRING
13.7EXERCÍCIOS:JAVA.LANG.STRING 193
imprimiramesmacaractereacaractere,comcadacaractereemumalinhadiferente.
6. (opcional) Reescreva o método do exercício anterior, mas modificando ele para que imprima aStringde trásparaa frenteeemuma linhasó.Teste-apara"Socorram-me, subinoônibusem
Marrocos"e"anotaramadatadamaratona".
7. (opcional)PesquiseaclasseStringBuilder(ouStringBuffernoJava1.4).Elaémutável.Porque
usá-laemvezdaString?Quandousá-la?
Comovocêpoderia reescreverométododeescrever aString de trás para a frente usandoum
StringBuilder?
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
1. ConvertaumaStringparaumnúmerosemusarasbibliotecasdojavaquejáfazemisso.Issoé,
umaStringx="762"devegeraruminti=762.
Paraajudar,saibaqueumcharpodeser"transformado"emintcomomesmovalornumérico
fazendo:
charc='3';inti=c-'0';//ivale3!
Aquiestamosnosaproveitandodoconhecimentodatabelaunicode:osnúmerosde0a9estãoemsequência! Você poderia usar o método estático Character.getNumericValue(char) em vez
disso.
EditoraCasadoCódigocomlivrosdeumaformadiferente
13.8DESAFIO
13.9DISCUSSÃOEMAULA:OQUEVOCÊPRECISAFAZEREMJAVA?
194 13.8DESAFIO
QualéasuanecessidadecomoJava?Precisafazeralgoritmosderedesneurais?Gerargráficos3D?Relatórios emPDF?Gerar códigodebarra?Gerarboletos?ValidarCPF?Mexer comumarquivodoExcel?
O instrutor vai mostrar que para a maioria absoluta das suas necessidades, alguém já fez umabibliotecaeadisponibilizou.
13.9DISCUSSÃOEMAULA:OQUEVOCÊPRECISAFAZEREMJAVA? 195
CAPÍTULO14
"Ohomemesqueceráantesamortedopaiqueaperdadapropriedade"--Maquiavel
Aotérminodessecapítulo,vocêserácapazde:
declarareinstanciararrays;popularepercorrerarrays.
Dentrodeumbloco,podemosdeclarardiversasvariáveiseusá-las:
doublesaldoDaConta1=conta1.getSaldo();doublesaldoDaConta2=conta2.getSaldo();doublesaldoDaConta3=conta3.getSaldo();doublesaldoDaConta4=conta4.getSaldo();
Isso pode se tornar um problema quando precisamos mudar a quantidade de variáveis a seremdeclaradasdeacordocomumparâmetro.Esseparâmetropodevariar,comoporexemplo,aquantidadedenúmerocontidosnumbilhetedeloteria.Umjogosimplespossui6números,maspodemoscomprarumbilhetemaiscaro,com7númerosoumais.
Parafacilitaressetipodecasopodemosdeclararumvetor(array)dedoubles:
double[]saldosDasContas;
Odouble[]éumtipo.Umaarrayésempreumobjeto,portanto,avariávelsaldosDasContasé
umareferência.Vamosprecisarcriarumobjetoparapoderusaraarray.Comocriamosoobjeto-array?
saldosDasContas=newdouble[10];
Oque fizemos foicriarumaarraydedoublede10posiçõeseatribuiroendereçonoqualela foicriada.Podemosaindaacessarasposiçõesdoarray:
saldosDasContas[5]=conta5.getSaldo();
Ocódigoacimaalteraasextaposiçãodoarray.NoJava,osíndicesdoarrayvãode0an-1,ondenéotamanhodadonomomentoemquevocêcriouoarray.Sevocêtentaracessarumaposiçãoforadessealcance,umerroocorreráduranteaexecução.
UMPOUCODEARRAYS
14.1OPROBLEMA
196 14UMPOUCODEARRAYS
ARRAYS-UMPROBLEMANOAPRENDIZADODEMUITASLINGUAGENS
Aprender a usar arrays pode ser um problema em qualquer linguagem. Isso porque envolveumasériedeconceitos,sintaxeeoutros.NoJava,muitasvezesutilizamosoutrosrecursosemvezdearrays,emespecialospacotesdecoleçõesdoJava,queveremosnocapítulo15.Portanto,fiquetranquilocasonãoconsigadigerirtodasintaxedasarraysnumprimeiromomento.
No caso do bilhete de loteria, podemos utilizar o mesmo recurso. Mais ainda, a quantidade denúmerosdonossobilhetepodeserdefinidoporumavariável.Considerequenindicaquantosnúmeros
nossobilheteterá,podemosentãofazer:
int[]numerosDoBilhete=newint[n];
Eassimpodemosacessaremodificarosinteiroscomíndicede0an-1.
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
É comum ouvirmos "array de objetos". Porém quando criamos uma array de alguma classe, elapossui referências. O objeto, como sempre, está na memória principal e, na sua array, só ficamguardadasasreferências(endereços).
ContaCorrente[]minhasContas;minhasContas=newContaCorrente[10];
JáconheceoscursosonlineAlura?
14.2ARRAYSDEREFERÊNCIAS
14.2ARRAYSDEREFERÊNCIAS 197
Quantascontasforamcriadasaqui?Naverdade,nenhuma.Foramcriados10espaçosquevocêpodeutilizarparaguardarumareferênciaaumaContaCorrente.Porenquanto,elessereferenciamparalugarnenhum(null).Sevocêtentar:
System.out.println(minhasContas[0].getSaldo());
Umerroduranteaexecuçãoocorrerá!Pois,naprimeiraposiçãodaarray,nãoháumareferênciaparaumaconta,nemparalugarnenhum.Vocêdevepopularsuaarrayantes.
ContaCorrentecontaNova=newContaCorrente();contaNova.deposita(1000.0);minhasContas[0]=contaNova;
Ouvocêpodefazerissodiretamente:
minhasContas[1]=newContaCorrente();minhasContas[1].deposita(3200.0);
Umaarraydetiposprimitivosguardavalores,umarraydeobjetosguardareferências.
Mase seagoraquisermosguardar tantoContaCorrente quantoContaPoupança?UmarraydeContaCorrente só consegueguardar objetos domesmo tipo.Sequisermosguardar os dois tiposdeconta,devemoscriarumarraydeConta!
Conta[]minhasContas=newConta[10];minhasContas[0]=newContaCorrente();minhasContas[1]=newContaPoupanca();
Perceba que não estamos criando umobjeto do tipoConta, que é abstrata, estamos criando 10
espaçosqueguardamreferênciasparaqualquertipodeconta.
14.3PERCORRENDOUMAARRAY
198 14.3PERCORRENDOUMAARRAY
Percorrerumarrayémuitosimplesquandofomosnósqueacriamos:
publicstaticvoidmain(String[]args){int[]idades=newint[10];for(inti=0;i<10;i++){idades[i]=i*10;}for(inti=0;i<10;i++){System.out.println(idades[i]);}}
Porém,emmuitoscasos,recebemosumaarraycomoargumentoemummétodo:
publicvoidimprimeArray(int[]array){//nãocompila!!for(inti=0;i<????;i++){System.out.println(array[i]);}}
Atéondeofordeveir?TodaarrayemJavatemumatributoquesechamalength,evocêpode
acessá-loparasaberotamanhodoarrayaoqualvocêestásereferenciandonaquelemomento:
publicvoidimprimeArray(int[]array){for(inti=0;i<array.length;i++){System.out.println(array[i]);}}
ARRAYSNÃOPODEMMUDARDETAMANHO
Apartirdomomentoqueumaarrayfoicriada,elanãopodemudardetamanho.
Sevocêprecisardemaisespaço,seránecessáriocriarumanovaarraye,antesdesereferirela,copieoselementosdaarrayvelha.
OJava5.0trazumanovasintaxeparapercorremosarrays(ecoleções,queveremosmaisafrente).
Nocasodevocênãoternecessidadedemanterumavariávelcomoíndicequeindicaaposiçãodoelementonovetor(queéumagrandepartedoscasos),podemosusaroenhanced-for.
publicclassAlgumaClasse{publicstaticvoidmain(String[]args){int[]idades=newint[10];for(inti=0;i<10;i++){idades[i]=i*10;}
//imprimindotodaaarray
14.4PERCORRENDOUMAARRAYNOJAVA5.0
14.4PERCORRENDOUMAARRAYNOJAVA5.0 199
for(intx:idades){System.out.println(x);}}}
Nãoprecisamosmaisdolengthparapercorrermatrizescujotamanhonãoconhecemos:
publicclassAlgumaClasse{publicvoidimprimeArray(int[]array){for(intx:array){System.out.println(x);}}}
Omesmoéválidoparaarraysdereferências.Essefornadamaiséqueumtruquedecompilação
parafacilitaressatarefadepercorrerarraysetorná-lamaislegível.
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoJavaeOrientaçãoaObjetos
Paraconsolidarmososconceitossobrearrays,vamosfazeralgunsexercíciosquenãointerferememnossoprojeto.
1. CrieumaclasseTestaArrays enométodomain crie umarrayde contas de tamanho10.Em
seguida,façaumlaçoparacriar10contascomsaldosdistintosecolocá-lasnoarray.Porexemplo,vocêpodeutilizaroíndicedolaçoemultiplicá-lopor100paragerarosaldodecadaconta:
Conta[]contas=newConta[10];
for(inti=0;i<contas.length;i++){Contaconta=newContaCorrente();conta.deposita(i*100.0);//escrevaocódigoparaguardaracontanaposiçãoidoarray}
2. AindanaclasseTestaArrays,façaumoutrolaçoparacalculareimprimiramédiadossaldosde
VocêpodetambémfazerocursodatadessaapostilanaCaelum
14.5EXERCÍCIOS:ARRAYS
200 14.5EXERCÍCIOS:ARRAYS
todasascontasdoarray.
3. (opcional) Crie uma classe TestaSplit que reescreva uma frase com as palavras na ordem
invertida."Socorram-me,subinoônibusemMarrocos"deveretornar"MarrocosemônibusnosubiSocorram-me,".Utilize ométodosplit daString para te auxiliar. Essemétodo divide uma
StringdeacordocomoseparadorespecificadoedevolveaspartesemumarraydeString,por
exemplo:
Stringfrase="Umamensagemqualquer";String[]palavras=frase.split("");
//Agorasóbastapercorreroarraynaordeminversaimprimindoaspalavras
4. (opcional)CrieumaclasseBancodentrodopacotebr.com.caelum.contas.modeloOBanco
deve ter umnome e umnúmero (obrigatoriamente) e uma referência a uma arraydeConta de
tamanho10,alémdeoutrosatributosquevocêjulgarnecessário.
publicclassBanco{privateStringnome;privateintnumero;privateConta[]contas;
//outrosatributosquevocêacharnecessário
publicBanco(Stringnome,intnumero){this.nome=nome;this.numero=numero;this.contas=newContaCorrente[10];}
//gettersparanomeenúmero,nãocolocarossetterspoisjárecebemosno//construtor}
5. (opcional)AclasseBancodeveterummétodoadiciona,querecebeumareferênciaaConta
comoargumentoeguardaessaconta.
VocêdeveinseriraContaemumaposiçãodaarrayqueestejalivre.Existemváriasmaneiraspara
vocêfazerisso:guardarumcontadorparaindicarqualapróximaposiçãovaziaouprocurarporumaposiçãovaziatodavez.Oqueseriamaisinteressante?
Sequiserverificarqualaprimeiraposiçãovazia(nula)eadicionarnela,poderiaserfeitoalgocomo:
publicvoidadiciona(Contac){for(inti=0;i<this.contas.length;i++){//verificarseaposiçãoestávazia//adicionarnoarray}}
Éimportanterepararqueométodoadicionanãorecebetitular,agencia,saldo,etc.Essaseriaumamaneiranemumpoucoestruturada,muitomenosorientadaaobjetosdesetrabalhar.Vocêantescria
14.5EXERCÍCIOS:ARRAYS 201
umaContaejápassaareferênciadela,quedentrodoobjetopossuititular,saldo,etc.
6. (opcional)CrieumaclasseTestaBancoquepossuiráummétodomain.Dentrodelecriealgumas
instânciasdeContaepasseparaobancopelométodoadiciona.
Bancobanco=newBanco("CaelumBank",999);//....
Criealgumascontasepassecomoargumentoparaoadicionadobanco:
ContaCorrentec1=newContaCorrente();c1.setTitular("Batman");c1.setNumero(1);c1.setAgencia(1000);c1.deposita(100000);banco.adiciona(c1);
ContaPoupancac2=newContaPoupanca();c2.setTitular("Coringa");c2.setNumero(2);c2.setAgencia(1000);c2.deposita(890000);banco.adiciona(c2);
Você pode criar essas contas dentro de um loop e dar a cada um deles valores diferentes dedepósitos:
for(inti=0;i<5;i++){ContaCorrenteconta=newContaCorrente();conta.setTitular("Titular"+i);conta.setNumero(i);conta.setAgencia(1000);conta.deposita(i*1000);banco.adiciona(conta);}
Repare que temos de instanciar ContaCorrente dentro do laço. Se a instanciação de
ContaCorrente ficasseacimado laço,estaríamosadicionadocincovezesamesma instância deContaCorrentenesteBancoeapenasmudandoseudepósitoacadaiteração,quenessecasonãoé
oefeitodesejado.
Opcional:ométodoadicionapodegerarumamensagemdeerroindicandoquandooarrayjáestá
cheio.
7. (opcional)PercorraoatributocontasdasuainstânciadeBancoeimprimaosdadosdetodasas
suascontas.Parafazerisso,vocêpodecriarummétodochamadomostraContasdentrodaclasse
Banco:
publicvoidmostraContas(){for(inti=0;i<this.contas.length;i++){System.out.println("Contanaposição"+i);//preencherparamostraroutrasinformacoesdaconta}}
202 14.5EXERCÍCIOS:ARRAYS
Cuidadoaopreencheressemétodo:alguns índicesdoseuarraypodemnãoconter referência paraumaContaconstruída,istoé,aindasereferiremparanull.Sepreferir,useofornovodojava
5.0.
Aí,atravésdoseumain,depoisdeadicionaralgumascontas,bastafazer:
banco.mostraContas();
8. (opcional) Em vez de mostrar apenas o salário de cada funcionário, você pode usar o métodotoString()decadaContadoseuarray.
9. (opcional)Crie ummétodo para verificar se umadeterminadaConta se encontra ou não como
contadestebanco:
publicbooleancontem(Contaconta){//...}
Vocêvaiprecisar fazerumfor emseuarrayeverificar se a contapassada comoargumento se
encontradentrodoarray.Eviteaomáximousarnúmeroshard-coded,istoé,useo.length.
10. (opcional)Caso o array já esteja cheio nomomento de adicionar uma outra conta, crie um arraynovocomumacapacidademaiorecopieosvaloresdoarrayatual.Istoé,vamosfazerarealocaçãodoselementosdoarrayjáquejavanãotemisso:umarraynasceemorrecomomesmolength.
USANDOOTHISPARAPASSARARGUMENTO
Dentrodeummétodo,vocêpodeusarapalavrathisparareferenciarasimesmoepode
passaressareferênciacomoargumento.
Arrays podem ter mais de uma dimensão. Isto é, em vez de termos uma array de 10 contas,podemosterumaarrayde10por10contasevocêpodeacessaracontanaposiçãodacolunaxelinhay.Naverdade,umaarraybidimensionalemJavaéumaarraydearrays.Pesquisesobreisso.
14.6UMPOUCOMAIS...
14.6UMPOUCOMAIS... 203
Uma array bidimensional não precisa ser retangular, isto é, cada linha pode ter um númerodiferentedecolunas.Como?Porque?
Oqueacontecesecriarmosumaarrayde0elementos?e-1?
OmétodomainrecebeumaarraydeStringscomoargumento.Essaarrayépassadapelousuárioquandoeleinvocaoprograma:
$javaTesteargumento1outromaisoutro
Enossaclasse:
publicclassTeste{publicstaticvoidmain(String[]args){for(Stringargumento:args){
204 14.6UMPOUCOMAIS...
System.out.println(argumento);}}}
Issoimprimirá:
argumento1outromaisoutro
1. Nosprimeiroscapítulos,vocêdeveterreparadoqueaversãorecursivaparaoproblemadeFibonacciélentaporquetodahoraestamosrecalculandovalores.Façacomqueaversãorecursivasejatãoboaquantoaversãoiterativa.(Dica:usearraysparaisso)
2. Oobjetivodesteexercícioéfixarosconceitosvistos.Sevocêestácomdificuldadeemalgumapartedessecapítulo,aproveiteetreinetudooquevimosatéagoranopequenoprogramaabaixo:
Programa:
Classe: Casa Atributos: cor, totalDePortas, portas[] Métodos: void pinta(String s), intquantasPortasEstaoAbertas(),voidadicionaPorta(Portap),inttotalDePortas()
Crieumacasa,pinte-a.Crietrêsportasecoloque-asnacasaatravésdométodoadicionaPorta,
abraefeche-ascomodesejar.UtilizeométodoquantasPortasEstaoAbertaspara imprimiro
númerodeportas abertas eométodototalDePortas para imprimir o total deportas em sua
casa.
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
14.7DESAFIOSOPCIONAIS
Seuslivrosdetecnologiaparecemdoséculopassado?
14.7DESAFIOSOPCIONAIS 205
CAPÍTULO15
"Aamizadeéumcontratosegundooqualnoscomprometemosaprestarpequenosfavoresparaqueno-losretribuamcomgrandes."--BarondelaBredeetdeMontesquieu
Aotérminodessecapítulo,vocêserácapazde:
utilizararrays,lists,setsoumapsdependendodanecessidadedoprograma;iterareordenarlistasecoleções;usarmapasparainserçãoebuscadeobjetos.
Comovimosnocapítulodearrays,manipulá-lasébastantetrabalhoso.Essadificuldadeapareceemdiversosmomentos:
nãopodemosredimensionarumarrayemJava;éimpossívelbuscardiretamenteporumdeterminadoelementocujoíndicenãosesabe;nãoconseguimossaberquantasposiçõesdoarrayjáforampopuladassemcriar,paraisso,métodosauxiliares.
Na figura acima, você pode ver um array que antes estava sendo completamente utilizado e que,depois,teveumdeseuselementosremovidos.
Supondoqueosdadosarmazenadosrepresentemcontas,oqueacontecequandoprecisarmosinseriruma nova conta no banco? Precisaremos procurar por um espaço vazio? Guardaremos em algumaestrutura dedados externa, as posiçõesvazias?E se nãohouver espaçovazio?Teríamosde criar umarraymaiorecopiarosdadosdoantigoparaele?
Hámais questões: comoposso saber quantas posições estão sendousadasno array?Vouprecisarsemprepercorreroarrayinteiroparaconseguiressainformação?
COLLECTIONSFRAMEWORK
15.1 ARRAYS SÃO TRABALHOSOS, UTILIZAR ESTRUTURA DEDADOS
206 15COLLECTIONSFRAMEWORK
Alémdessasdificuldadesqueosarraysapresentavam,faltavaumconjuntorobustodeclassesparasupriranecessidadedeestruturasdedadosbásicas,comolistasligadasetabelasdeespalhamento.
Com esses e outros objetivos em mente, o comitê responsável pelo Java criou um conjunto declasseseinterfacesconhecidocomoCollectionsFramework,queresidenopacotejava.utildesdeoJava21.2.
COLLECTIONS
AAPIdeCollectionsérobustaepossuidiversasclassesquerepresentamestruturasdedadosavançadas.
Porexemplo,nãoénecessárioreinventararodaecriarumalistaligada,massimutilizaraquelaqueoJavadisponibiliza.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Umprimeiro recurso que aAPI deCollections traz são listas.Uma lista é uma coleção quepermiteelementosduplicadosemantémumaordenaçãoespecíficaentreoselementos.
Em outras palavras, você tem a garantia de que, quando percorrer a lista, os elementos serãoencontrados em uma ordem pré-determinada, definida na hora da inserção dosmesmos. Ela resolvetodososproblemasquelevantamosemrelaçãoaoarray(busca,remoção, tamanho"infinito",...).Essecódigojáestápronto!
AAPIdeCollectionstrazainterfacejava.util.List,queespecificaoqueumaclassedeve
ser capaz de fazer para ser uma lista. Há diversas implementações disponíveis, cada uma com uma
Agoraéamelhorhoradeaprenderalgonovo
15.2LISTAS:JAVA.UTIL.LIST
15.2LISTAS:JAVA.UTIL.LIST 207
formadiferentederepresentarumalista.
A implementaçãomaisutilizadada interfaceListéaArrayList, que trabalha comumarray
interno para gerar uma lista. Portanto, ela é mais rápida na pesquisa do que sua concorrente, aLinkedList,queémaisrápidanainserçãoeremoçãodeitensnaspontas.
ARRAYLISTNÃOÉUMARRAY!
É comum confundirem uma ArrayList com um array, porém ela não é um array. O que
ocorreéque,internamente,elausaumarraycomoestruturaparaarmazenarosdados,porémesteatributoestápropriamenteencapsuladoevocênãotemcomoacessá-lo.Repare,também,quevocênãopodeusar[]comumaArrayList,nemacessaratributolength.Nãohárelação!
ParacriarumArrayList,bastachamaroconstrutor:
ArrayListlista=newArrayList();
ÉsemprepossívelabstrairalistaapartirdainterfaceList:
Listlista=newArrayList();
Paracriarumalistadenomes(String),podemosfazer:
Listlista=newArrayList();lista.add("Manoel");lista.add("Joaquim");lista.add("Maria");
AinterfaceListpossuidoismétodosadd,umquerecebeoobjetoaserinseridoeocolocano
finaldalista,eumsegundoquepermiteadicionaroelementoemqualquerposiçãodamesma.Noteque,em momento algum, dizemos qual é o tamanho da lista; podemos acrescentar quantos elementosquisermos,quealistacresceconformefornecessário.
Todalista(naverdade,todaCollection)trabalhadomodomaisgenéricopossível.Istoé,nãohá
uma ArrayList específica para Strings, outra para Números, outra para Datas etc. Todos os
métodostrabalhamcomObject.
Assim,épossívelcriar,porexemplo,umalistadeContasCorrentes:
ContaCorrentec1=newContaCorrente();c1.deposita(100);
ContaCorrentec2=newContaCorrente();c2.deposita(200);
ContaCorrentec3=newContaCorrente();c3.deposita(300);
208 15.2LISTAS:JAVA.UTIL.LIST
Listcontas=newArrayList();contas.add(c1);contas.add(c3);contas.add(c2);
Parasaberquantoselementoshánalista,usamosométodosize():
System.out.println(contas.size());
Háaindaummétodoget(int) que recebe como argumento o índice do elemento que se quer
recuperar.Atravésdele,podemosfazerumforparaiterarnalistadecontas:
for(inti=0;i<contas.size();i++){contas.get(i);//códigonãomuitoútil....}
Mascomofazerparaimprimirosaldodessascontas?PodemosacessarogetSaldo()diretamente
apósfazercontas.get(i)?Nãopodemos; lembre-seque toda lista trabalha semprecomObject.
Assim, a referência devolvida pelo get(i) é do tipo Object , sendo necessário o cast para
ContaCorrentesequisermosacessarogetSaldo():
for(inti=0;i<contas.size();i++){ContaCorrentecc=(ContaCorrente)contas.get(i);System.out.println(cc.getSaldo());}//notequeaordemdoselementosnãoéalterada
Háaindaoutrosmétodos,comoremove()querecebeumobjetoquesedesejaremoverdalista;e
contains(), que recebeumobjeto comoargumento e devolvetrue oufalse, indicando se o
elementoestáounãonalista.
AinterfaceListealgumasclassesqueaimplementampodemservistasnodiagramaaseguir:
15.2LISTAS:JAVA.UTIL.LIST 209
ACESSOALEATÓRIOEPERCORRENDOLISTASCOMGET
Algumaslistas,comoaArrayList,têmacessoaleatórioaosseuselementos:abuscaporum
elemento em uma determinada posição é feita demaneira imediata, sem que a lista inteira sejapercorrida(quechamamosdeacessosequencial).
Nestecaso,oacessoatravésdométodoget(int)émuitorápido.Casocontrário,percorrer
umalistausandoumforcomoessequeacabamosdever,podeserdesastroso.Aopercorrermos
umalista,devemosusarsempreumIteratorouenhancedfor,comoveremos.
Umalistaéumaexcelentealternativaaumarraycomum,jáquetemostodososbenefíciosdearrays,semanecessidadedetomarcuidadocomremoções,faltadeespaçoetc.
A outra implementação muito usada, a LinkedList, fornece métodos adicionais para obter e
removeroprimeiroeúltimoelementoda lista.Ela também temo funcionamento internodiferente,oquepodeimpactarperformance,comoveremosduranteosexercíciosnofinaldocapítulo.
210 15.2LISTAS:JAVA.UTIL.LIST
VECTOR
Outra implementação é a tradicional classe Vector, presente desde o Java 1.0, que foi
adaptadaparausocomoframeworkdeCollections,comainclusãodenovosmétodos.
Ela deve ser escolhida com cuidado, pois lida de uma maneira diferente com processoscorrendo em paralelo e terá um custo adicional em relação a ArrayList quando não houver
acessosimultâneoaosdados.
Emqualquerlista,épossívelcolocarqualquerObject.Comisso,épossívelmisturarobjetos:
ContaCorrentecc=newContaCorrente();
Listlista=newArrayList();lista.add("Umastring");lista.add(cc);...
Mas e depois, na hora de recuperar esses objetos?Comoométodoget devolveumObject,
precisamosfazerocast.Mascomumalistacomváriosobjetosdetiposdiferentes,issopodenãosertãosimples...
Geralmente, não nos interessa uma lista com vários tipos de objetos misturados; no dia-a-dia,usamoslistascomoaqueladecontascorrentes.NoJava5.0,podemosusarorecursodeGenericspararestringiraslistasaumdeterminadotipodeobjetos(enãoqualquerObject):
List<ContaCorrente>contas=newArrayList<ContaCorrente>();contas.add(c1);contas.add(c3);contas.add(c2);
ReparenousodeumparâmetroaoladodeListeArrayList:eleindicaquenossalistafoicriada
paratrabalharexclusivamentecomobjetosdotipoContaCorrente. Issonos trazumasegurançaem
tempodecompilação:
contas.add("umastring");//issonãocompilamais!!
OusodeGenericstambémeliminaanecessidadedecasting,jáque,seguramente,todososobjetosinseridosnalistaserãodotipoContaCorrente:
for(inti=0;i<contas.size();i++){ContaCorrentecc=contas.get(i);//semcasting!System.out.println(cc.getSaldo());}
15.3LISTASNOJAVA5EJAVA7COMGENERICS
15.3LISTASNOJAVA5EJAVA7COMGENERICS 211
Apartir do Java 7, se você instancia um tipo genérico namesma linha de sua declaração, não énecessáriopassaros tiposnovamente,bastausarnewArrayList<>().É conhecido comooperador
diamante:
List<ContaCorrente>contas=newArrayList<>();
ValeressaltaraimportânciadousodainterfaceList:quandodesenvolvemos,procuramossempre
nosreferiraela,enãoàsimplementaçõesespecíficas.Porexemplo,setemosummétodoquevaibuscarumasériedecontasnobancodedados,poderíamosfazerassim:
classAgencia{publicArrayList<Conta>buscaTodasContas(){ArrayList<Conta>contas=newArrayList<>();
//paracadacontadobancodedados,contas.add
returncontas;}}
Porém,paraqueprecisamosretornarareferênciaespecíficaaumaArrayList?Paraque ser tão
específico?Dessamaneira,odiaqueoptarmospordevolverumaLinkedListemvezdeArrayList,
as pessoas que estão usando o método buscaTodasContas poderão ter problemas, pois estavam
fazendo referência a uma ArrayList. O ideal é sempre trabalhar com a interface mais genérica
possível:
classAgencia{
//modificaçãoapenasnoretorno:publicList<Conta>buscaTodasContas(){ArrayList<Conta>contas=newArrayList<>();
//paracadacontadobancodedados,contas.add
returncontas;}}
ÉomesmocasodepreferirreferenciaraosobjetoscomInputStreamcomofizemosnocapí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çãoemespecíficocomoArrayList,deixandoométodomaisflexível:
classAgencia{
publicvoidatualizaContas(List<Conta>contas){//...
15.4AIMPORTÂNCIADASINTERFACESNASCOLEÇÕES
212 15.4AIMPORTÂNCIADASINTERFACESNASCOLEÇÕES
}}
Também declaramos atributos como List em vez de nos comprometer como uma ou outra
implementação.Dessaformaobtemosumbaixoacoplamento:podemostrocaraimplementação,jáqueestamosprogramandoparaainterface!Porexemplo:
classEmpresa{
privateList<Funcionario>empregados=newArrayList<>();
//...}
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Vimos anteriormente que as listas são percorridas de maneira pré-determinada de acordo com ainclusãodositens.Mas,muitasvezes,queremospercorreranossalistademaneiraordenada.
AclasseCollectionstrazummétodoestáticosortquerecebeumListcomoargumentoeo
ordenaporordemcrescente.Porexemplo:
List<String>lista=newArrayList<>();lista.add("Sérgio");lista.add("Paulo");lista.add("Guilherme");
//reparequeotoStringdeArrayListfoisobrescrito:System.out.println(lista);
Collections.sort(lista);
System.out.println(lista);
Aotestaroexemploacima,vocêobservaráque,primeiro,alistaéimpressanaordemdeinserçãoe,depoisdeinvocarosort,elaéimpressaemordemalfabética.
EditoraCasadoCódigocomlivrosdeumaformadiferente
15.5ORDENAÇÃO:COLLECTIONS.SORT
15.5ORDENAÇÃO:COLLECTIONS.SORT 213
Mastoda listaemJavapodeserdequalquer tipodeobjeto,porexemplo,ContaCorrente.E se
quisermosordenaruma listadeContaCorrente?Emqueordema classeCollections ordenará?
Pelosaldo?Pelonomedocorrentista?
ContaCorrentec1=newContaCorrente();c1.deposita(500);
ContaCorrentec2=newContaCorrente();c2.deposita(200);
ContaCorrentec3=newContaCorrente();c3.deposita(150);
List<ContaCorrente>contas=newArrayList<>();contas.add(c1);contas.add(c3);contas.add(c2);
Collections.sort(contas);//qualseriaocritérioparaestaordenação?
Semprequefalamosemordenação,precisamospensaremumcritériodeordenação,umaformadedeterminar qual elemento vem antes de qual. É necessário instruir o sort sobre como compararnossasContaCorrenteafimdedeterminarumaordemnalista.Paraisto,ométodosortnecessita
que todosseusobjetosda listasejamcomparáveis epossuamummétodoque secomparacomoutraContaCorrente.Comoéqueométodosortteráagarantiadequeasuaclassepossuiessemétodo?
Issoseráfeito,novamente,atravésdeumcontrato,deumainterface!
Vamos fazer com que os elementos da nossa coleção implementem a interfacejava.lang.Comparable,quedefineométodointcompareTo(Object).Estemétododeveretornar
zero,seoobjetocomparadoforigualaesteobjeto,umnúmeronegativo,seesteobjetoformenorqueoobjetodado,eumnúmeropositivo,seesteobjetoformaiorqueoobjetodado.
ParaordenarasContaCorrentesporsaldo,bastaimplementaroComparable:
publicclassContaCorrenteextendsContaimplementsComparable<ContaCorrente>{
//...todoocódigoanteriorficaaqui
publicintcompareTo(ContaCorrenteoutra){if(this.saldo<outra.saldo){return-1;}
if(this.saldo>outra.saldo){return1;}
return0;}}
Com o código anterior, nossa classe tornou-se "comparável": dados dois objetos da classe,
214 15.5ORDENAÇÃO:COLLECTIONS.SORT
conseguimos dizer se um objeto é maior, menor ou igual ao outro, segundo algum critério por nósdefinido.Nonossocaso,acomparaçãoseráfeitabaseando-senosaldodaconta.
Reparequeocritériodeordenaçãoé totalmenteaberto,definidopeloprogramador.Sequisermosordenarporoutroatributo(ouatéporumacombinaçãodeatributos),bastamodificaraimplementaçãodométodocompareTonaclasse.
QuandochamarmosométodosortdeCollections,elesaberácomofazeraordenaçãodalista;
eleusaráocritérioquedefinimosnométodocompareTo.
OUTRAIMPLEMENTAÇÃO...
Oqueachadaimplementaçãoabaixo?
publicintcompareTo(Contaoutra){returnInteger.compare(this.getNumero(),outra.getNumero());}
Mas,eoexemploanterior,comumalistadeStrings?Porqueaordenaçãofuncionou,naquelecaso,semprecisarmosfazernada?Simples:quemescreveuaclasseString (lembrequeelaéumaclasse
comoqualqueroutra)implementouainterfaceComparableeométodocompareToparaStrings,
fazendo comparação em ordem alfabética. (Consulte a documentação da classe String e veja o
métodocompareTolá).OmesmoacontececomoutrasclassescomoInteger,BigDecimal,Date,
entreoutras.
15.5ORDENAÇÃO:COLLECTIONS.SORT 215
OUTROSMÉTODOSDACLASSECOLLECTIONS
AclasseCollectionstrazumagrandequantidadedemétodosestáticosúteisnamanipulação
decoleções.
binarySearch(List,Object): Realiza uma busca binária por determinado elemento na
listaordenadaeretornasuaposiçãoouumnúmeronegativo,casonãoencontrado.
max(Collection):Retornaomaiorelementodacoleção.
min(Collection):Retornaomenorelementodacoleção.
reverse(List):Invertealista.
...emuitosoutros.Consulteadocumentaçãoparaveroutrosmétodos.
No Java 8 muitas dessas funcionalidades da Collections podem ser feitas através dos
chamadosStreams,queficaumpoucoforadoescopodeumcursoinicialdeJava.
Existeumaclasseanáloga,ajava.util.Arrays,quefazoperaçõessimilarescomarrays.
Éimportanteconhecê-lasparaevitarescrevercódigojáexistente.
Vamosordenarocampodedestino da teladedetalhesdacontaparaqueascontasapareçamemordemalfabéticadetitular.
1. FaçasuaclasseContaimplementarainterfaceComparable<Conta>.Utilizeocritériodeordenar
pelotitulardaconta.
publicclassContaimplementsComparable<Conta>{...}
DeixeoseumétodocompareToparecidocomeste:
publicclassContaimplementsComparable<Conta>{
//...todoocódigoanteriorficaaqui
publicintcompareTo(ContaoutraConta){returnthis.titular.compareTo(outraConta.titular);}}
15.6EXERCÍCIOS:ORDENAÇÃO
216 15.6EXERCÍCIOS:ORDENAÇÃO
2. Queremosqueascontasapareçamnocampodedestinoordenadaspelotitular.Vamosentãocriarométodo ordenaLista na classe ManipuladorDeContas. Use o Collections.sort() para
ordenaralistarecuperadadoEvento:
publicclassManipuladorDeContas{
//outrosmétodos
publicvoidordenaLista(Eventoevento){List<Conta>contas=evento.getLista("destino");Collections.sort(contas);}}
Rodeaaplicação,adicionealgumascontaseverifiqueseascontasaparecemordenadaspelonomedotitular,nocampodestino,napartedatransferência.Paraveraordenaçãoénecessárioacessarosdetalhesdeumaconta.
Atençãoespecial:reparequeescrevemosummétodocompareToemnossaclasseenossocódigonunca o invoca!! Isto émuito comum.Reescrevemos (ou implementamos) ummétodo e quemoinvocará será umoutro conjuntode classes (nesse caso, quemestá chamandoocompareTo é o
Collections.sort,queousa comobasepara o algoritmodeordenação). Isso cria um sistema
extremamentecoesoe, aomesmo tempo, combaixoacoplamento: a classeCollections nunca
imaginouqueordenariaobjetosdotipoConta,mas jáqueelessãoComparable,oseumétodo
sortestásatisfeito.
3. OqueteriaacontecidoseaclasseContanãoimplementasseComparable<Conta>mastivesseo
métodocompareTo?
Façaumteste:removatemporariamenteasentençaimplementsComparable<Conta>,nãoremova
ométodocompareToevejaoqueacontece.Bastaterométodo,semassinarainterface?
4. Comoposso inverter a ordemde uma lista?Comoposso embaralhar todos os elementos de umalista?Comopossorotacionaroselementosdeumalista?
InvestigueadocumentaçãodaclasseCollectionsdentrodopacotejava.util.
5. (opcional)CrieumanovaclasseTestaListaquecriaumaArrayListeinserenovascontascom
saldosaleatóriosusandoumlaço(for).Adivinheonomedaclasseparacolocarsaldosaleatórios?
Random. Do pacote java.util . Consulte sua documentação para usá-la (utilize o método
nextInt()passandoonúmeromáximoasersorteado).
6. ModifiqueaclasseTestaListaparautilizarumaLinkedListemvezdeArrayList:
List<Conta>contas=newLinkedList<Conta>();
15.6EXERCÍCIOS:ORDENAÇÃO 217
Precisamos alterar mais algum código para que essa substituição funcione? Rode o programa.Algumadiferença?
7. (opcional)Imprimaareferênciaparaessalista.OtoStringdeumaArrayList/LinkedListé
reescrito?
System.out.println(contas);
Umconjunto(Set)funcionadeformaanálogaaosconjuntosdamatemática,eleéumacoleçãoque
nãopermiteelementosduplicados.
Outracaracterísticafundamentaldeleéofatodequeaordememqueoselementossãoarmazenadospodenãoseraordemnaqualelesforaminseridosnoconjunto.Ainterfacenãodefinecomodeveserestecomportamento.Talordemvariadeimplementaçãoparaimplementação.
15.7CONJUNTO:JAVA.UTIL.SET
218 15.7CONJUNTO:JAVA.UTIL.SET
Um conjunto é representado pela interface Set e tem como suas principais implementações as
classesHashSet,LinkedHashSeteTreeSet.
Ocódigoaseguircriaumconjuntoeadicionadiversoselementos,ealgunsrepetidos:
Set<String>cargos=newHashSet<>();
cargos.add("Gerente");cargos.add("Diretor");cargos.add("Presidente");cargos.add("Secretária");cargos.add("Funcionário");cargos.add("Diretor");//repetido!
//imprimenatelatodososelementosSystem.out.println(cargos);
Aqui,osegundoDiretornãoseráadicionadoeométodoaddlheretornaráfalse.
O uso de um Set pode parecer desvantajoso, já que ele não armazena a ordem, e não aceita
elementos repetidos. Não hámétodos que trabalham com índices, como o get(int) que as listas
possuem.AgrandevantagemdoSetéqueexistemimplementações,comoaHashSet, quepossui
umaperformanceincomparávelcomasListsquandousadoparapesquisa (métodocontains por
exemplo).Veremosessaenormediferençaduranteosexercícios.
ORDEMDEUMSET
Seriapossívelusarumaoutraimplementaçãodeconjuntos,comoumTreeSet,queinsereos
elementosdetalformaque,quandoforempercorridos,elesapareçamemumaordemdefinidapelométodo de comparação entre seus elementos. Esse método é definido pela interfacejava.lang.Comparable.Ou,ainda,podesepassarumComparatorparaseuconstrutor.
JáoLinkedHashSetmantémaordemdeinserçãodoselementos.
AntesdoJava5,nãopodíamosutilizargenerics,eusávamosoSetde formaqueele trabalhava
comObject,havendonecessidadedecastings.
15.7CONJUNTO:JAVA.UTIL.SET 219
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
AscoleçõestêmcomobaseainterfaceCollection,quedefinemétodosparaadicionareremover
umelemento,everificarseeleestánacoleção,entreoutrasoperações,comomostraatabelaaseguir:
Umacoleçãopode implementardiretamentea interfaceCollection,porémnormalmente seusa
umadasduassubinterfacesmaisfamosas:justamenteSeteList.
A interface Set, como previamente vista, define um conjunto de elementos únicos enquanto a
interfaceListpermiteelementosduplicados,alémdemanteraordemaqualelesforamadicionados.
A busca em umSet pode sermais rápida do que em um objeto do tipoList, pois diversas
implementaçõesutilizam-sede tabelas de espalhamento (hash tables), realizando a busca para tempolinear(O(1)).
A interfaceMap faz parte do framework,mas não estendeCollection. (veremosMap mais
JáconheceoscursosonlineAlura?
15.8PRINCIPAISINTERFACES:JAVA.UTIL.COLLECTION
220 15.8PRINCIPAISINTERFACES:JAVA.UTIL.COLLECTION
adiante).
NoJava5,temosoutrainterfacefilhadeCollection:aQueue,quedefinemétodosdeentradae
desaídaecujocritérioserádefinidopelasua implementação(porexemploLIFO,FIFOouaindaumheapondecadaelementopossuisuachavedeprioridade).
Comopercorreroselementosdeumacoleção?Seforumalista,podemossempreutilizarumlaçofor,invocandoométodogetparacadaelemento.Maseseacoleçãonãopermitirindexação?
Por exemplo, um Set não possui um método para pegar o primeiro, o segundo ou o quinto
elementodoconjunto,jáqueumconjuntonãopossuioconceitode"ordem"
Podemosusaroenhanced-for (o"foreach")doJava5parapercorrerqualquerCollection semnos preocupar com isso. Internamente o compilador vai fazer com que seja usado o Iterator da
Collectiondadaparapercorreracoleção.Repare:
Set<String>conjunto=newHashSet<>();
conjunto.add("java");conjunto.add("vraptor");conjunto.add("scala");
for(Stringpalavra:conjunto){System.out.println(palavra);}
15.9PERCORRENDOCOLEÇÕESNOJAVA5
15.9PERCORRENDOCOLEÇÕESNOJAVA5 221
Emqueordemoselementosserãoacessados?
Numa lista, os elementos aparecerão de acordo com o índice em que foram inseridos, isto é, deacordo com o que foi pré-determinado. Em um conjunto, a ordem depende da implementação dainterfaceSet:vocêmuitasvezesnãovaisaberaocertoemqueordemosobjetosserãopercorridos.
PorqueoSeté,então,tãoimportanteeusado?
Paraperceberseumitemjáexisteemumalista,émuitomaisrápidousaralgumasimplementaçõesdeSetdoqueumList, eosTreeSets já vêmordenadosde acordo comas características que
desejarmos!SempreconsidereusarumSetsenãohouveranecessidadedeguardaroselementosem
determinadaordemebuscá-losatravésdeumíndice.
Noeclipse,vocêpodeescreverforeach e darctrl+espaço, que ele vai gerar o esqueletodesseenhancedfor!Muitoútil!
Antes do Java 5 introduzir o novo enhanced-for, iterações em coleções eram feitas com oIterator . Toda coleção fornece acesso a um iterator, um objeto que implementa a interface
Iterator,queconheceinternamenteacoleçãoedáacessoatodososseuselementos,comoafigura
abaixomostra.
Aindahoje(depoisdoJava5)podemosusaroIterator,masomaiscomuméusaroenhanced-
for.E,naverdade,oenhanced-foréapenasumaçúcarsintáticoqueusaiteratorportrásdospanos.
Primeiro criamos um Iterator que entra na coleção. A cada chamada do método next, o
Iterator retorna o próximo objeto do conjunto. Um iterator pode ser obtido com o método
iterator()deCollection,porexemplonumalistadeString:
15.10 PARA SABER MAIS: ITERANDO SOBRE COLEÇÕES COMJAVA.UTIL.ITERATOR
222 15.10PARASABERMAIS:ITERANDOSOBRECOLEÇÕESCOMJAVA.UTIL.ITERATOR
Iterator<String>i=lista.iterator();
AinterfaceIteratorpossuidoismétodosprincipais:hasNext()(comretornobooleano),indica
seaindaexisteumelementoaserpercorrido;next(),retornaopróximoobjeto.
Voltandoaoexemplodoconjuntodestrings,vamospercorreroconjunto:
Set<String>conjunto=newHashSet<>();conjunto.add("item1");conjunto.add("item2");conjunto.add("item3");
//retornaoiteratorIterator<String>i=conjunto.iterator();while(i.hasNext()){//recebeapalavraStringpalavra=i.next();System.out.println(palavra);}
Owhile anterior só termina quando todos os elementos do conjunto forem percorridos, isto é,
quandoométodohasNextmencionarquenãoexistemmaisitens.
LISTITERATOR
Umalistafornece,alémdeacessoaumIterator,umListIterator,queoferecerecursos
adicionais,específicosparalistas.
UsandooListIterator,vocêpode,porexemplo,adicionarumelementonalistaouvoltar
paraoelementoquefoi"iterado"anteriormente.
USARITERATOREMVEZDOENHANCED-FOR?
OIteratorpodesimaindaserútil.Alémde iterarnacoleçãocomofazoenhanced-for,o
Iterator consegue remover elementos da coleção durante a iteração de uma forma elegante,
atravésdométodoremove.
15.10PARASABERMAIS:ITERANDOSOBRECOLEÇÕESCOMJAVA.UTIL.ITERATOR 223
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoJavaeOrientaçãoaObjetos
Muitas vezes queremos buscar rapidamente um objeto dado alguma informação sobre ele. Umexemploseria,dadaaplacadocarro,obtertodososdadosdocarro.Poderíamosutilizarumalistaparaissoepercorrer todososseuselementos,mas issopodeserpéssimoparaaperformance,mesmoparalistasnãomuitograndes.Aquientraomapa.
Ummapaécompostoporumconjuntodeassociaçõesentreumobjetochaveaumobjetovalor.Éequivalenteaoconceitodedicionário,usadoemváriaslinguagens.Algumaslinguagens,comoPerlouPHP,possuemumsuportemaisdiretoamapas,ondesãoconhecidoscomomatrizes/arraysassociativas.
java.util.Map é um mapa, pois é possível usá-lo para mapear uma chave a um valor, por
exemplo: mapeie à chave "empresa" o valor "Caelum", ou então mapeie à chave "rua" ao valor"Vergueiro".Semelhanteaassociaçõesdepalavrasquepodemosfazeremumdicionário.
VocêpodetambémfazerocursodatadessaapostilanaCaelum
15.11MAPAS-JAVA.UTIL.MAP
224 15.11MAPAS-JAVA.UTIL.MAP
Ométodo put(Object, Object) da interface Map recebe a chave e o valor de uma nova
associação. Para saber o que está associado a um determinado objeto-chave, passa-se esse objeto nométodoget(Object).Semdúvidaessassãoasduasoperaçõesprincipaisemaisfrequentesrealizadas
sobreummapa.
Observeoexemplo:criamosduascontascorrenteseascolocamosemummapaassociando-asaosseusdonos.
ContaCorrentec1=newContaCorrente();c1.deposita(10000);
ContaCorrentec2=newContaCorrente();c2.deposita(3000);
//criaomapaMap<String,ContaCorrente>mapaDeContas=newHashMap<>();
//adicionaduaschaveseseusrespectivosvaloresmapaDeContas.put("diretor",c1);mapaDeContas.put("gerente",c2);
//qualacontadodiretor?(semcasting!)ContaCorrentecontaDoDiretor=mapaDeContas.get("diretor");System.out.println(contaDoDiretor.getSaldo());
Ummapaémuitousadopara"indexar"objetosdeacordocomdeterminadocritério,parapodermosbuscar esse objetos rapidamente. Ummapa costuma aparecer juntamente com outras coleções, parapoderrealizaressasbuscas!
Ele,assimcomoascoleções,trabalhadiretamentecomObjects(tantonachavequantonovalor),
o que tornaria necessário o casting nomomento que recuperar elementos.Usandoos generics, comofizemosaqui,nãoprecisamosmaisdocasting.
SuasprincipaisimplementaçõessãooHashMap,oTreeMapeoHashtable.
Apesardomapa fazerpartedo framework, elenãoestende a interfaceCollection, por ter um
comportamentobemdiferente.Porém,ascoleçõesinternasdeummapa(adechaveseadevalores,verFigura7)sãoacessíveispormétodosdefinidosnainterfaceMap.
15.11MAPAS-JAVA.UTIL.MAP 225
OmétodokeySet()retornaumSetcomaschavesdaquelemapaeométodovalues()retorna
aCollectioncomtodososvaloresqueforamassociadosaalgumadaschaves.
UmmapaimportanteéatradicionalclasseProperties,quemapeiastringseémuitoutilizadapara
aconfiguraçãodeaplicações.
APropertiespossui,também,métodosparaleregravaromapeamentocombaseemumarquivo
texto,facilitandomuitoasuapersistência.
Propertiesconfig=newProperties();
config.setProperty("database.login","scott");config.setProperty("database.password","tiger");config.setProperty("database.url","jdbc:mysql:/localhost/teste");
//muitaslinhasdepois...
Stringlogin=config.getProperty("database.login");Stringpassword=config.getProperty("database.password");Stringurl=config.getProperty("database.url");DriverManager.getConnection(url,login,password);
ReparequenãohouveanecessidadedocastingparaStringnomomentoderecuperarosobjetos
associados. Isto porque a classe Properties foi desenhada com o propósito de trabalhar com a
15.12PARASABERMAIS:PROPERTIES
226 15.12PARASABERMAIS:PROPERTIES
associaçãoentreStrings.
Muitas das coleções do java guardam os objetos dentro de tabelas de hash. Essas tabelas sãoutilizadasparaqueapesquisadeumobjetosejafeitademaneirarápida.
Como funciona? Cada objeto é "classificado" pelo seu hashCode e, com isso, conseguimos
espalharcadaobjetoagrupando-ospelohashCode.Quandobuscamosdeterminadoobjeto, sóvamos
procurar entre os elementos que estão no grupo daquele hashCode. Dentro desse grupo, vamos
testandooobjetoprocuradocomocandidatousandoequals().
Paraque issofuncionedireito,ométodohashCode de cadaobjetodeve retornaromesmovalor
paradoisobjetos,seelessãoconsideradosequals.Emoutraspalavras:
a.equals(b)implicaa.hashCode()==b.hashCode()
Implementar hashCode de tal maneira que ele retorne valores diferentes para dois objetos
consideradosequalsquebraocontratodeObjecteresultaráemcollectionsqueusamespalhamento
(comoHashSet,HashMapeHashtable),nãoachandoobjetosiguaisdentrodeumamesmacoleção.
EQUALSEHASHCODENOECLIPSE
O Eclipse é capaz de gerar uma implementação correta de equals e hashcode baseado nosatributosquevocêqueiracomparar.BastairnomenuSourceedepoisemGeneratehashcode()andequals().
15.13PARASABERMAIS:EQUALSEHASHCODE
15.13PARASABERMAIS:EQUALSEHASHCODE 227
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
AscoleçõesdoJavaoferecemgrandeflexibilidadeaousuário.Aperdadeperformanceemrelaçãoàutilizaçãodearrayséirrelevante,masdeve-setomaralgumasprecauções:
Grandepartedas coleçõesusam, internamente, umarraypara armazenaros seusdados.Quandoessearraynãoémaissuficiente,écriadaummaioreoconteúdodaantigaécopiado.Esteprocessopodeacontecermuitasvezes,nocasodevocêterumacoleçãoquecrescemuito.Vocêdeve,então,criarumacoleçãojácomumacapacidadegrande,paraevitaroexcessoderedimensionamento.
Evite usar coleções que guardam os elementos pela sua ordem de comparação quando não hánecessidade.UmTreeSetgastacomputacionalmenteO(log(n)) para inserir (ele utiliza uma
árvorerubro-negracomoimplementação),enquantooHashSetgastaapenasO(1).
NãoiteresobreumaListutilizandoumforde0atélist.size()eusandoget(int)para
receberosobjetos.Enquantoissopareceatraente,algumasimplementaçõesdaListnãosãode
acesso aleatório como a LinkedList , fazendo esse código ter uma péssima performance
computacional.(useIterator)
1. Crieumcódigoqueinsira30milnúmerosnumaArrayListepesquise-os.Vamosusarummétodo
deSystemparacronometrarotempogasto:
publicclassTestaPerformance{
publicstaticvoidmain(String[]args){System.out.println("Iniciando...");Collection<Integer>teste=newArrayList<>();
Seuslivrosdetecnologiaparecemdoséculopassado?
15.14PARASABERMAIS:BOASPRÁTICAS
15.15EXERCÍCIOS:COLLECTIONS
228 15.14PARASABERMAIS:BOASPRÁTICAS
longinicio=System.currentTimeMillis();
inttotal=30000;
for(inti=0;i<total;i++){teste.add(i);}
for(inti=0;i<total;i++){teste.contains(i);}
longfim=System.currentTimeMillis();longtempo=fim-inicio;System.out.println("Tempogasto:"+tempo);}}
TroqueaArrayListporumHashSeteverifiqueotempoquevaidemorar:
Collection<Integer>teste=newHashSet<>();
Oqueélento?Ainserçãode30milelementosouas30milbuscas?Descubracomputandootempogastoemcadaforseparadamente.
Adiferençaémaisquegritante.Sevocêpassarde30milparaumnúmeromaior,como50ou100mil,veráqueissoinviabilizaporcompletoousodeumaList,nocasoemquequeremosutilizá-la
essencialmenteempesquisas.
2. (conceitual,importante)Repareque,sevocêdeclararacoleçãoedernewassim:
Collection<Integer>teste=newArrayList<>();
emvezde:
ArrayList<Integer>teste=newArrayList<>();
É garantido que vai ter de alterar só essa linha para substituir a implementação porHashSet.
Estamosaquiusandoopolimorfismoparanosprotegerquemudançasde implementaçãovenhamnos obrigar a alterar muito código. Mais uma vez: programe voltado a interface, e não àimplementação!
Esse é um excelente exemplo de bom uso de interfaces, afinal, de que importa como a coleçãofunciona? O que queremos é uma coleção qualquer, isso é suficiente para os nossos propósitos!Nosso código está com baixoacoplamento em relação a estrutura de dados utilizada: podemostrocá-lafacilmente.
Esseéumcódigoextremamenteeleganteeflexível.Comotempovocêvairepararqueaspessoastentamprogramarsempresereferindoaessasinterfacesmenosespecíficas,namedidadopossível:métodos costumam receber e devolver Collections,Lists e Sets em vez de referenciar
diretamente uma implementação. É o mesmo que ocorre com o uso de InputStream e
15.15EXERCÍCIOS:COLLECTIONS 229
OutputStream:elessãoosuficiente,nãoháporqueforçarousodealgomaisespecífico.
Obviamente,algumasvezesnãoconseguimostrabalhardessaformaeprecisamosusarumainterfacemaisespecíficaoumesmonosreferiraoobjetopelasuaimplementaçãoparapoderchamaralgunsmétodos. Por exemplo, TreeSet tem mais métodos que os definidos em Set, assim como
LinkedListemrelaçãoàList.
DêumexemplodeumcasoemquenãopoderíamosnosreferiraumacoleçãodeelementoscomoCollection,masnecessariamenteporinterfacesmaisespecíficascomoListouSet.
3. FaçatestescomoMap,comovistonessecapítulo:
publicclassTestaMapa{
publicstaticvoidmain(String[]args){Contac1=newContaCorrente();c1.deposita(10000);
Contac2=newContaCorrente();c2.deposita(3000);
//criaomapaMapmapaDeContas=newHashMap();
//adicionaduaschaveseseusvaloresmapaDeContas.put("diretor",c1);mapaDeContas.put("gerente",c2);
//qualacontadodiretor?ContacontaDoDiretor=(Conta)mapaDeContas.get("diretor");System.out.println(contaDoDiretor.getSaldo());}}
Depois,altereocódigoparausarogenericsenãohaveranecessidadedocasting,alémdagarantiadequenossomapaestaráseguroemrelaçãoatipagemusada.
VocêpodeutilizaroquickfixdoEclipseparaqueeleconserteissoparavocê:nalinhaemquevocêestáchamandooput,useoctrl+1.Depoisdemaisumquickfix(descubra!)seucódigodeve
ficarcomosegue:
//criaomapaMap<String,Conta>mapaDeContas=newHashMap<>();
Queopçãodoctrl+1vocêescolheuparaqueeleadicionasseogenericsparavocê?
4. (opcional)Assimcomonoexercício1, crieumacomparaçãoentreArrayList eLinkedList,
para ver qual é a mais rápida para se adicionar elementos na primeira posição (list.add(0,
elemento)),comoporexemplo:
publicclassTestaPerformanceDeAdicionarNaPrimeiraPosicao{publicstaticvoidmain(String[]args){System.out.println("Iniciando...");
230 15.15EXERCÍCIOS:COLLECTIONS
longinicio=System.currentTimeMillis();
//trocardepoisporArrayListList<Integer>teste=newLinkedList<>();
for(inti=0;i<30000;i++){teste.add(0,i);}
longfim=System.currentTimeMillis();doubletempo=(fim-inicio)/1000.0;System.out.println("Tempogasto:"+tempo);}}
Seguindo o mesmo raciocínio, você pode ver qual é a mais rápida para se percorrer usando oget(indice) (sabemosqueocorreto seriautilizaroenhancedfor ouoIterator). Para isso,
insira30milelementosedepoispercorra-osusandocadaimplementaçãodeList.
Perceba que aqui o nosso intuito não é que você aprenda qual é o mais rápido, o importante éperceberquepodemostirarproveitodopolimorfismoparanoscomprometerapenascomainterface.Depois,quandonecessário,podemostrocareescolherumaimplementaçãomaisadequadaasnossasnecessidades.
Qualdasduaslistasfoimaisrápidaparaadicionarelementosàprimeiraposição?
5. (opcional) Crie a classe Banco (caso não tenha sido criada anteriormente) no pacote
br.com.caelum.contas.modeloquepossuiumaListdeContachamadacontas.Repareque
numalistadeConta,vocêpodecolocartantoContaCorrentequantoContaPoupancaporcausa
dopolimorfismo.
Crie ummétodo void adiciona(Conta c), ummétodo Conta pega(int x) e outro int
pegaQuantidadeDeContas().Basta usar a sua lista e delegar essas chamadaspara osmétodos e
coleçõesqueestudamos.
ComoficouaclasseBanco?
6. (opcional)NoBanco,crieummétodoContabuscaPorTitular(Stringnome)queprocurapor
umaContacujotitularsejaequalsaonomeDoTitulardado.
Vocêpode implementaressemétodocomumfor na sua lista deConta, porémnão temuma
performanceeficiente.
Adicionando um atributo privado do tipo Map<String,Conta> terá um impacto significativo.
Toda vez que o método adiciona(Conta c) for invocado, você deve invocar
.put(c.getTitular(),c)noseumapa.Dessamaneira,quandoalguéminvocarométodoConta
buscaPorTitular(String nomeDoTitular), basta você fazer o get no seu mapa, passando
15.15EXERCÍCIOS:COLLECTIONS 231
nomeDoTitularcomoargumento!
Note, apenas, que isso é só um exercício!Dessa forma você não poderá ter dois clientes com omesmonomenessebanco,oquesabemosquenãoélegal.
ComoficariasuaclasseBancocomesseMap?
7. (opcional, avançado) Crie o método hashCode para a sua conta, de forma que ele respeite o
equalsdequeduascontassãoequalsquandotemomesmonúmeroeagência.Felizmentepara
nós, o próprio Eclipse já vem com um criador de equals e hashCode que os faz de forma
consistente.
NaclasseConta,useoctrl+3ecomeceaescreverhashCodeparaacharaopçãodegerá-los.
Então,selecioneosatributosnumeroeagenciaemandegerarohashCodeeoequals.
Comoficouocódigogerado?
8. (opcional, avançado) Crie uma classe de teste e verifique se sua classe Conta funciona agora
corretamenteemumHashSet,istoé,queelanãoguardacontascomnúmeroeagênciarepetidos.
Depois,removaométodohashCode.Continuafuncionando?
DominarousoeofuncionamentodohashCodeéfundamentalparaobomprogramador.
1. Gere todosos números entre 1 e 1000 e ordene emordemdecrescente utilizandoumTreeSet.
Comoficouseucódigo?
2. Geretodososnúmerosentre1e1000eordeneemordemdecrescenteutilizandoumArrayList.
Comoficouseucódigo?
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
15.16DESAFIOS
Agoraéamelhorhoradeaprenderalgonovo
232 15.16DESAFIOS
E se precisarmos ordernar uma lista com outro critério de comparação? Se precisarmos alterar aprópriaclasseemudarseumétodocompareTo, teremos apenasuma formade comparaçãopor vez.
Precisamosdemais!
É possível definir outros critérios de ordenação usando a interface do java.util chamada
Comparator . Existe um método sort em Collections que recebe, além da List , um
Comparatordefinindoumcritériodeordenaçãoespecífico.ÉpossívelterváriosComparatorscom
critériosdiferentesparausarquandofornecessário.
VamoscriarumComparatorqueserveparaordernarStringsdeacordocomseutamanho.
classComparadorPorTamanhoimplementsComparator<String>{publicintcompare(Strings1,Strings2){if(s1.length()<s2.length())return-1;if(s2.length()<s1.length())return1;return0;}}
Repare que, diferente de Comparable , o método aqui se chama compare e recebe dois
argumentos,jáquequemoimplementanãoéopróprioobjeto.
Podemosdeixá-lomaiscurto,tomandoproveitodométodoestáticoauxiliarInteger.compareque
comparadoisinteiros:
classComparadorPorTamanhoimplementsComparator<String>{publicintcompare(Strings1,Strings2){returnInteger.compare(s1.length(),s2.length());}}
Depois, dentro do nosso código, teríamos uma chamada a Collections.sort passando o
comparadortambém:
List<String>lista=newArrayList<>();lista.add("Sérgio");lista.add("Paulo");lista.add("Guilherme");
//invocandoosortpassandoocomparadorComparadorPorTamanhocomparador=newComparadorPorTamanho();Collections.sort(lista,comparador);
System.out.println(lista);
Comoavariáveltemporáriacomparadoréutilizadaapenasaí,écomumescrevermosdiretamente
Collections.sort(lista,newComparadorPorTamanho()).
15.17 PARA SABER MAIS: COMPARATORS, CLASSES ANÔNIMAS,JAVA8EOLAMBDA
15.17PARASABERMAIS:COMPARATORS,CLASSESANÔNIMAS,JAVA8EOLAMBDA 233
Repareque a classeComparadorPorTamanho é bempequena.É comumhaver a necessidade de
criarvárioscritériosdecomparação,emuitasvezeselessãoutilizadosapenasnumúnicopontodonossoprograma.
Háumaformadeescreveressaclasseeinstanciá-lanumaúnicainstrução.Vocêfazissodandonew
emComparator.Mascomo,sedissemosqueumainterfacenãopodeserinstanciada?Realmentenew
Comparator() não compila. Mas vai compilar se você abrir chaves e implementar tudo o que é
necessário.Vejaocódigo:
List<String>lista=newArrayList<>();lista.add("Sérgio");lista.add("Paulo");lista.add("Guilherme");
Comparator<String>comparador=newComparator<String>(){publicintcompare(Strings1,Strings2){returnInteger.compare(s1.length(),s2.length());}};Collections.sort(lista,comparador);
System.out.println(lista);
Asintaxeérealmenteesdrúxula!Numaúnicalinhanósdefinimosumaclasseeainstanciamos!Umaclassequenemmesmonometem.Poressemotivoorecursoéchamadodeclasseanônima.Eleaparececomcertafrequência,emespecialparanãoprecisarimplementarinterfacesqueocódigodosmétodosseriammuitocurtosenão-reutilizáveis.
Há ainda como diminuir ainda mais o código, evitando a criação da variável temporáriacomparadoreinstanciandoainterfacedentrodainvocaçãoparaosort:
List<String>lista=newArrayList<>();lista.add("Sérgio");lista.add("Paulo");lista.add("Guilherme");
Collections.sort(lista,newComparator<String>(){publicintcompare(Strings1,Strings2){returnInteger.compare(s1.length(),s2.length());}});
System.out.println(lista);
VocêpodefazerodownloaddoJava8aqui:
https://jdk8.java.net/download.html
EscrevendoumComparatorcomclasseanônima
EscrevendoumComparatorcomlambdanoJava8
234 15.17PARASABERMAIS:COMPARATORS,CLASSESANÔNIMAS,JAVA8EOLAMBDA
O Eclipse já possui atualizações para compatibilidade com a nova versão, mas ele pode serrelativamenteinstável.Vocêpodeutilizaralinhadecomando,comofizemosnocomeçodocurso,paraessestestes,casoachenecessário.
ApartirdessanovaversãodoJavaháumaformamaissimplesdeobteressemesmoComparator.
Repare:
Collections.sort(lista,(s1,s2)->Integer.compare(s1.length(),s2.length()));
Ocódigo(s1,s2)->Integer.compare(s1.length(),l2.length())geraráumainstânciade
ComparatorqueocomparedevolveInteger.compare(s1.length,l2.length).Atémesmoo
returnnãoénecessário,jáquesótemosumainstruçãoapóso->.Esseéorecursodelambdado
Java8.
Uma outra novidade do Java 8 é a possibilidade de declarar métodos concretos dentro de umainterface,oschamadosdefaultmethods.Atéo Java7nãoexistiasort em listas.Colocar umnovo
métodoabstratoemuma interfacepode terconsequênciasdrásticas: todomundoquea implementavaparadecompilar!Mascolocarummétododefaultnãotemessemesmoimpactodevastador, jáqueasclassesqueimplementamainterface'herdam'essemétodo.Entãovocêpodefazer:
lista.sort((s1,s2)->Integer.compare(s1.length(),s2.length()));
Háoutrosmétodosnascoleçõesqueutilizamdolambdaparaseremmaissucintos.
UmdeleséoforEach.Vocêpodefazerlista.forEach(s->System.out.println(s)).
OremoveIféoutrodeles.Porexemplo,podemosescreverlista.removeIf(c->c.getSaldo()
<0).OremoveIfrecebecomoargumentoumobjetoqueimplementeainterfacePredicate,que
possuiapenasummétodo,querecebeumelementedevolveboolean.Porpossuirapenasummétodo
abstrato também chamamos essa interface é uma interface funcional. Omesmo ocorre ao invocar oforEach,querecebeumargumentoqueimplementaainterfacefuncionalConsumer.
TrabalharcomlambdasnoJava8vaimuitoalém.Hádiversosdetalheserecursosquenãoveremosnesseprimeirocurso.Casotenhacuriosidadeequeirasabermais,vejanoblog:
http://blog.caelum.com.br/o-minimo-que-voce-deve-saber-de-java-8/
Mais?Methodreferences,streamsecollectors
15.17PARASABERMAIS:COMPARATORS,CLASSESANÔNIMAS,JAVA8EOLAMBDA 235
CAPÍTULO16
"Abenevolênciaésobretudoumvíciodoorgulhoenãoumavirtudedaalma." --DoantienAlphonseFrançois(MarquêsdeSade)
Aotérminodessecapítulo,vocêserácapazde:
usarasclasseswrappers(comoInteger)eboxing;
lereescreverbytes,caractereseStringsde/paraaentradaesaídapadrão;lereescreverbytes,caractereseStringsde/paraarquivos;utilizarbuffersparaagilizaraleituraeescritaatravésdefluxos;usarScannerePrintStream.
VamospassaraconhecerAPIsdoJava.java.ioejava.utilpossuemasclassesquevocêmais
comumentevaiusar,nãoimportandoseseuaplicativoédesktop,web,oumesmoparacelulares.
Apesardeserimportanteconhecernomesemétodosdasclassesmaisutilizadas,ointeressanteaquiéquevocêenxerguequetodososconceitospreviamenteestudadossãoaplicadosatodahoranasclassesdabibliotecapadrão.
Nãosepreocupeemdecorarnomes.Atenha-seementendercomoessasclassesestãorelacionadasecomoelasestãotirandoproveitodousodeinterfaces,polimorfismo,classesabstrataseencapsulamento.Lembre-sedeestarcomadocumentação(javadoc)abertaduranteocontatocomessespacotes.
Veremos também threads e sockets em capítulos posteriores, que ajudarão a condensar nossoconhecimento, tendo em vista que no exercício de sockets utilizaremos todos conceitos aprendidos,juntamentecomasváriasAPIs.
PACOTEJAVA.IO
16.1CONHECENDOUMAAPI
236 16PACOTEJAVA.IO
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
AssimcomotodoorestodasbibliotecasemJava,apartedecontroledeentradaesaídadedados(conhecidocomoio)éorientadaaobjetoseusaosprincipaisconceitosmostradosatéagora:interfaces,classesabstratasepolimorfismo.
Aideiaatrásdopolimorfismonopacotejava.ioédeutilizarfluxosdeentrada(InputStream)e
desaída(OutputStream)paratodaequalqueroperação,sejaelarelativaaumarquivo,aumcampoblobdobancodedados,aumaconexãoremotaviasockets,ouatémesmoàsentradaesaídapadrãodeumprograma(normalmenteotecladoeoconsole).
AsclassesabstratasInputStreameOutputStreamdefinem,respectivamente,ocomportamento
padrãodosfluxosemJava:emumfluxodeentrada,épossívellerbytese,nofluxodesaída,escreverbytes.
A grande vantagem dessa abstração pode ser mostrada em um método qualquer que utiliza umOutputStreamrecebidocomoargumentoparaescreveremumfluxodesaída.Paraondeométodoestá
escrevendo?Nãosesabeenãoimporta:quandoosistemaprecisarescreveremumarquivoouemumasocket,bastachamaromesmométodo,jáqueeleaceitaqualquerfilhadeOutputStream!
Paralerumbytedeumarquivo,vamosusaroleitordearquivo,oFileInputStream.Paraum
FileInputStreamconseguirlerumbyte,eleprecisasaberdeondeeledeveráler.Essainformaçãoé
tãoimportantequequemescreveuessaclasseobrigavocêapassaronomedoarquivopeloconstrutor:semissooobjetonãopodeserconstruído.
classTestaEntrada{
EditoraCasadoCódigocomlivrosdeumaformadiferente
16.2ORIENTAÇÃOAOBJETOSNOJAVA.IO
16.3INPUTSTREAM,INPUTSTREAMREADEREBUFFEREDREADER
16.2ORIENTAÇÃOAOBJETOSNOJAVA.IO 237
publicstaticvoidmain(String[]args)throwsIOException{InputStreamis=newFileInputStream("arquivo.txt");intb=is.read();}}
A classe InputStream é abstrata e FileInputStream uma de suas filhas concretas.
FileInputStream vai procurar o arquivo no diretório em que a JVM fora invocada (no caso do
Eclipse,vaiserapartirdedentrododiretóriodoprojeto).Alternativamentevocêpodeusarumcaminhoabsoluto.
Quandotrabalhamoscomjava.io,diversosmétodoslançamIOException,queéumaexception
do tipo checked - o que nos obriga a tratá-la ou declará-la.Nos exemplos aqui, estamos declarandoIOExceptionatravésdaclausulathrowsdomainapenasparafacilitaroexemplo.Casoaexception
ocorra,aJVMvaiparar,mostrandoastacktrace.Estanãoéumaboapráticaemumaaplicaçãoreal:tratesuasexceptionsparasuaaplicaçãopoderabortarelegantemente.
InputStream tem diversas outras filhas, como ObjectInputStream , AudioInputStream ,
ByteArrayInputStream,entreoutras.
Para recuperarumcaractere,precisamos traduzirosbytescomoencodingdadoparao respectivocódigo unicode, isso pode usar um oumais bytes. Escrever esse decodificador émuito complicado,quemfazissoporvocêéaclasseInputStreamReader.
classTestaEntrada{publicstaticvoidmain(String[]args)throwsIOException{InputStreamis=newFileInputStream("arquivo.txt");InputStreamReaderisr=newInputStreamReader(is);intc=isr.read();}}
OconstrutordeInputStreamReaderpodereceberoencodingaserutilizadocomoparâmetro,se
desejado,talcomoUTF-8ouISO-8859-1.
ENCODINGS
Devidoagrandequantidadedeaplicativosinternacionalizadosdehojeemdia,éimprescindívelqueumbomprogramadorentendabemoquesãooscharacterencodingseoUnicode.OblogdaCaelumpossuiumbomartigoarespeito:
http://blog.caelum.com.br/2006/10/22/entendendo-unicode-e-os-character-encodings/
InputStreamReader é filhada classe abstrataReader, quepossui diversas outras filhas - são
classesquemanipulamchars.
238 16.3INPUTSTREAM,INPUTSTREAMREADEREBUFFEREDREADER
ApesardaclasseabstrataReader jáajudarnotrabalhodemanipulaçãodecaracteres,aindaseria
difícilpegarumaString.AclasseBufferedReaderéumReaderquerecebeoutroReaderpelo
construtoreconcatenaosdiversoscharsparaformarumaStringatravésdométodoreadLine:
classTestaEntrada{publicstaticvoidmain(String[]args)throwsIOException{InputStreamis=newFileInputStream("arquivo.txt");InputStreamReaderisr=newInputStreamReader(is);BufferedReaderbr=newBufferedReader(isr);Strings=br.readLine();}}
Como o próprio nome diz, essa classe lê doReader por pedaços (usando o buffer) para evitar
realizarmuitas chamadasao sistemaoperacional.Vocêpodeaté configuraro tamanhodobufferpeloconstrutor.
Éessaacomposiçãodeclassesqueestáacontecendo:
Essepadrãodecomposiçãoébastanteutilizadoeconhecido.ÉoDecoratorPattern.
Aqui,lemosapenasaprimeiralinhadoarquivo.OmétodoreadLinedevolvealinhaquefoilidae
muda o cursor para a próxima linha. Caso ele chegue ao fim do Reader (no nosso caso, fim do
arquivo),elevaidevolvernull.Então,comumsimpleslaço,podemosleroarquivoporinteiro:
classTestaEntrada{publicstaticvoidmain(String[]args)throwsIOException{InputStreamis=newFileInputStream("arquivo.txt");InputStreamReaderisr=newInputStreamReader(is);BufferedReaderbr=newBufferedReader(isr);
Strings=br.readLine();//primeiralinha
while(s!=null){System.out.println(s);s=br.readLine();}
br.close();}}
16.4LENDOSTRINGSDOTECLADO
16.4LENDOSTRINGSDOTECLADO 239
Com um passe de mágica, passamos a ler do teclado em vez de um arquivo, utilizando oSystem.in,queéumareferênciaaumInputStreamoqual,porsuavez,lêdaentradapadrão.
classTestaEntrada{publicstaticvoidmain(String[]args)throwsIOException{InputStreamis=System.in;InputStreamReaderisr=newInputStreamReader(is);BufferedReaderbr=newBufferedReader(isr);Strings=br.readLine();
while(s!=null){System.out.println(s);s=br.readLine();}}}
Apenasmodificamosaquemavariávelisestásereferindo.Podemosreceberargumentosdotipo
InputStream e ter esse tipo de abstração: não importa exatamente de onde estamos lendo esse
punhadodebytes,desdequeagenterecebaainformaçãoqueestamosquerendo.Comonafigura:
Repare que a ponta da direita poderia ser qualquer InputStream, seja ObjectInputStream,
AudioInputStream,ByteArrayInputStream, ou a nossa FileInputStream. Polimorfismo! Ou
vocêmesmopodecriarumafilhadeInputStream,sedesejar.
Por isso émuito comummétodos recebereme retornaremInputStream, em vez de suas filhas
específicas. Com isso, elas desacoplam as informações e escondem a implementação, facilitando amudançaemanutençãodocódigo.Reparequeissovaiaoencontrodetudooqueaprendemosduranteoscapítulosqueapresentaramclassesabstratas,interfaces,polimorfismoeencapsulamento.
240 16.4LENDOSTRINGSDOTECLADO
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
Comovocêpodeimaginar,escreveremumarquivoéomesmoprocesso:
classTestaSaida{publicstaticvoidmain(String[]args)throwsIOException{OutputStreamos=newFileOutputStream("saida.txt");OutputStreamWriterosw=newOutputStreamWriter(os);BufferedWriterbw=newBufferedWriter(osw);
bw.write("caelum");
bw.close();}}
Lembre-sededarrefresh(cliquedadireitanonomedoprojeto,refresh)noseuprojetodoEclipseparaqueoarquivocriadoapareça.OFileOutputStream pode receber umbooleano como segundo
parâmetro,paraindicarsevocêquerreescreveroarquivooumanteroquejáestavaescrito(append).
OmétodowritedoBufferedWriternãoinsereo(s)caractere(s)dequebradelinha.Paraisso,
vocêpodechamarométodonewLine.
JáconheceoscursosonlineAlura?
16.5AANALOGIAPARAAESCRITA:OUTPUTSTREAM
16.5AANALOGIAPARAAESCRITA:OUTPUTSTREAM 241
FECHANDOOARQUIVOCOMOFINALLYEOTRY-WITH-RESOURCES
Éimportantesemprefecharoarquivo.Vocêpodefazer issochamandodiretamenteométodo close do FileInputStream / OutputStream , ou ainda chamando o close do
BufferedReader/Writer.Nesseúltimocaso,ocloseserácascateadoparaosobjetososquais
oBufferedReader/Writer utiliza para realizar a leitura/escrita, além dele fazer o flush dosbuffersnocasodaescrita.
Écomumefundamentalqueocloseestejadentrodeumblocofinally.Seumarquivofor
esquecidoabertoea referênciaparaele forperdida,podeserqueele seja fechadopelogarbagecollector,queveremosmaisafrente,porcausadofinalize.Masnãoébomvocêseprendera
isso. Se você esquecer de fechar o arquivo, no caso de um programa minúsculo como esse, oprogramavaiterminarantesqueotaldogarbagecollectorteajude,resultandoemumarquivonãoescrito(osbytesficaramnobufferdoBufferedWriter).Problemassimilarespodemacontecer
comleitoresquenãoforemfechados.
No Java 7 há a estrutura try-with-resources, que já fará o finally cuidar dos recursos
declarados 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(BufferedReaderbr=newBufferedReader(newFile("arquivo.txt"))){//comexceçãoounão,oclose()dobrserainvocado}
ApartirdoJava5,temosaclassejava.util.Scanner,quefacilitabastanteotrabalhodelerde
umInputStream.Alémdisso,aclassePrintStreampossuiumconstrutorquejárecebeonomede
umarquivocomoargumento.Dessaforma,aleituradotecladocomsaídaparaumarquivoficoumuitosimples:
Scanners=newScanner(System.in);PrintStreamps=newPrintStream("arquivo.txt");while(s.hasNextLine()){ps.println(s.nextLine());}
Nenhumdosmétodos lançaIOException:PrintStream lança FileNotFoundException se
vocêoconstruirpassandoumaString.EssaexceçãoéfilhadeIOExceptioneindicaqueoarquivo
nãofoiencontrado.OScannerconsideraráquechegouaofimseumaIOExceptionforlançada,mas
16.6UMAMANEIRAMAISFÁCIL:SCANNEREPRINTSTREAM
242 16.6UMAMANEIRAMAISFÁCIL:SCANNEREPRINTSTREAM
o PrintStream simplesmente engole exceptions desse tipo. Ambos possuem métodos para você
verificarsealgumproblemaocorreu.
AclasseScanner édopacotejava.util.Ela possuimétodosmuitoúteis para trabalhar com
Strings, em especial, diversos métodos já preparados para pegar números e palavras já formatadasatravésdeexpressõesregulares.Ficafácilparsearumarquivocomqualquerformatodado.
SYSTEM.OUT
Comovimosnocapítulopassado,oatributooutdaclasseSystemédotipoPrintStream
(e,portanto,éumOutputStream).
EOF
Quando rodar sua aplicação, para encerrar a entrada de dados do teclado, é necessárioenviarmosumsinaldefimdestream.ÉofamosoEOF,istoé,endoffile.
NoLinux/Mac/Solaris/Unixvocêfazissocomoctrl+D.NoWindows,useoctrl+Z.
Existemduasclasseschamadasjava.io.FileReaderejava.io.FileWriter.Elassãoatalhos
paraaleituraeescritadearquivos.
Odo { .. } while(condicao); é uma alternativa para se construir um laço. Pesquise-o e
utilize-onocódigoparalerumarquivo,elevaificarmaissucinto(vocênãoprecisaráleraprimeiralinhaforadolaço).
16.7UMPOUCOMAIS...
16.7UMPOUCOMAIS... 243
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoJavaeOrientaçãoaObjetos
Anteriormente, vimos que conseguimos ler e escrever dados emumarquivo no Java utilizando aclasseScanner. Por padrão, quando fazemos essas operações, estamos trabalhando sempre comos
dadosemformadeString.Maseseprecisássemoslerouescrevernúmerosinteirosemumarquivo?
ComofaríamosparatransformaressesnúmerosemStringevice-versa?
Cuidado!Usamosaquiotermo"transformar",porémoqueocorrenãoéumatransformaçãoentreostiposesimumaformadeconseguirmosumStringdadoumintevice-versa.Ojeitomaissimples
detransformarumnúmeroemStringéconcatená-lodaseguintemaneira:
inti=100;Strings=""+i;System.out.println(s);
doubled=1.2;Strings2=""+d;System.out.println(s2);
Paraformataronúmerodeumamaneiradiferente,comvírgulaenúmerodecasasdecimaisdevemosutilizaroutrasclassesdeajuda(NumberFormat,Formatter).
ParatransformarumaStringemnúmero,utilizamosasclassesdeajudaparaostiposprimitivos
correspondentes. Por exemplo, para transformar a String s em um número inteiro utilizamos o
métodoestáticodaclasseInteger:
Strings="101";inti=Integer.parseInt(s);
As classes Double, Short, Long , Float etc contêm o mesmo tipo de método, como
parseDoubleeparseFloatqueretornamumdoubleefloatrespectivamente.
Essas classes também sãomuitoutilizadaspara fazer owrapping (embrulho) de tiposprimitivos
VocêpodetambémfazerocursodatadessaapostilanaCaelum
16.8INTEGERECLASSESWRAPPERS(BOX)
244 16.8INTEGERECLASSESWRAPPERS(BOX)
como objetos, pois referências e tipos primitivos são incompatíveis. Imagine que precisamos passarcomoargumentouminteiroparaonossoguardadordeobjetos.UminteironãoéumObject, como
fazer?
inti=5;Integerx=newInteger(i);guardador.adiciona(x);
E,dadoumInteger,podemospegarointqueestádentrodele(desembrulhá-lo):
inti=5;Integerx=newInteger(i);intnumeroDeVolta=x.intValue();
Esse processo de wrapping e unwrapping é entediante. O Java 5.0 em diante traz um recursochamadodeautoboxing,quefazissosozinhoparavocê,custandolegibilidade:
Integerx=5;inty=x;
NoJava1.4essecódigoéinválido.NoJava5.0emdianteelecompilaperfeitamente.Éimportanteressaltar que isso não quer dizer que tipos primitivos e referências sejam do mesmo tipo, isso ésimplesmenteum"açúcarsintático"(syntaxsugar)parafacilitaracodificação.
Vocêpodefazertodosostiposdeoperaçõesmatemáticascomoswrappers,porémcorreoriscodetomarumNullPointerException.
Você pode fazer o autoboxing diretamente paraObject também, possibilitando passar um tipo
primitivoparaummétodoquereceberObjectcomoargumento:
Objecto=5;
NaclasseMath,existeumasériedemétodosestáticosquefazemoperaçõescomnúmeroscomo,
por exemplo, arredondar(round), tirar o valor absoluto (abs), tirar a raiz(sqrt), calcular o
seno(sin)eoutros.
doubled=4.6;longi=Math.round(d);
intx=-4;inty=Math.abs(x);
Consulteadocumentaçãoparaveragrandequantidadedemétodosdiferentes.
NoJava5.0,podemostirarproveitodoimportstaticaqui:
16.9AUTOBOXINGNOJAVA5.0
16.10PARASABERMAIS:JAVA.LANG.MATH
16.9AUTOBOXINGNOJAVA5.0 245
importstaticjava.lang.Math.*;
Issoeliminaanecessidadedeusaronomedaclasse,sobocustodelegibilidade:
doubled=4.6;longi=round(d);intx=-4;inty=abs(x);
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Vamossalvarascontascadastradasemumarquivoparanãoprecisarficaradicionandoascontasatodomomento.
1. NaclasseManipuladorDeContas,crieométodosalvaDadosquerecebeumEvento de onde
obteremosalistadecontas:
publicvoidsalvaDados(Eventoevento){List<Conta>contas=evento.getLista("listaContas");//aquisalvaremosascontasemarquivo}
2. Para não colocarmos todo o código de gerenciamento de arquivos dentro da classeManipuladorDeContas,vamoscriarumanovaclassecujaresponsabilidadeserálidarcomaescrita
/ leitura de arquivos. Crie a classe RepositorioDeContas dentro do pacote
br.com.caelum.contasedeclareométodosalvaquedeveráreceberalistadecontasaserem
guardadas.Nestemétodovocêdevepercorreralistadecontasesalvá-lasseparandoasinformaçõesdetipo,numero,agencia,titularesaldocomvírgulas.Ocódigoficaráparecidocom:
publicclassRepositorioDeContas{
publicvoidsalva(List<Conta>contas){PrintStreamstream=newPrintStream("contas.txt");for(Contaconta:contas){
Seuslivrosdetecnologiaparecemdoséculopassado?
16.11EXERCÍCIOS:JAVAI/O
246 16.11EXERCÍCIOS:JAVAI/O
stream.println(conta.getTipo()+","+conta.getNumero()+","+conta.getAgencia()+","+conta.getTitular()+","+conta.getSaldo());}stream.close();}}
O compilador vai reclamar que você não está tratando algumas exceções (comojava.io.FileNotFoundException).Utilize o devidotry/catch e relance a exceção como
RuntimeException.UtilizeoquickfixdoEclipseparafacilitar(ctrl+1).
Vale lembrarquedeixar todasasexceptionspassaremdespercebidasnãoéumaboaprática!Vocêpodeusaraqui,poisestamosfocandoapenasnoaprendizadodautilizaçãodojava.io.
Quandotrabalhamoscomrecursosquefalamcomaparteexternaànossaaplicação,éprecisoqueavisemosquandoacabarmosdeusaressesrecursos.Porisso,éimportantíssimolembrardefecharoscanaiscomoexteriorqueabrimosutilizandoométodoclose!
3. Voltando à classe ManipuladorDeContas, vamos completar o método salvaDados para que
utilizeanossanovaclasseRepositorioDeContascriada.
publicvoidsalvaDados(Eventoevento){List<Conta>contas=evento.getLista("listaContas");RepositorioDeContasrepositorio=newRepositorioDeContas();repositorio.salva(contas);}
Rodesuaaplicação,cadastrealgumascontasevejaseapareceumarquivochamadocontas.txt
dentrododiretóriosrcdeseuprojeto.TalvezsejanecessáriodarumF5neleparaqueoarquivo
apareça.
4. (Opcional,Difícil)Vamosfazercomquealémdesalvarosdadosemumarquivo,nossaaplicaçãotambém consiga carregar as informações das contas para já exibir na tela. Para que a aplicaçãofuncione, é necessário que a nossa classe ManipuladorDeContas possua um método chamado
carregaDados que devolva uma List<Conta>. Vamos fazer o mesmo que anteriormente e
encapsularalógicadecarregamentodentrodaclasseRepositorioDeContas:
publicList<Conta>carregaDados(){RepositorioDeContasrepositorio=newRepositorioDeContas();returnrepositorio.carrega();}
Faça o código referente ao método carrega que devolve uma List dentro da classe
RepositorioDeContasutilizandoaclasseScanner.Paraobterosvaloresdecadaatributovocê
podeutilizarométodosplitdaString.Lembre-sequeosatributosdascontassãocarregados
naseguinteordem:tipo,numero,agencia,titularesaldo.Exemplo:
Stringlinha=scanner.nextLine();
16.11EXERCÍCIOS:JAVAI/O 247
String[]valores=linha.split(",");Stringtipo=valores[0];
Alémdisso,acontadeveserinstanciadadeacordocomoconteúdodotipoobtido.Tambémfique
atentopois os dados lidosvirão sempre lidos em formadeString e para alguns atributos será
necessáriotransformarodadonostiposprimitivoscorrespondentes.Porexemplo:
StringnumeroTexto=valores[1];intnumero=Integer.parseInt(numeroTexto);
5. (opcional) A classe Scanner é muito poderosa! Consulte seu javadoc para saber sobre o
delimitereosoutrosmétodosnext.
6. (opcional) Crie uma classe TestaInteger e vamos fazer comparações com Integers dentro do
main:
Integerx1=newInteger(10);Integerx2=newInteger(10);
if(x1==x2){System.out.println("igual");}else{System.out.println("diferente");}
Esetestarmoscomoequals?Oquepodemosconcluir?
7. (opcional)Umdoublenãoestásendosuficienteparaguardaraquantidadedecasasnecessáriasem
umaaplicação.Precisoguardarumnúmerodecimalmuitogrande!Oquepoderiausar?
Odouble tambémtemproblemasdeprecisãoaofazercontas,porcausadearredondamentosda
aritméticadepontoflutuantedefinidopelaIEEE754:
http://en.wikipedia.org/wiki/IEEE_754
Elenãodeveserusadosevocêprecisarealmentedemuitaprecisão(casosqueenvolvamdinheiro,porexemplo).
Consulteadocumentação,tenteadivinharondevocêpodeencontrarumtipoqueteajudariapararesolveressescasosevejacomoéintuitivo!Qualéaclassequeresolveriaessesproblemas?
Lembre-se:noJavahámuitojápronto.Sejanabibliotecapadrão,sejaembibliotecasopen sourcequevocêpodeencontrarpelainternet.
Aplicarbemosconceitosdeorientaçãoaobjetosésempreumagrandedúvida.Semprequeremosencapsular direito, favorecer a flexibilidade, desacoplar classes, escrever código elegante e de fácil
16.12 DISCUSSÃO EM AULA: DESIGN PATTERNS E O TEMPLATEMETHOD
248 16.12DISCUSSÃOEMAULA:DESIGNPATTERNSEOTEMPLATEMETHOD
manutenção.EouvimosfalarqueaOrientaçãoaObjetosajudaemtudoisso.
Mas,ondeusarherançadeformasaudável?Comousarinterfaces?Ondeopolimorfismomeajuda?Comoencapsulardireito?Classesabstratassãousadasemquesituações?
Muitos anos atrás, grandes nomes domundo da orientação a objetos perceberam que criar bonsdesigns orientados a objetos era um grande desafio para muitas pessoas. Perceberam que muitosproblemas de OO apareciam recorrentemente em vários projetos; e que as pessoas já tinham certassoluçõesparaessesproblemasclássicos(nemsempremuitoelegantes).
O que fizeram foi criar soluções padrões para problemas comuns na orientação a objetos, echamaramissodeDesignPatterns, ouPadrõesdeProjeto.O conceito vinhada arquitetura onde eramuitocomumteressetipodesolução.E,em1994,ganhougrandepopularidadenacomputaçãocomolivroDesignPatterns:ElementsofReusableObject-OrientedSoftware,umcatálogocomváriasdessassoluções escrito por Erich Gamma, Ralph Johnson, Richard Helm e John Vlissides (a Gangue dosQuatro,GoF).
DesignPatterns tornou-sereferênciaabsolutanobomusodaorientaçãoaobjetos.Outrospadrõessurgiram depois, em outras literaturas igualmente consagradas. O conhecimento dessas técnicas éimprescindívelparaobomprogramador.
DiscutacomoinstrutorcomoDesignPatternsajudamaresolverproblemasdemodelagememsistemas orientados a objetos. Veja como Design Patterns são aplicados em muitos lugares dopróprioJava.
OinstrutorcomentarádoTemplateMethodemostraráocódigofontedométodoread()daclasse
java.io.InputStream:
publicintread(byteb[],intoff,intlen)throwsIOException{if(b==null){thrownewNullPointerException();}elseif(off<0||len<0||len>b.length-off){thrownewIndexOutOfBoundsException();}elseif(len==0){return0;}
intc=read();if(c==-1){return-1;}
b[off]=(byte)c;
inti=1;try{for(;i<len;i++){c=read();if(c==-1){break;}
16.12DISCUSSÃOEMAULA:DESIGNPATTERNSEOTEMPLATEMETHOD 249
b[off+i]=(byte)c;}}catch(IOExceptionee){}returni;}
Discuta em aula como esse método aplica conceitos importantes da orientação a objetos epromoveflexibilidadeeextensibilidade.
250 16.12DISCUSSÃOEMAULA:DESIGNPATTERNSEOTEMPLATEMETHOD
CAPÍTULO17
"Aprimeiracoisaaentenderéquevocênãoentende."--SorenAabyeKierkegaard
Ondecontinuarao terminarosexercíciosde 'JavaeOrientaçãoaObjetos'?Aquiháumpostcomsugestõesdecomoiniciarnacarreira:
http://blog.caelum.com.br/como-posso-aprender-java-e-iniciar-na-carreira/
Evocêpodeseguirnessescursoseáreas:
Umdos principais usos do Java é rodar aplicaçõesweb. Entram aqui tecnologias comoServlets,JSPseferramentasfamosasdomercado,comooStruts.
ACaelum oferece o curso FJ-21, onde você pode estudar os tópicos necessários para começar atrabalharcomJavanawebusandoasmelhorespráticas,designpatternsetecnologiasdomercado.Essaapostilatambémestádisponívelparadownload.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
A melhor maneira para fixar tudo o que foi visto nos capítulos anteriores é planejar e montarpequenos sistemas. Pense na modelagem de suas classes, como e onde usar herança, polimorfismo,
EAGORA?
17.1WEB
Agoraéamelhorhoradeaprenderalgonovo
17.2PRATICANDOJAVAEUSANDOBIBLIOTECAS
17EAGORA? 251
encapsulamentoeoutrosconceitos.PratiqueousodasAPIsmaisúteisdoJava integrando-asaoseussistemas.
OcursoFJ-22 éum laboratórioque alémdedemonstrarousodiversasAPIs eboaspráticas, vaimostrardiversosdesignpatternseseuscasosdeuso.
Diversosprogramadorescomomínimooumáximodeconhecimentosereúnemonlineparaatrocadedúvidas,informaçõeseideiassobreprojetos,bibliotecasemuitomais.Sãoosgruposdeusuáriosdejava.
UmdosmaisimportanteseconhecidosnoBrasiléoGUJ:
http://www.guj.com.br
O'FalandoemJava'nãopáraporaqui.ACaelumofereceumagrandevariedadedecursosquevocêpodeseguir.Algunsdosmaisrequisitados:
FJ-21:JavaparadesenvolvimentoWeb
FJ-22:LaboratórioJavacomTestes,JSF,WebServiceseDesignPatterns
FJ-25:PersistênciacomJPA,HibernateeEJBlite
FJ-26:LaboratórioWebcomJSFeCDI
FJ-57:DesenvolvimentomóvelcomGoogleAndroid
FJ-91:ArquiteturaeDesigndeProjetosJava
Consulte mais informações no nosso site e entre em contato conosco. Conheça nosso mapa decursos:
http://www.caelum.com.br/mapa-dos-cursos/
17.3GRUPOSDEUSUÁRIOS
17.4PRÓXIMOSCURSOS
252 17.3GRUPOSDEUSUÁRIOS
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
EditoraCasadoCódigocomlivrosdeumaformadiferente
17.4PRÓXIMOSCURSOS 253
CAPÍTULO18
"Oúnicolugarondeosucessovemantesdotrabalhoénodicionário."--AlbertEinstein
Aotérminodessecapítulo,vocêserácapazde:
executartarefassimultaneamente;colocartarefasparaaguardaratéqueumdeterminadoeventoocorra;entenderofuncionamentodoGarbageCollector.
Emváriassituações,precisamos"rodarduascoisasaomesmo tempo". ImagineumprogramaquegeraumrelatóriomuitograndeemPDF.Éumprocessodemoradoe,paradaralgumasatisfaçãoparaousuário, queremosmostrar umabarra deprogresso.Queremos entãogerar oPDFeaomesmo tempoatualizarabarrinha.
Pensandoumpoucomaisamplamente,quandousamosocomputadortambémfazemosváriascoisassimultaneamente:queremosnavegarnainterneteaomesmotempoouvirmúsica.
Anecessidadedesefazerváriascoisassimultaneamente,aomesmotempo,paralelamente,aparecefrequentemente na computação. Para vários programas distintos, normalmente o próprio sistemaoperacionalgerenciaissoatravésdeváriosprocessosemparalelo.
Em um programa só (um processo só), se queremos executar coisas em paralelo, normalmentefalamosdeThreads.
Em Java, usamos a classe Thread do pacote java.lang para criarmos linhas de execução
paralelas.AclasseThreadrecebecomoargumentoumobjetocomocódigoquedesejamosrodar.Por
exemplo,noprogramadePDFebarradeprogresso:
publicclassGeraPDF{
APÊNDICE-PROGRAMAÇÃOCONCORRENTEETHREADS
18.1THREADS
"Duastarefasaomesmotempo"
ThreadsemJava
254 18APÊNDICE-PROGRAMAÇÃOCONCORRENTEETHREADS
publicvoidrodar(){//lógicaparageraropdf...}}
publicclassBarraDeProgresso{publicvoidrodar(){//mostrabarradeprogressoevaiatualizandoela...}}
E,nométodomain,criamososobjetosepassamosparaaclasseThread.Ométodostart é
responsávelporiniciaraexecuçãodaThread:
publicclassMeuPrograma{publicstaticvoidmain(String[]args){
GeraPDFgerapdf=newGeraPDF();ThreadthreadDoPdf=newThread(gerapdf);threadDoPdf.start();
BarraDeProgressobarraDeProgresso=newBarraDeProgresso();ThreadthreadDaBarra=newThread(barraDeProgresso);threadDaBarra.start();
}}
Ocódigoacima,porém,nãocompilará.ComoaclasseThread sabequedevechamarométodo
roda?Comoelasabequenomedemétododaremosequeeladevechamaressemétodoespecial?Falta
naverdadeumcontratoentreasnossasclassesaseremexecutadaseaclasseThread.
Esse contrato existe e é feito pela interface Runnable : devemos dizer que nossa classe é
"executável"equesegueessecontrato.NainterfaceRunnable,háapenasummétodochamadorun.
Bastaimplementá-lo,"assinar"ocontratoeaclasseThreadjásaberáexecutarnossaclasse.
publicclassGeraPDFimplementsRunnable{publicvoidrun(){//lógicaparageraropdf...}}
publicclassBarraDeProgressoimplementsRunnable{publicvoidrun(){//mostrabarradeprogressoevaiatualizandoela...}}
AclasseThread recebe no construtor umobjeto que éumRunnable, e seumétodostart
chamaométodorundanossaclasse.ReparequeaclasseThreadnãosabequaléotipoespecíficoda
nossaclasse;paraela,bastasaberqueaclassesegueocontratoestabelecidoepossuiométodorun.
Éobomusodeinterfaces,contratosepolimorfismonaprática!
18.1THREADS 255
ESTENDENDOACLASSETHREAD
A classe Thread implementa Runnable. Então, você pode criar uma subclasse dela e
reescreverorunque,naclasseThread,nãofaznada:
publicclassGeraPDFextendsThread{publicvoidrun(){//...}}
E,comonossaclasseéumaThread,podemosusarostartdiretamente:
GeraPDFgera=newGeraPDF();gera.start();
Apesar de ser um código mais simples, você está usando herança apenas por "preguiça"(herdamosummontedemétodosmasusamosapenasorun),enãoporpolimorfismo,queseriaa
grandevantagem.PrefiraimplementarRunnableaherdardeThread.
DORMINDO
Para que a thread atual durma basta chamar ométodo a seguir, por exemplo, para dormir 3segundos:
javaThread.sleep(3*1000);
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoJavaeOrientaçãoaObjetos
VocêpodetambémfazerocursodatadessaapostilanaCaelum
256 18.1THREADS
Vejaaclasseaseguir:
publicclassProgramaimplementsRunnable{
privateintid;//colocargetteresetterproatributoid
publicvoidrun(){for(inti=0;i<10000;i++){System.out.println("Programa"+id+"valor:"+i);}}}
Éumaclasseque implementaRunnable e,nométodorun, apenas imprimedezmil números.
Vamosusá-lasduasvezesparacriarduasthreadseimprimirosnúmerosduasvezessimultaneamente:
publicclassTeste{publicstaticvoidmain(String[]args){
Programap1=newPrograma();p1.setId(1);
Threadt1=newThread(p1);t1.start();
Programap2=newPrograma();p2.setId(2);
Threadt2=newThread(p2);t2.start();
}}
Serodarmosesseprograma,qualseráasaída?Deumamiledepoisdeumamil?Provavelmentenã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?Exatamenteintercalado?
Naverdade,nãosabemosexatamentequaléasaída.Rodeoprogramaváriasvezeseobserve:emcadaexecuçãoasaídaéumpoucodiferente.
Oproblemaéquenocomputadorexisteapenasumprocessadorcapazdeexecutarcoisas.Equandoqueremosexecutarváriascoisasaomesmotempo,eoprocessadorsóconseguefazerumacoisadecadavez?Entraemcenaoescalonadordethreads.
O escalonador (scheduler), sabendoque apenasuma coisa pode ser executadade cadavez, pegatodasas threadsqueprecisamserexecutadasefazoprocessadorficaralternandoaexecuçãodecadauma delas. A ideia é executar um pouco de cada thread e fazer essa troca tão rapidamente que aimpressãoqueficaéqueascoisasestãosendofeitasaomesmotempo.
18.2ESCALONADORETROCASDECONTEXTO
18.2ESCALONADORETROCASDECONTEXTO 257
Oescalonadoréresponsávelporescolherqualapróximathreadaserexecutadaefazeratrocadecontexto (contextswitch).Eleprimeirosalvaoestadodaexecuçãoda threadatualparadepoispoderretomar a execução da mesma. Aí ele restaura o estado da thread que vai ser executada e faz oprocessadorcontinuaraexecuçãodesta.Depoisdeumcertotempo,estathreadétiradadoprocessador,seuestado(ocontexto)ésalvoeoutrathreadécolocadaemexecução.Atrocadecontextoéjustamenteas operações de salvar o contexto da thread atual e restaurar o da thread que vai ser executada emseguida.
Quando fazer a troca de contexto, por quanto tempo a thread vai rodar e qual vai ser a próximathread a ser executada, são escolhas do escalonador. Nós não controlamos essas escolhas (emborapossamosdar"dicas"aoescalonador).Porissoquenuncasabemosaocertoaordememqueprogramasparalelossãoexecutados.
Vocêpodepensarqueéruimnãosaberaordem.Maspercebaqueseaordemimportaparavocê,seé importantequedeterminadacoisasejafeitaantesdeoutra,entãonãoestamosfalandodeexecuçõesparalelas,massimdeumprogramasequencialnormal(ondeumacoisaéfeitadepoisdaoutra,emumasequência).
Todo esse processo é feito automaticamente pelo escalonador do Java (e,mais amplamente, peloescalonador do sistema operacional). Para nós, programadores das threads, é como se as coisasestivessemsendoexecutadasaomesmotempo.
EEMMAISDEUMPROCESSADOR?
AVMdoJavaeamaioriadosSOsmodernosconseguefazerproveitodesistemascomváriosprocessadoresoumulti-core.Adiferençaéqueagora temosmaisdeumprocessadorexecutandocoisaseteremos,sim,execuçõesverdadeiramenteparalelas.
MasonúmerodeprocessosnoSOeonúmerodeThreadsparalelascostumamsertãograndesque, mesmo com vários processadores, temos as trocas de contexto. A diferença é que oescalonadortemdoisoumaisprocessadoresparaexecutarsuasthreads.Masdificilmenteteráumamáquinacommaisprocessadoresquethreadsparalelasexecutando.
OGarbageCollector(coletordelixo,lixeiro)funcionacomoumaThreadresponsávelporjogarforatodososobjetosquenãoestãosendoreferenciadospornenhumoutroobjeto-sejademaneiradiretaouindireta.
Considereocódigo:
18.3GARBAGECOLLECTOR
258 18.3GARBAGECOLLECTOR
Contaconta1=newContaCorrente();Contaconta2=newContaCorrente();
Atéestemomento,sabemosquetemos2objetosemmemória.Aqui,oGarbageCollectornãopodeeliminarnenhumdosobjetos,poisaindatemalguémsereferindoaelesdealgumaforma.
Podemos, então, executar uma linha que nos faça perder a referência para um dos dois objetoscriados,como,porexemplo,oseguintecódigo:
conta2=conta1;
Quantosobjetostemosemmemória?
Perdemosareferênciaparaumdosobjetosqueforamcriados.Esseobjetojánãoémaisacessível.Temos,então,apenasumobjetoemmemória?Nãopodemosafirmarisso!ComooGarbageCollectoréumaThread,vocênãotemgarantiadequandoelevairodar.Vocêsósabeque,emalgummomentonofuturo,aquelamemóriavaiserliberada.
Algumaspessoascostumamatribuirnullaumavariável,comointuitodeacelerarapassagemdo
GarbageCollectorporaqueleobjeto:
for(inti=0;i<100;i++){Listx=newArrayList();//fazalgumascoisascomaarraylistx=null;}
Isso rarissimamente é necessário. O Garbage Collector age apenas sobre objetos, nunca sobrevariáveis.Nessecaso,avariávelxnãoexistirámaisacadaiteração,deixandoaArrayList criada
semnenhumareferênciaparaela.
SYSTEM.GC()
Você nunca consegue forçar oGarbageCollector,mas chamando ométodo estáticogc da
classeSystem, você está sugerindo que a VirtualMachine rode o Garbage Collector naquele
momento.Sesuasugestãovaiseraceitaounão,istodependedeJVMparaJVM,evocênãotemgarantias.Evite o uso destemétodo.Você não deve basear sua aplicação emquando oGarbageCollectorvairodarounão.
18.3GARBAGECOLLECTOR 259
FINALIZER
A classe Object define também ummétodo finalize, que você pode reescrever. Esse
método será chamado no instante antes do Garbage Collector coletar este objeto. Não é umdestrutor, você não sabe em quemomento ele será chamado. Algumas pessoas o utilizam paraliberarrecursos"caros"comoconexões,threadserecursosnativos.Issodeveserutilizadoapenasporsegurança:oidealéliberaressesrecursosomaisrápidopossível,semdependerdapassagemdoGarbageCollector.
1. Testeoexemplodestecapítuloparaimprimirnúmerosemparalelo.
EscrevaaclassePrograma:
publicclassProgramaimplementsRunnable{
privateintid;//colocargetteresetterproatributoid
publicvoidrun(){for(inti=0;i<10000;i++){System.out.println("Programa"+id+"valor:"+i);}}}
EscrevaaclassedeTeste:
publicclassTeste{publicstaticvoidmain(String[]args){
Programap1=newPrograma();p1.setId(1);
Threadt1=newThread(p1);t1.start();
Programap2=newPrograma();p2.setId(2);
Threadt2=newThread(p2);t2.start();
}}
Rode várias vezes a classeTeste e observe os diferentes resultados em cada execução. O que
muda?
18.4EXERCÍCIOS
260 18.4EXERCÍCIOS
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
É comum aparecer uma classe anônima junto com uma thread. Vimos como usá-la com oComparator.VamosvercomousaremumRunnable.
ConsidereumRunnablesimples,queapenasmandaimprimiralgonasaídapadrão:
publicclassPrograma1implementsRunnable{publicvoidrun(){for(inti=0;i<10000;i++){System.out.println("Programa1valor:"+i);}}}
Noseumain,vocêfaz:
Runnabler=newPrograma1();Threadt=newThread(r);t.start();
Emvezde criar essa classePrograma1, podemosutilizar o recursode classe anônima.Ela nos
permitedarnewnumainterface,desdequeimplementemosseusmétodos.Comisso,podemoscolocar
diretamentenomain:
Runnabler=newRunnable(){publicvoidrun(){for(inti=0;i<10000;i++)System.out.println("programa1valor"+i);}};Threadt=newThread(r);t.start();
Seuslivrosdetecnologiaparecemdoséculopassado?
18.5EASCLASSESANÔNIMAS?
18.5EASCLASSESANÔNIMAS? 261
LIMITAÇÕESDASCLASSESANÔNIMAS
O uso de classes anônimas tem limitações. Não podemos declarar um construtor. Comoestamosinstanciandoumainterface,entãonãoconseguimospassarumparâmetroparaela.Comoentão passar o id como argumento? Você pode, de dentro de uma classe anônima, acessar
atributos da classe dentro da qual foi declarada! Também pode acessar as variáveis locais dométodo,desdequeelessejamfinal.
Dá para ir mais longe com o Java 8, utilizando o lambda. Como Runnable é uma interface
funcional(contémapenasummétodoabstrato),elapodeserfacilmenteescritadessaforma:
Runnabler=()->{for(inti=0;i<10000;i++)System.out.println("programa1valor"+i);};Threadt=newThread(r);t.start();
A sintaxe pode ser um pouco estranha.Como não há parâmetros a serem recebidos pelométodorun, usamoso() para indicar isso.Vale lembrar,mais umavez, queno lambdanãoprecisamos
escreveronomedométodoqueestamos implementando,nonossocasoorun. Isso é possível pois
existeapenasummétodoabstratonainterface.
Querdeixarocódigomaisenxutoainda?PodemospassarolambdadiretamenteparaoconstrutordeThread,semcriarumavariáveltemporária!Elogoemseguidachamarostart:
newThread(()->{for(inti=0;i<10000;i++)System.out.println("programa1valor"+i);}).start();
Obviamente o uso excessivo de lambdas e classes anônimas pode causar uma certa falta delegibilidade.Vocêdeve lembrarqueusamosessesrecursosparaescrevercódigosmais legíveis,enãoapenas para poupar algumas linhas de código.Caso nossa implementação do lambda venha a ser deváriaslinhas,éumfortesinaldequedeveríamosterumaclasseapartesomenteparaela.
EcomlambdadoJava8?
262 18.5EASCLASSESANÔNIMAS?
CAPÍTULO19
"Olhoporolho,eomundoacabarácego."--MohandasGandhi
Conectando-seamáquinasremotas.
Nestecapítulo,vocêvaiconheceraAPIdeSocketsdojavapelopacotejava.net.
Mais útil que conhecer a API, é você perceber que estamos usando, aqui, todos os conceitos ebibliotecas aprendidas durante os outros capítulos. Repare, também, que é relativamente simplesaprenderautilizarumaAPI,agoraquetemostodososconceitosnecessáriosparatal.
Lembre-sedefazeresseapêndicecomojavadocabertoaoseulado.
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoJavaeOrientaçãoaObjetos
Da necessidade de dois computadores se comunicarem, surgiram diversos protocolos quepermitissemtaltrocadeinformação:oprotocoloquevamosusaraquiéoTCP(TransmissionControlProtocol).
AtravésdoTCP,épossívelcriarumfluxoentredoiscomputadores-comoémostradonodiagramaabaixo:
APÊNDICE-SOCKETS
19.1MOTIVAÇÃO:UMAAPIQUEUSAOSCONCEITOSAPRENDIDOS
VocêpodetambémfazerocursodatadessaapostilanaCaelum
19.2PROTOCOLO
19APÊNDICE-SOCKETS 263
Épossível conectarmais de um cliente aomesmo servidor, como é o caso de diversos banco dedados,servidoresWeb,etc.
Ao escrever um programa em Java que se comunique com outra aplicação, não é necessário sepreocupar com um nível tão baixo quanto o protocolo.As classes que trabalham com eles já foramdisponibilizadasparaseremusadaspornósnopacotejava.net.
A vantagemde se usarTCP, emvez de criar nosso próprio protocolo de bytes, é que oTCPvaigarantir a entrega dos pacotes que transferirmos e criar um protocolo base para isto é algo bemcomplicado.
Acabamosdemencionarquediversoscomputadorespodemseconectaraumsó,mas,narealidade,émuito comum encontrarmáquinas clientes com uma só conexão física. Então, como é possível seconectaradoispontos?Comoépossívelserconectadopordiversospontos?
Todasasaplicaçõesqueestãoenviandoe recebendodados fazem issoatravésdamesmaconexãofísica, mas o computador consegue discernir, durante a chegada de novos dados, quais informaçõespertencemaqualaplicação.Mascomo?
19.3PORTA
264 19.3PORTA
AssimcomoexisteoIPparaidentificarumamáquina,aportaéasoluçãoparaidentificardiversasaplicaçõesemumamáquina.Estaportaéumnúmerode2bytes,variade0a65535.Setodasasportasdeumamáquinaestiveremocupadas,nãoépossívelseconectaraelaenquantonenhumaforliberada.
Ao configurar um servidor para rodar na porta 80 (padrão http), é possível se conectar a esseservidoratravésdessaportaque, juntocomo ip,vai formaroendereçodaaplicação.Porexemplo,oservidorwebdacaelum.com.brpodeserrepresentadopor:caelum.com.br:80
Masseumclienteseconectaaumprogramarodandonaporta80deumservidor,enquantoelenãosedesconectardessaporta,seráimpossívelqueoutrapessoaseconecte?
Acontece que, ao efetuar e aceitar a conexão, o servidor redireciona o cliente de uma porta paraoutra,liberandonovamentesuaportainicialepermitindoqueoutrosclientesseconectemnovamente.
EmJava,issodeveserfeitoatravésdethreadseoprocessodeaceitaraconexãodeveserrodadoomaisrápidopossível.
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
19.4SOCKET
Seuslivrosdetecnologiaparecemdoséculopassado?
19.4SOCKET 265
Iniciandoummodelodeservidordechat,oserviçodocomputadorquefuncionacomobasedeve,primeiro,abrirumaportaeficarouvindoatéalguémtentarseconectar.
importjava.net.*;
publicclassServidor{publicstaticvoidmain(String[]args)throwsIOException{
ServerSocketservidor=newServerSocket(12345);System.out.println("Porta12345aberta!");//acontinuaçãodoservidordeveserescritaaqui
}}
Seoobjetoforrealmentecriado,significaqueaporta12345estavafechadaefoiaberta.Seoutroprogramapossuiocontroledestaportanesteinstante,énormalqueonossoexemplonãofuncione,poiselenãoconsegueutilizarumaportaquejáestáemuso.
Após abrir a porta, precisamos esperar por um cliente através do método accept da
ServerSocket.Assimqueumclienteseconectar,oprogramacontinuará,porissodizemosqueesse
métodoéblocante,seguraathreadatéquealgoonotifique.
Socketcliente=servidor.accept();System.out.println("Novaconexãocomocliente"+cliente.getInetAddress().getHostAddress());//imprimeoipdocliente
Porfim,bastalertodasasinformaçõesqueoclientenosenviar:
Scannerscanner=newScanner(cliente.getInputStream());
while(scanner.hasNextLine()){System.out.println(scanner.nextLine());}
Fechamosasconexões,começandopelofluxo:
in.close();cliente.close();servidor.close();
Oresultadoéaclasseaseguir:
publicclassServidor{publicstaticvoidmain(String[]args)throwsIOException{ServerSocketservidor=newServerSocket(12345);System.out.println("Porta12345aberta!");
Socketcliente=servidor.accept();System.out.println("Novaconexãocomocliente"+cliente.getInetAddress().getHostAddress());
Scanners=newScanner(cliente.getInputStream());
19.5SERVIDOR
266 19.5SERVIDOR
while(s.hasNextLine()){System.out.println(s.nextLine());}
s.close();servidor.close();cliente.close();}}
Anossatarefaécriarumprogramaclientequeenviemensagensparaoservidor...oclienteéaindamaissimplesdoqueoservidor.
Ocódigo a seguir é aparteprincipal e tenta se conectar aum servidorno IP127.0.0.1 (máquinalocal)eporta12345:
Socketcliente=newSocket("127.0.0.1",12345);System.out.println("Oclienteseconectouaoservidor!");
Queremoslerosdadosdocliente,daentradapadrão(teclado):
Scannerteclado=newScanner(System.in);while(teclado.hasNextLine()){//lêalinhaefazalgocomela}
Bastaleraslinhasqueousuáriodigitaratravésdobufferdeentrada(in),ejogá-lasnobufferde
saída:
PrintStreamsaida=newPrintStream(cliente.getOutputStream());Scannerteclado=newScanner(System.in);while(teclado.hasNextLine()){saida.println(teclado.nextLine());}saida.close();teclado.close();
Reparequeusamososconceitodejava.io aqui novamente, para leitura do teclado e enviode
mensagensparaoservidor.ParaasclassesScannerePrintStream,tantofazdeondequeselêou
escreveosdados:oimportanteéqueessestreamsejaumInputStream/OutputStream.Éopoder
dasinterfaces,dopolimorfismo,aparecendonovamente.
Nossoprogramafinal:
publicclassCliente{publicstaticvoidmain(String[]args)throwsUnknownHostException,IOException{Socketcliente=newSocket("127.0.0.1",12345);System.out.println("Oclienteseconectouaoservidor!");
Scannerteclado=newScanner(System.in);PrintStreamsaida=newPrintStream(cliente.getOutputStream());
19.6CLIENTE
19.6CLIENTE 267
while(teclado.hasNextLine()){saida.println(teclado.nextLine());}
saida.close();teclado.close();cliente.close();}}
Paratestarosistema,precisamosrodarprimeirooservidore,logodepois,ocliente.Tudooquefordigitadonoclienteseráenviadoparaoservidor.
MULTITHREADING
Para que o servidor seja capaz de trabalhar comdois clientes aomesmo tempo é necessáriocriarumathreadlogoapósexecutarométodoaccept.
A threadcriadaserá responsávelpelo tratamentodessaconexão,enquantoo laçodoservidordisponibilizaráaportaparaumanovaconexão:
while(true){
Socketcliente=servidor.accept();
//criaumobjetoquevaitrataraconexãoTratamentoClasstratamento=newTratamentoClass(cliente);
//criaathreademcimadesteobjetoThreadt=newThread(tratamento);
//iniciaathreadt.start();
}
19.7IMAGEMGERAL
268 19.7IMAGEMGERAL
AsocketdoclientetemumInputStream,querecebedoOutputStreamdoservidor,e temum
OutputStream,quetransferetudoparaoInputStreamdoservidor.Muitoparecidocomumtelefone!
Reparequeclienteeservidorsãorótulosqueindicamumestado.Ummicro(oumelhor,umaJVM)podeserservidornumcaso,maspodeserclienteemoutrocaso.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
1. Crieumprojetosockets.
Vamosfazerumpequenosistemaemquetudoqueédigitadonomicroclienteacabaaparecendonomicroservidor.Istoé,apenasumacomunicaçãounidirecional.
CrieaclasseServidorcomovimosnessecapítulo.AbusedosrecursosdoEclipseparanãoterde
escrevermuito!
packagebr.com.caelum.chat;
importjava.io.IOException;importjava.net.ServerSocket;importjava.net.Socket;importjava.util.Scanner;
Agoraéamelhorhoradeaprenderalgonovo
19.8EXERCÍCIOS:SOCKETS
19.8EXERCÍCIOS:SOCKETS 269
publicclassServidor{publicstaticvoidmain(String[]args)throwsIOException{ServerSocketservidor=newServerSocket(12345);System.out.println("Porta12345aberta!");
Socketcliente=servidor.accept();System.out.println("Novaconexãocomocliente"+cliente.getInetAddress().getHostAddress());
Scannerentrada=newScanner(cliente.getInputStream());while(entrada.hasNextLine()){System.out.println(entrada.nextLine());}
entrada.close();servidor.close();}}
2. CrieaclasseClientecomovistaanteriormente:
packagebr.com.caelum.chat;
importjava.io.IOException;importjava.io.PrintStream;importjava.net.Socket;importjava.net.UnknownHostException;importjava.util.Scanner;
publicclassCliente{publicstaticvoidmain(String[]args)throwsUnknownHostException,IOException{Socketcliente=newSocket("127.0.0.1",12345);System.out.println("Oclienteseconectouaoservidor!");
Scannerteclado=newScanner(System.in);PrintStreamsaida=newPrintStream(cliente.getOutputStream());
while(teclado.hasNextLine()){saida.println(teclado.nextLine());}
saida.close();teclado.close();}}
Utilizedosquickfixesecontrolespaçoparaosimportseothrows.
3. Rode a classeServidor: repare no console doEclipse que o programa fica esperando.Rode a
classeCliente: a conexão deve ser feita e o Eclipse devemostrar os dois consoles para você
(existeumpequenoíconenaviewdeConsoleparavocêalternarentreeles).
Digitemensagensnoclienteevejaseelasaparecemcorretamentenoservidor.
4. Testeseuprogramacomumcolegadocurso,usandocomunicaçãoremotaentreasduasmáquinas.Combinementresiquemvairodaroclienteequemvairodaroservidor.Quemforrodarocliente
270 19.8EXERCÍCIOS:SOCKETS
deve editar o IP na classe para indicar o endereço da outramáquina (verifique também se estãoacessandoamesmaporta).
DESCOBRINDOOIPDAMÁQUINA
NoWindows,abraoconsoleedigiteipconfigparasaberqualéoseuIP.NoLinux(ounoBSD,Mac,Solaris),vánoconsoleedigiteifconfig.
5. (opcional)Esevocêquisesse,emvezdeenviartudooqueoclientedigitou,transferirumarquivotextodomicrodoclienteparaservidor?Seriadifícil?
Abusedopolimorfismo!Façaoclientelerdeumarquivochamadoarquivo.txt (crie-o!)efaça
comqueoservidorgravetudoquerecebenumarquivoquechamarecebido.txt.
Quandooservidoraceitaumclientecomachamadaaoaccept, ele poderia chamarnovamente
estemétodo para aceitar um novo cliente. E, se queremos aceitar vários clientes, simultâneos, bastachamaroacceptváriasvezesetratarcadaclienteemsuaprópriaThread(senãoométodoaccept
nãoseráinvocadonovamente!).
UmesboçodesoluçãoparaaclasseServidor:
ServerSocketservidor=newServerSocket(12345);
//servidorficaeternamenteaceitandoclientes...while(true){Socketcliente=servidor.accept();//disparaumaThreadquetrataesseclienteejáesperaopróximo}
[TODO:serialegalessasoluçãoparcialparaapenasessaparte!]
Agora que vários clientes podemmandar mensagens, gostaríamos que os clientes recebessem asmensagensenviadaspelasoutraspessoas.Aoinvésdoservidorsimplesmenteescreverasmensagensnoconsole,eledevemandarcadamensagemparatodososclientesconectados.
Precisamosmanterumalistadeclientesconectadose,quandochegarumamensagem(dequalquercliente),percorremosessalistaemandamosparatodos.
UseumListparaguardarosPrintStreamsdosclientes.Logodepoisqueoservidoraceitarum
19.9DESAFIO:MÚLTIPLOSCLIENTES
19.10DESAFIO:BROADCASTDASMENSAGENS
19.9DESAFIO:MÚLTIPLOSCLIENTES 271
cliente novo, crie umPrintStream usando o OutputStream dele e adicione na lista. E, quando
receberumamensagemnova,enviaparatodosnalista.
Umesboço:
Adicionandonalista:
while(true){Socketcliente=servidor.accept();this.lista.add(newPrintStream(cliente.getOutputStream()));
//disparaumaThreadquetrataesseclienteejáesperaopróximo}
Métodoquedistribuiasmensagens:
voiddistribuiMensagem(Stringmsg){for(PrintStreamcliente:lista){cliente.println(msg);}}
Masnossoclientetambémrecebemensagens.EntãoprecisamosfazercomqueoCliente,alémdelermensagensdo tecladoeenviarparaoservidor,simultaneamente tambémpossarecebermensagensdeoutrosclientesenviadaspeloservidor.
Ouseja,precisamosdeumasegundaThreadnaclasseClientequeficarecebendomensagensdo
InputStreamdoservidoreimprimindonoconsole.
Umesboço:
Scannerservidor=newScanner(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ãoprovavelmentevocêvaiterqueescrever4classes.
Melhoriaspossíveis:
Faça como a primeira linha enviada pelo cliente seja sempre o nick dele. E quando o servidorenviaramensagem,façaeleenviaronickdecadaclienteantesdamensagem.
Equandoumclientedesconectar?Comoretirá-lodalista?
É difícil fazer o envio de arquivos pelo nosso sistema de chats? Sabendo que a leitura de umarquivo é feita pelo FileInputStream , seria difícil mandar esse InputStream pelo
OutputStreamdaconexãoderede?
272 19.10DESAFIO:BROADCASTDASMENSAGENS
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Umasoluçãoparaosistemadechatcliente-servidorcommúltiplosclientespropostonosdesafiosacima. Repare que a solução não está nem um pouco elegante: o main já faz tudo, além de não
tratarmosasexceptions.OcódigovisaapenasmostrarousodeumaAPI.Éumapéssimapráticacolocartodaafuncionalidadedoseuprogramanomainetambémdejogarexceçõesparatrás.
Nestalistagem,faltamosdevidosimports.
Primeiro, as duas classes para o cliente. Repare que a única mudança grande é a classe nova,Recebedor:
publicclassCliente{publicstaticvoidmain(String[]args)throwsUnknownHostException,IOException{//disparaclientenewCliente("127.0.0.1",12345).executa();}
privateStringhost;privateintporta;
publicCliente(Stringhost,intporta){this.host=host;this.porta=porta;}
publicvoidexecuta()throwsUnknownHostException,IOException{Socketcliente=newSocket(this.host,this.porta);System.out.println("Oclienteseconectouaoservidor!");
//threadpararecebermensagensdoservidorRecebedorr=newRecebedor(cliente.getInputStream());newThread(r).start();
//lêmsgsdotecladoemandaproservidor
EditoraCasadoCódigocomlivrosdeumaformadiferente
19.11SOLUÇÃODOSISTEMADECHAT
19.11SOLUÇÃODOSISTEMADECHAT 273
Scannerteclado=newScanner(System.in);PrintStreamsaida=newPrintStream(cliente.getOutputStream());while(teclado.hasNextLine()){saida.println(teclado.nextLine());}
saida.close();teclado.close();cliente.close();}}
publicclassRecebedorimplementsRunnable{
privateInputStreamservidor;
publicRecebedor(InputStreamservidor){this.servidor=servidor;}
publicvoidrun(){//recebemsgsdoservidoreimprimenatelaScanners=newScanner(this.servidor);while(s.hasNextLine()){System.out.println(s.nextLine());}}}
JáoServidorsofreubastantemodificações.AclasseTrataClienteéaresponsávelporcuidarde
cadaclienteconectadonosistema:
publicclassServidor{
publicstaticvoidmain(String[]args)throwsIOException{//iniciaoservidornewServidor(12345).executa();}
privateintporta;privateList<PrintStream>clientes;
publicServidor(intporta){this.porta=porta;this.clientes=newArrayList<PrintStream>();}
publicvoidexecuta()throwsIOException{ServerSocketservidor=newServerSocket(this.porta);System.out.println("Porta12345aberta!");
while(true){//aceitaumclienteSocketcliente=servidor.accept();System.out.println("Novaconexãocomocliente"+cliente.getInetAddress().getHostAddress());
//adicionasaidadoclienteàlistaPrintStreamps=newPrintStream(cliente.getOutputStream());this.clientes.add(ps);
274 19.11SOLUÇÃODOSISTEMADECHAT
//criatratadordeclientenumanovathreadTrataClientetc=newTrataCliente(cliente.getInputStream(),this);newThread(tc).start();}
}
publicvoiddistribuiMensagem(Stringmsg){//enviamsgparatodomundofor(PrintStreamcliente:this.clientes){cliente.println(msg);}}}
publicclassTrataClienteimplementsRunnable{
privateInputStreamcliente;privateServidorservidor;
publicTrataCliente(InputStreamcliente,Servidorservidor){this.cliente=cliente;this.servidor=servidor;}
publicvoidrun(){//quandochegarumamsg,distribuipratodosScanners=newScanner(this.cliente);while(s.hasNextLine()){servidor.distribuiMensagem(s.nextLine());}s.close();}}
19.11SOLUÇÃODOSISTEMADECHAT 275
CAPÍTULO20
"Quempoucopensa,engana-semuito."--LeonardodaVinci
OusodeThreadscomeçaaficarinteressanteecomplicadoquandoprecisamoscompartilharobjetosentreváriasThreads.
Imagineaseguintesituação:temosumBancocommilhõesdeContasBancárias.Clientessacamedepositam dinheiro continuamente, 24 horas por dia.No primeiro dia de cadamês, oBanco precisaatualizar o saldo de todas as Contas de acordo com uma taxa específica. Para isso, ele utiliza oAtualizadorDeContasquevimosanteriormente.
OAtualizadorDeContas,basicamente,pegaumaaumacadaumadasmilhõesdecontasechama
seumétodoatualiza.Aatualizaçãodemilhõesdecontaséumprocessodemorado,quedurahoras;é
inviávelpararobancoportantotempoatéqueasatualizaçõestenhamcompletado.Éprecisoexecutarasatualizaçõesparalelamenteàsatividades,dedepósitosesaques,normaisdobanco.
Ouseja,teremosváriasthreadsrodandoparalelamente.Emumathread,pegamostodasascontasevamoschamandoométodoatualizadecadauma.Emoutra,podemosestarsacandooudepositando
dinheiro.Estamoscompartilhandoobjetosentremúltiplasthreads(ascontas,nonossocaso).
Imagineaseguintepossibilidade(mesmoquemuitoremota):noexatoinstanteemqueoatualizadorestáatualizandoumaContaX,oclientedonodestaContaresolveefetuarumsaque.Comosabemos,aotrabalhar comThreads, o escalonador podeparar uma certaThread a qualquer instante para executaroutra,evocênãotemcontrolesobreisso.
VejaessaclasseConta:
publicclassConta{
privatedoublesaldo;
//outrosmétodoseatributos...
publicvoidatualiza(doubletaxa){
APÊNDICE-PROBLEMASCOMCONCORRÊNCIA
20.1THREADSACESSANDODADOSCOMPARTILHADOS
276 20APÊNDICE-PROBLEMASCOMCONCORRÊNCIA
doublesaldoAtualizado=this.saldo*(1+taxa);this.saldo=saldoAtualizado;}
publicvoiddeposita(doublevalor){doublenovoSaldo=this.saldo+valor;this.saldo=novoSaldo;}}
ImagineumaContacomsaldode100reais.Umclienteentranaagênciaefazumdepósitode1000reais.IssodisparaumaThreadnobancoquechamaométododeposita();elecomeçacalculandoo
novoSaldo que passa a ser 1100 (linha 13). Só que por algum motivo que desconhecemos, o
escalonadorpáraessathread.
Nesteexatoinstante,elecomeçaaexecutarumaoutraThreadquechamaométodoatualiza da
mesmaConta,porexemplo,comtaxade1%. IssoquerdizerqueonovoSaldo passa a valer 101
reais(linha8).E,nesseinstanteoescalonadortrocadeThreadsnovamente.Eleexecutaalinha14naThreadquefaziaodepósito;osaldopassaavaler1100.Acabandoodeposita,oescalonadorvoltapraThreaddoatualizaeexecutaalinha9,fazendoosaldovaler101reais.
Resultado:odepósitodemilreaisfoitotalmenteignoradoeseuClienteficarápoucofelizcomisso.Percebaquenãoépossíveldetectaresseerro, jáque todoocódigo foiexecutadoperfeitamente, semproblemas.Oproblema,aqui,foioacessosimultâneodeduasThreadsaomesmoobjeto.
EoerrosóocorreuporqueoescalonadorparounossasThreadsnaquelesexatos lugares.Podeserquenossocódigofiquerodando1anosemdarproblemaalgumeemumbelodiaoescalonadorresolvealternar nossas Threads daquela forma. Não sabemos como o escalonador se comporta! Temos queprotegernossocódigocontraessetipodeproblema.Dizemosqueessaclassenãoéthreadsafe,issoé,nãoestáprontaparaterumainstânciautilizadaentreváriasthreadsconcorrentemente.
OquequeríamoseraquenãofossepossívelalguématualizaraContaenquantooutrapessoaestá
depositandoumdinheiro.QueríamosqueumaThreadnãopudessemexer emumaConta enquanto
outraThreadestámexendonela.Nãohácomoimpediroescalonadordefazertalescolha.Então,oquefazer?
20.1THREADSACESSANDODADOSCOMPARTILHADOS 277
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
Umaideiaseriacriarumatravae,nomomentoemqueumaThreadentrasseemumdessesmétodos,ela trancariaaentradacomumachave.Dessamaneira,mesmoquesendocolocadade lado,nenhumaoutraThreadpoderiaentrarnessesmétodos,poisachaveestariacomaoutraThread.
Essaideiaéchamadaderegiãocrítica.Éumpedaçodecódigoquedefinimoscomocríticoequenãopodeserexecutadoporduasthreadsaomesmotempo.Apenasumathreadporvezconsegueentraremalgumaregiãocrítica.
PodemosfazerissoemJava.Podemosusarqualquerobjetocomoumlock(trava,chave),parapodersincronizar emcimadesseobjeto, isto é, se umaThread entrar emumblocoque foi definido comosincronizadoporesse lock,apenasumaThreadpoderáestar ládentroaomesmo tempo,poisachaveestarácomela.
Apalavrachavesynchronizeddáessacaracterísticaaumblocodecódigoerecebequaléoobjeto
queseráusadocomochave.AchavesóédevolvidanomomentoemqueaThreadquetinhaessachavesair do bloco, seja por return ou disparo de uma exceção (ou ainda na utilização do método
wait())..
Queremos,então,bloquearoacessosimultâneoaumamesmaConta:
publicclassConta{
privatedoublesaldo;
//outrosmétodoseatributos...
publicvoidatualiza(doubletaxa){synchronized(this){doublesaldoAtualizado=this.saldo*(1+taxa);this.saldo=saldoAtualizado;
JáconheceoscursosonlineAlura?
20.2CONTROLANDOOACESSOCONCORRENTE
278 20.2CONTROLANDOOACESSOCONCORRENTE
}}
publicvoiddeposita(doublevalor){synchronized(this){doublenovoSaldo=this.saldo+valor;this.saldo=novoSaldo;}}}
Observeousodosblocossynchronized dentrodosdoismétodos.Eles bloqueiamumaThread
utilizandoomesmoobjetoConta,othis.
Essesmétodossãomutuamenteexclusivosesóexecutamdemaneiraatômica.Threadsquetentampegarumlockquejáestápego,ficarãoemumconjuntoespecialesperandopelaliberaçãodolock(nãonecessariamentenumafila).
SINCRONIZANDOOBLOCOINTEIRO
Écomumsempresincronizarmosummétodointeiro,normalmenteutilizandoothis.
publicvoidmetodo(){synchronized(this){//conteúdodometodo}}
Para estemesmo efeito, existe uma sintaxemais simples, onde o synchronized pode ser
usadocomomodificadordométodo:
publicsynchronizedvoidmetodo(){//conteúdodometodo}
MAISSOBRELOCKS,MONITORESECONCORRÊNCIA
Se ométodo for estático, será sincronizado usando o lock do objeto que representa a classe(NomeDaClasse.class).
Alémdisso,opacotejava.util.concurrent,conhecidocomoJUC,entrounoJava5.0parafacilitarumasériedetrabalhoscomunsquecostumamapareceremumaaplicaçãoconcorrente.
Essepacoteajudaatémesmocriarthreadsepooldethreads,atravésdosExecutors.
20.2CONTROLANDOOACESSOCONCORRENTE 279
Duas collectionsmuito famosas são Vector e Hashtable, a diferença delas com suas irmãs
ArrayListeHashMapéqueasprimeirassãothreadsafe.
Vocêpodeseperguntarporquenãousamossempreessasclassesthreadsafe.Adquirirumlocktemumcusto,ecasoumobjetonãováserusadoentrediferentesthreads,nãoháporqueusaressasclassesqueconsomemmaisrecursos.Masnemsempreéfácilenxergarsedevemossincronizarumbloco,ousedevemosutilizarblocossincronizados.
Antigamenteocustodeseusarlockseraaltíssimo,hojeemdiaissocustapoucoparaaJVM,masnãoémotivoparavocêsincronizartudosemnecessidade.
Você pode mudar a prioridade de cada uma de suas Threads, mas isto também é apenas umasugestãoaoescalonador.
ExisteummétodostopnasThreads,porquenãoéboapráticachamá-lo?
Umtópicomaisavançadoéautilizaçãodewait,notifiyenotifyAllparaqueasThreads
comuniquem-sedeeventosocorridos,indicandoquepodemounãopodemavançardeacordocomcondições
O pacote java.util.concurrent foi adicionado no Java 5 para facilitar o trabalho na
programaçãoconcorrente.Elepossuiumasériedeprimitivasparaquevocênãotenhadetrabalhardiretamentecomwaitenotify,alémdeterdiversascoleçõesthreadsafe.
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoJavaeOrientaçãoaObjetos
20.3VECTOREHASHTABLE
20.4UMPOUCOMAIS...
VocêpodetambémfazerocursodatadessaapostilanaCaelum
20.5EXERCÍCIOSAVANÇADOSDEPROGRAMAÇÃOCONCORRENTE
280 20.3VECTOREHASHTABLE
Exercícios só recomendados se você já tinha algum conhecimento prévio de programaçãoconcorrente,locks,etc.
1. Vamos enxergar o problema ao se usar uma classe que não é thread-safe: a ArrayList por
exemplo.
Imaginequetemosumobjetoqueguardatodasasmensagensqueumaaplicaçãodechatrecebeu.Vamosusar umaArrayList<String> para armazená-las.Nossa aplicação émulti-thread, então
diferentesthreadsvãoinserirdiferentesmensagensparaseremregistradas.Nãoimportaaordemqueelassejamguardadas,desdequeelasumdiasejam!
Vamosusaraseguinteclasseparaadicionarasqueries:
publicclassProduzMensagensimplementsRunnable{privateintcomeco;privateintfim;privateCollection<String>mensagens;
publicProduzMensagens(intcomeco,intfim,Collection<String>mensagens){this.comeco=comeco;this.fim=fim;this.mensagens=mensagens;}
publicvoidrun(){for(inti=comeco;i<fim;i++){mensagens.add("Mensagem"+i);}}}
Vamos criar três threads que rodem esse código, todas adicionando as mensagens na mesmaArrayList.Emoutraspalavras,teremosthreadscompartilhandoeacessandoummesmoobjeto:é
aquiquemoraoperigo.
publicclassRegistroDeMensagens{
publicstaticvoidmain(String[]args)throwsInterruptedException{Collection<String>mensagens=newArrayList<String>();
Threadt1=newThread(newProduzMensagens(0,10000,mensagens));Threadt2=newThread(newProduzMensagens(10000,20000,mensagens));Threadt3=newThread(newProduzMensagens(20000,30000,mensagens));
t1.start();t2.start();t3.start();
//fazcomqueathreadquerodaomainaguardeofimdessast1.join();t2.join();t3.join();
ELOCKS
20.5EXERCÍCIOSAVANÇADOSDEPROGRAMAÇÃOCONCORRENTEELOCKS 281
System.out.println("Threadsprodutorasdemensagensfinalizadas!");
//verificasetodasasmensagensforamguardadasfor(inti=0;i<15000;i++){if(!mensagens.contains("Mensagem"+i)){thrownewIllegalStateException("nãoencontreiamensagem:"+i);}}
//verificasealgumamensagemficounulaif(mensagens.contains(null)){thrownewIllegalStateException("nãodeviaternullaquidentro!");}
System.out.println("Fimdaexecucaocomsucesso");}}
Rodealgumasvezes.Oqueacontece?
2. Testeocódigoanterior,masusandosynchronizedaoadicionarnacoleção:
publicvoidrun(){for(inti=comeco;i<fim;i++){synchronized(mensagens){mensagens.add("Mensagem"+i);}}}
3. SemusarosynchronizedtestecomaclasseVector,queéumaCollectioneéthread-safe.
Oquemudou?OlheocódigodométodoaddnaclasseVector.Oquetemdediferentenele?
4. Novamentesemusarosynchronized,testeusarHashSeteLinkedList,emvezdeVector.
Façaváriostestes,poisasthreadsvãoseentrelaçarcadavezdeumamaneiradiferente,podendoounãoterumefeitoinesperado.
NocapítulodeSocketsusaremosthreadsparasolucionarumproblemarealdeexecuçõesparalelas.
282 20.5EXERCÍCIOSAVANÇADOSDEPROGRAMAÇÃOCONCORRENTEELOCKS
CAPÍTULO21
"Quempoucopensa,engana-semuito."--LeonardodaVinci
Comovimos antes, aVMé apenasumaespecificaçãoedevemosbaixaruma implementação.HámuitasempresasqueimplementamumaVM,comoaprópriaOracle,aIBM,aApacheeoutros.
AdaOracleé amaisusadaepossuiversõesparaWindows,LinuxeSolaris.VocêpodebaixaroSDKacessando:
http://www.oracle.com/technetwork/java/
NestapáginadaOracle,vocêdeveescolheroJavaSE,dentrodostopdownloads.Depois,escolhaoJDKeseusistemaoperacional.
CadadistribuiçãoLinuxtemsuaprópriaformadeinstalação.AlgumasjátrazemoJavajunto,outraspossibilitamquevocêinstalepelosrepositóriosoficiaiseemalgunscasosvocêprecisabaixardiretodaOracleeconfigurartudomanualmente.
NoUbuntu,adistribuiçãousadanaCaelum,ainstalaçãoébastantesimples.Bastairnoterminaledigitar:
sudoadd-apt-repositoryppa:webupd8team/javasudoapt-getupdatesudoapt-getinstalloracle-java8-installer
Casoprefirautilizaroopenjdk,adistribuiçãoopensource,bastafazer
sudoapt-getinstallopenjdk-7-jdk
Porenquantoelepossuiapenasaversão7.Nolinuxfedora,vocêfariacomsu-c"yuminstall
java-1.7.0-openjdk".
SevocêjátiveroutrasversõesinstaladasnoseuUbuntu,podeutilizarsudoupdate-alternatives
--configjavaparaescolherentreelas.
Umainstalaçãomaisbraçal,semusarrepositório ,podeserfeitabaixandooinstaladornoprópriosite daOracle. É umtar.gz que possui um.bin que deve ser executado. Depois, é necessário
APÊNDICE-INSTALAÇÃODOJAVA
21.1INSTALANDONOUBUNTUEEMOUTROSLINUX
21APÊNDICE-INSTALAÇÃODOJAVA 283
apontarJAVA_HOMEparaessediretórioeadicionarJAVA_HOME/binnoseuPATH.
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
OMacOSXjátrazoJavainstaladojuntocomosistemaoperacionalatéaversão10.6.Asversõesmaisnovas,doLionemdiante,o instaladordoMacvaiperguntarsevocêdesejabaixá-loquandoforrodarsuaprimeiraaplicaçãoJava,comooEclipse.
AversãoparaoJava8podeserbaixadanomesmosite:
http://www.oracle.com/technetwork/java/
Para instalar o JDK no Windows, primeiro baixe-o no site da Oracle. É um simples arquivoexecutávelquecontémoWizarddeinstalação:
http://www.oracle.com/technetwork/java/
Seuslivrosdetecnologiaparecemdoséculopassado?
21.2NOMACOSX
21.3INSTALAÇÃODOJDKEMAMBIENTEWINDOWS
284 21.2NOMACOSX
Dêumcliqueduplonoarquivojdk-<versão>-windows-i586-p.exeeespereatéeleentrarno
wizarddeinstalação.
Aceite os próximos dois passos clicando em Next. Após um tempo, o instalador pedirá paraescolheremquediretórioinstalaroSDK.Podeserondeelejáoferececomopadrão.Anotequalfoiodiretórioescolhido,vamosutilizaressecaminhomaisadiante.Acópiadearquivosiniciará:
Instalação
21.3INSTALAÇÃODOJDKEMAMBIENTEWINDOWS 285
Oinstalador instalará tambémo JavaFX2.Após isso,você serádirecionadoàumapáginaondevocêpode,opcionalmente,criarumacontanaOraclepararegistrarsuainstalação.
Precisamosconfiguraralgumasvariáveisdeambienteapósainstalação,paraqueocompiladorsejaacessívelvia linhade comando.CasovocêváutilizardiretamenteoEclipse, provavelmentenão seránecessáriorealizaressespassos.
CliquecomobotãodireitoemcimadoíconeComputadoreselecioneaopçãoPropriedades.
Escolha a aba "Configurações Avançadas de Sistema" e depois clique no botão "Variáveis deAmbiente"
Configurandooambiente
286 21.3INSTALAÇÃODOJDKEMAMBIENTEWINDOWS
Nestatela,vocêverá,napartedecima,asvariáveisdeambientedousuáriocorrentee,embaixo,asvariáveisdeambientedocomputador(servemparatodososusuários).CliquenobotãoNovo...dapartedebaixo.
EmNome da Variável digite JAVA_HOME e, em valor da variável, digite o caminho que você
utilizou na instalação do Java. Provavelmente será algo como: C:\Program
Files\Java\jdk1.8.0_03:
CliqueemOk.
Nãovamoscriaroutravariável,massimalterar.Paraisso,procureavariávelPATH,ouPath(dá
21.3INSTALAÇÃODOJDKEMAMBIENTEWINDOWS 287
nomesmo),ecliquenobotãodebaixo"Editar".
Nãoaltereonomedavariável!Deixecomoestáeadicionenofinaldovalor;%JAVA_HOME%\bin,
não esqueça do ponto-e-vírgula - assim, você está adicionandomais umcaminho à sua variávelPath.
Abraoprompt,indoemIniciar,Executaredigitecmd.
No console, digite javac-version. O comando deve mostrar a versão do Java Compiler e
algumasopções.
VocêpodeseguirparaainstalaçãodoEclipse,conformevistonoseucapítulo,ouutilizarumeditordetextosimplescomooblocodenotasparaosprimeiroscapítulosdeapostila.
Qualquerdúvida,nãohesitedepostá-lanoGrupodeUsuáriosJava:
http://www.guj.com.br.
288 21.3INSTALAÇÃODOJDKEMAMBIENTEWINDOWS
CAPÍTULO22
"Olhoporolho,eomundoacabarácego."--MohandasGandhi
Debugging(emportuguês,depuraçãooudepurar)éumprocessodereduzirouencontrarbugsnoseusistema. De uma forma geral, debugging não é uma tarefa fácil de ser executada.Muitas variaçõespodem atrapalhar esse processo, por exemplo, a linguagem que estamos utilizando e ferramentasdisponíveisparafazermosdebuggingdeumcódigo.
OJavaemsifacilitamuitonesteprocesso,poisnosfornecemaneirasdesabermosseocódigoestáerrado, por exemplo as exceptions. Em linguagens de baixo nível saber onde o bug estava eraextremamentecomplicado.Oquetambémfacilitanossotrabalhosãoasferramentasdedebug.Veremosqueelassãonecessáriasnoscasosquenossostestesdeunidadedeloggingnãoforamsuficientesparaencontrararazãodeumproblema.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
No curso utilizamos o Eclipse como IDE para desenvolvermos nosso código. Como foi ditoferramentasdedebuggingfacilitammuitonossotrabalho,oEclipseéumadasIDEsmaispoderosasdomercadoenosforneceumaferramentaquetornaoprocessoextremamentesimples.
APÊNDICE-DEBUGGING
22.1OQUEÉDEBUGAR
Agoraéamelhorhoradeaprenderalgonovo
22.2DEBUGANDONOECLIPSE
22APÊNDICE-DEBUGGING 289
O primeiro recurso que temos que conhecer quando começamos a debugar no Eclipse são osbreakpoints. Eles são pontos de partida em nosso código para iniciarmos o processo de debug. Porexemplo, no código abaixo, imagine que desejamos debugar o comportamento dométodosaca da
classeConta,maisespecificamentedoifqueverifica se saldoémenorqueovalora ser sacado.
Colocaríamosobreakpointexatamentenalinhaif(this.saldo<valor){:
publicclassConta{
privatedoublesaldo;
publicbooleansaca(doublevalor){if(this.saldo<valor){returnfalse;}else{this.saldo=this.saldo-valor;returntrue;}}}
Mascomofaçoisso?Muitosimples,bastaclicarnalinhaquedesejaadicionarobreakpoint,depoisclicarnomenuRun->ToogleBreakpoint.
Esseéotipomaisclássicodebreakpoint,veremosalgunsoutrosaolongodocapítulo.
Agora que já adicionamos o breakpoint que é o ponto de partida, vamos debugar nosso código.Precisamosrodarnossocódigo,ouseja,chamarométodosacaparaqueobreakpointsejaencontrado.
Teremosumcódigosimilaraoseguinte:
publicclassTestaConta{
290 22.2DEBUGANDONOECLIPSE
publicstaticvoidmain(String[]args){Contaconta=newConta();conta.saca(200);}}
O processo normal para executarmos esse código seria clicar no menuRun -> Run As -> JavaApplication. Porém para rodar o nosso código emmododebug e ativar nosso breakpoint, devemosrodarocodigonomenuRun->DebugAs->JavaApplication.Quandoumbreakpointforencontradonocódigoqueestásendoexecutado,oeclipseexibiráumaperspectivaespecíficadedebug,apontandoparaalinhaquetemobreakpoint.
Temos várias informações disponíveis nessa perspectiva, algumas são essenciais e básicas paratrabalharmos com debug no nosso dia-a-dia, outras não tão relevantes e só usamos em casosmuitoespecíficos.
Dentro da perspectiva de debug, temos uma aba chamada Variables. São exibidas todas as
variáveisencontradasdentrodocódigoquevocêestádebugando.Porexemplo,nodebugquefizemosserãoexibidasasvariáveisdométodosaca,nestecaso,valor.Alémdosatributosde instânciado
objeto.
22.3PERSPECTIVADEDEBUG
22.3PERSPECTIVADEDEBUG 291
Podemosexibirmaisinformaçõessobreasvariáveis,bastaadicionarmosascolunasquedesejamosnatabelaexibida.
Épossíveltambémadicionarmosconstantesevariáveisestáticasdaclassequeestásendodebugada.
NaabaBreakpoints sãoexibidos todososbreakpointsqueseuworkspacepossui.Masporque
isso é importante? É importante porque podemos ver todos os pontos de debug presentes e melhor,podemosdesabilitá-losumaumoutodosdeumasóvez.Vocêpodeatémesmopedirparaexportarosbreakpoints.
Paradesabilitarouhabilitar todosbreakpointsbastaclicarmosno íconeSkipAllBreakpoints. Sequisermosdesabilitarumaum,bastadesmarcarocheckboxeobreakpointserádesativado.Àsvezes,encontrarocódigoondeobreakpointfoicolocadopodesercomplicado,naabaBreakpointsissofica
bemfácildefazer,bastadarumduplocliquenobreakpointeoeclipseautomaticamentenosmostraaclasse"dona"dele.
Quandoestamosdebugandocódigo,muitasvezeséinteressantesaberovalordealgumaexpressãooumétodo.Porexemplo,umacondiçãodentrodeumif,this.saldo>valor.Essevalornãoestáem
292 22.3PERSPECTIVADEDEBUG
umavariável,eleestáemumaexpressão,oquepodetornarsaberovalordelacomplicado.Afeaturede Expressions descomplica esse processo para nós. Na perspectiva de Debug temos a aba
Expressions.Bastaclicarcomodireitodentrodaaba,eclicaremAddExpression:
Eoresultadodaexpressãoéexibido.
TemosoutraabaimportantechamadadeDebug.Dentreasfunçõesdelaestão:
Threads -Exibe as threads que estão sendo executadas, emelhor,mostra qual thread efetuou achamada para ométodo onde está o debug.Além dissomostra a pilha de execução, o que nospermitevoltarachamadadeummétodoBarradenavegação-Quepermitealterarmososcaminhosqueodebugseguirá.
Alistaaseguirmostraralgumasteclasebotõesquealteramocaminhonaturaldosnosssdebug:
F5-Vaiparaopróximopassodoseuprograma.Seopróximopassoforummétodo,eleentraránocódigoassociado;F6-Tambémvaiparaopróximopasso,porémseopróximopassoforummétodo,elenãoentraránocódigoassociado;F7-Voltaráemostraráométodoquefezachamadaparaocódigoqueestásendodebugado.NonossocasovoltaráparaométodomaindaclasseTestaConta;
22.3PERSPECTIVADEDEBUG 293
F8 -Vaiparaopróximobreakpoint,senenhumforencontrado,oprogramaseguiráseufluxodeexecuçãonormal.
VocêtambémpodeusarosbotõesqueestãopresentesnaabaDebug.
Depoisquecolocamosumbreakpointemalgumpontodonossocódigo,podemoscolocaralgumaspropriedadesnele,porexemplo,usaralgumacondiçãopararestringirquandoobreakpointseráativadoemtempodeexecução.PodemosrestringirnapropriedadeHitCountqueobreakpointsóseráativadoquandoalinhaemqueeleencontra-seforexecutada'X'vezes.
Como na imagem acima o breakpoint só será ativado quando a linha de código em que ele seencontraforexecutada'2'vezes.Podemostambémcolocaralgumaexpressãocondicional,umif,por
22.4DEBUGAVANÇADO
294 22.4DEBUGAVANÇADO
exemplo.
O breakpoint, neste caso, somente será ativado quando o argumentovalor que foi passado ao
métodosacaformaiorque100.Oimportanteaquiénotarmosquedevemosretornarsempreumvalorbooleano,senãoofizermos,teremosumerroemtempodeexecução.EssapropriedadeéválidaquandoqueremoscolocaraquelesfamososSystem.out.println("entrounoiftal")paraefeitode log,
podemosfazerissocolocandoologdentrodaexpressãocondicionalnaspropriedadesdobreakpoint.
O display é uma das partes mais interessantes do debug do eclipse, ele provê uma maneira deexecutarmos 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 poderutilizarasvariáveis,métodos,constantesdaclassequeestamosdebugando.
Umexemploclássicoéquandoestamosemdebuggingequeremossaberoretornodealgummétododoqualnãotemosacesso,oquefaríamosantesseriacolocarumamontoadodeSystem.out.println,
poluindoextremamentenossocódigo.Nodisplayoque fazemosé efetuar a chamadadessecódigoeautomaticamenteosresultadossãoexibidos.
Para vermos um efeito real disso, vamos alterar umpouco o comportamento da classeConta, demodoqueagoraosaldoparasaquetenhaqueserosaldorealmaisovalordolimite.Nossocódigoficaassim:
publicclassConta{
22.4DEBUGAVANÇADO 295
privatedoublesaldoReal;privatedoublelimite;
publicConta(doublelimite){this.limite=limite;}
publicbooleansaca(doublevalor){if(!isSaldoSuficiente(valor)){returnfalse;}else{this.saldoReal=this.saldoReal-valor;returntrue;}}
privatebooleanisSaldoSuficiente(doublevalor){return(this.saldoReal+this.limite)>valor;}}
Reparequeoifqueverificaseosaldoésuficienteparaefetuarmososaquechamaummétodo
isSaldoSuficiente,oquepodeserumproblemaquandoestamosdebugando,afinalacondiçãodo
iféummétodo.SeutilizarmosodisplaypodemosfazerachamadadométodoisSaldoSuficiente,
verseuresultadoeomelhor,nãoafetamosodebug,apenasqueremosveroresultadodométodo,porexemplo.
ParaexibirmosaabaDisplayébemsimples.TecleCtrl+3,digiteDisplay e aaba seráexibida.Quandorodarmosnossocódigoemmododebug,podemosirnodisplay,digitarmosumachamadaparaométodo isSaldoSuficiente, executamos esse código que foi digitado selecionando-o dentro do
displayeteclandoCtrl+Shift+Deoresultadoseráimpresso,assimcomonaimagemabaixo:
Muitasvezesqueremos"seguir"algumavariáveldeinstância,ouseja,qualquerchamadaparaessavariável(leituraouescrita)queremossernotificadosdisso.Podemosusarowatchpoint,quefaránossoprogramaentraremmododebug,quandoqualqueralteraçãonavariávelqueestamosseguindoocorrer,oprogramaentraráemdebugexatamentena linhaquefezaalteração.Paracolocarmosumwatchpoint,bastadarumduplocliquenoatributodeinstânciaquedesejacolocá-lo.
296 22.4DEBUGAVANÇADO
Épossívelalteraressecomportamentopadrão,edefinirsevocêquerqueowatchpointsejaativadoparaleituraousomenteparaescrita.
A idéiadesse tipodebreakpointé fazernossoprogramaentraremdebugquandoalgumaexceçãoespecífica ocorrer. Quando definirmos essa exceção no Exception Breakpoint e a mesma ocorrer,automaticamente nosso programa entra em debug na linha que gerou aquela exceção. Por exemplo,vamosalterarocodigodaclasseTestaContaparaqueamesmatenhaumaNullPointerException:
22.4DEBUGAVANÇADO 297
publicclassTestaConta{publicstaticvoidmain(String[]args){Contaconta=null;conta.saca(10);}}
Quando rodarmos o código acima, teremos uma NullPointerException. Pode ser útil nesses
casosdebugaresaberondeaexceçãoestáocorrendodefato,emquallinhamaisespecificamente.Parafazermos isso podemos criar um Exception Breakpoint, que debugará códigos que eventualmentelancemumaNullPointerException,porexemplo.BastaabrirmosaabaBreakpointseclicarmosnoíconeabaixo:
Seráabertaumajanelaondepodemosbuscarporumaexceçãoespecífica.
Podemosdefinir umbreakpoint que é ativadoou antes oudepois queométodo é chamado.Paradefinirmosele,bastaestaremqualquerpartedométodoquedesejamosdebugar,clicarnomenuRun->
298 22.4DEBUGAVANÇADO
ToogleMethodBreakpoint.Podemoseditaraspropriedadesdessebreakpointdizendosequeremosqueele seja ativado antes(default) ou depois da execução do método. Basta acessar as propriedades domethodbreakpointealterá-las.
Éutilquandodesejamosqueumbreakpointsejaativadoquandoumaclasseespecíficaforcarregadapelaprimeiravez,chamamosessebreakpointdeClassBreakpoint.BastaclicarmosnomenuRun ->Add Class Load Breakpoint, uma janela será aberta e basta digitarmos o nome da classe eadicionarmos:
22.4DEBUGAVANÇADO 299
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Um dos principais hábitos que nós desenvolvedores devemos evitar é a questão da otimizaçãoprematura,ouseja,quandodesenvolvemosumaaplicaçãoparaumcliente,devemosnospreocuparematenderorequisitosfuncionaisdemaneiramaisrápidaemaissimplespossível.Opassoseguinteérefatorar seu código para que ele sejamelhorado e para que no futuro possa se adaptar as possíveismudanças.
Aregraé:"Deixeosproblemasdofuturo,paraseremresolvidosnofuturo".
EditoraCasadoCódigocomlivrosdeumaformadiferente
22.5PROFILING
300 22.5PROFILING
Umadas ferramentasquenosauxiliamnaquestãodenãootimizarnossocódigoprematuramente,sãoas ferramentasdeprofiling,que tornamaparentes,porexemplo,osproblemasdememóriaecpu,quepodemfazercomqueotimizemosnossocódigo.Atualmentedevidoastécnicasqueutilizamosparaentregaralgodevalorparaocliente,focamosprincipalmentenaqualidade,aspectosfuncionais,testes,etc.Porém,muitosproblemasquenão fazempartedos requisitos funcionaispodemacontecer apenasquandoaaplicaçãoestáemprodução,nestepontoasferramentasdeprofilingtambémnosajudam.
JuntamentecomoEclipsetemosaopçãodeinstalareutilizarumaferramentadeprofilingconhecidacomoEclipseTPTP(EclipseTest&PerformanceToolsPlatform),quenosforneceopçõesparaisolareidentificarproblemasdeperformance,taiscomo:memória(memoryleak),recursoseprocessamento.OTPTPnospermiteanalisardesimplesaplicaçõesjavaatéaplicaçõesquerodamemmúltiplasmáquinaseemmúltiplasplataformas.
ALTERNATIVASAOTPTP
Existem algumas alternativas ao TPTP, os mais conhecidos são Netbeans Profiler(http://profiler.netbeans.org/) que é gratuito, e o JProfiler (http://www.ej-technologies.com/products/jprofiler/overview.html)queépago.
O TPTP não vem por padrão junto com o Eclipse. Portanto, para utilizarmos é necessário ainstalaçãodomesmo.Podemosfazeroprocessodeinstalaçãodeduasmaneiras.AprimeiraemaisfáciléutilizandooUpdateSitedoEclipsequeresolveaspossíveisdependênciasenospossibilitaescolherquaisfeaturesqueremosinstalar.ParainstalaroTPTPatravésdesserecurso,bastairnomenu:Help->InstallNewSoftware,umajanelaseráaberta,bastaclicaremAdd...epreenchê-laconformeaimagemaseguir:
Basta adicionar as ferramentas do TPTP em nosso eclipse, para isto, selecione o repositório que
22.6PROFILINGNOECLIPSETPTP
22.6PROFILINGNOECLIPSETPTP 301
acabamosdeadicionareaversãodoTPTPquequeremosinstalar,nestecaso,aversão4.6.2.
INSTALANDOPELOZIP
VocêtemaopçãodeinstalaroTPTPbaixandoozipdoprojetoecolocandomanualmentenodiretó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
Umproblemaquepodeaconteceremaplicaçõesequemuitaspessoasnãoconhecemafundo,éaquestãodopooldeStringsquepodeeventualmenteficarmuitogrande.EsteproblemapodesercausadoporqueobjetosdotipoStringsãoimutáveis,sendoassim,sefizermosconcatenaçõesdeStringsmuitasvezes,cadaumadessasconcatenaçõesproduziráumanovaString,queautomaticamenteserácolocadanopooldaJVM.
A alternativa neste caso, seria trabalhar com objetos do tipo StringBuilder ou StringBuffer que
302 22.6PROFILINGNOECLIPSETPTP
funcionam como Strings,mas que não produzem Strings novas em caso de uma concatenação.MascomomedirotamanhodonossopooldeString?
O TPTP possui uma aba de estatísticas que nosmostra o tempo que ummétodo levou para serexecutado,quantoprocessamentoessemétodogastou,quantodememóriafoigastocomcadamétodo.VamosanalisaralgumasdessasestatísticascriandoumcódigoqueconcateneváriasStrings,demaneiraquesobrecarregueopool,gerebastanteprocessamentoeconsumodememória.
publicclassTeste{
publicstaticvoidmain(String[]args){for(inti=0;i<1000000;i++){Stringx="a"+i;System.out.println(x);}}
}
Paraanalisarmosoresultadodocódigo,vamosrodarocódigodomainatravésdomenuRun->
ProfileAs->JavaApplication.
VERSÕES
Infelizmente o TPTP funciona somente no Windows. Versões para MacOS e Linux sãoprometidas, mas até hoje estão em desenvolvimento. Uma alternativa paga para esses outrossistemasoperacionaiséoJProfiler.
22.6PROFILINGNOECLIPSETPTP 303