J AVA francisco calaça otávio calaça Guia para iniciantes 2013 – Versão 1.2-beta LICENÇA Esta apostila é disponibilizada sob os termos da licença Creative Commons - AttributionNonCommercial-NoDerivs 3.0 Unported. Isto quer dizer que VOCÊ PODE: • Copiar este material de forma não comercial; • Redistribuir este material de forma não comercial; • Imprimir este material de forma não comercial; Esta licença também quer dizer que você VOCÊ NÃO PODE: • Vender este material a terceiros; • Alterar este material; Qualquer uso indevido deste material, venda ou alteração estarão sugeitos às penas previstas na Lei Federal No 9.610, de 19 de fevereiro 1998. Mais detalhes sobre esta licença bem como seu conteúdo original pode ser acessado em: http://creativecommons.org/licenses/by-nc-nd/3.0/legalcode Bons estudos. . . iii C O L A B O R E C O M E S TA A P O S T I L A Precisamos de colaboradores para melhorar esta apostila. Se você deseja entrar para nosso time, mande um email para [email protected] com o título: DESEJO COLABORAR COM A APOSTILA DE JAVA. Responderemos a você com informações sobre o que ainda é necessário fazer. Nas próximas versões, você verá seu nome adicionado na lista de colaboradores e poderá se gabar, mostrando isto ao seus amigos. Colabore ! Colaboradores • Francisco Calaça Xavier • Otávio Calaça Xavier • Edicarlos Pimenta Gonçalves • Deuslirio Junior v CONTEÚDO 1 introdução 1 1.1 Algoritmos 1 1.2 Lógica binária 1 1.3 Nascimento da ciência da computação 2 1.4 Java 2 2 preparação do ambiente de estudos 5 2.1 Padronização do ambiente de trabalho 5 2.2 Primeiros testes no ambiente de trabalho 6 2.3 Exercícios 7 3 lógica de programação em java 9 3.1 Fluxograma 9 3.2 Para entender os programas criados a partir de agora 3.2.1 Informações iniciais 10 3.3 Strings 11 3.4 Saída Formatada 12 3.5 Conceito de Variável 13 3.6 Palavras reservadas e identificadores 14 3.7 Tipos Primitivos 15 3.7.1 Tipos primitivos inteiros 15 3.7.2 Tipos primitivos de ponto flutuante 15 3.7.3 Tipo primitivo char 16 3.7.4 Tipo primitivo boolean 16 3.7.5 Conversões de variáveis 17 3.8 Operadores 17 3.8.1 Aritméticos 17 3.8.2 Atribuição 18 3.8.3 Incremento/Decremento 19 3.8.4 Relacionais 20 3.8.5 Lógicos 20 3.9 Estruturas de seleção 22 3.9.1 if . . . else 22 3.9.2 Operador condicional ou ternário 24 3.9.3 switch 25 3.10 Estruturas de Repetição 26 3.10.1 for 26 3.10.2 while 27 3.10.3 do . . . while 28 3.11 Exercícios 28 4 introdução à orientação a objetos 31 4.1 O conceitos Classe e Objeto 31 4.2 Elementos de uma classe 32 10 vii Versão 1.2-beta 4.2.1 Atributos 32 4.2.2 Métodos 33 4.2.3 Métodos construtores 34 4.2.4 Padrões de nomenclatura 35 4.3 Atributos e métodos static 36 4.3.1 Import static 37 4.4 Tipos Wrapper 38 4.4.1 Auto-boxing e Auto-unboxing 38 4.5 Regras de escopo 39 4.6 Sobrecarga de métodos 40 4.7 Exercícios 41 5 arrays 43 5.1 O que são arrays 43 5.2 Declaração e inicialização de arrays 44 5.3 Método main 46 5.4 Laço for aprimorado 48 5.5 Passagem de parâmetros no Java 48 5.6 Arrays multidimensionais 51 5.7 Lista de parâmetros com comprimento variável 51 5.8 Exercícios 52 6 um pouco mais de orientação a objetos 53 6.1 Coletor de lixo 53 6.2 A palavra-chave this 54 6.3 Variáveis do tipo final 56 6.4 Encapsulamento 56 6.5 Enumerações 59 6.6 Pacotes 59 6.6.1 Como usar tipos dentro de outros pacotes 61 6.7 Herança 62 6.7.1 Um exemplo de Herança 62 6.7.2 Sobrescrita de métodos 64 6.7.3 A palavra-chave super 64 6.8 Alguns Modificadores de acesso 64 6.8.1 private 64 6.8.2 pacote 64 6.8.3 protected 65 6.8.4 public 65 6.9 Classe object 65 6.9.1 método equals() 65 6.9.2 método toString() 66 6.10 Polimorfismo 67 6.10.1 Abstração 67 6.10.2 Exemplo de Polimorfismo 68 6.11 Conversão e casting 71 6.11.1 A palavra-chave instanceof 72 6.12 Métodos e classe do tipo final 72 viii conteúdo http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 7 8 9 10 11 conteúdo 6.13 Interfaces 73 6.13.1 Interfaces em Java 73 6.14 Exercícios 75 tratamento de exceções 77 7.1 O que são exceções 77 7.2 Como tratar exceções 77 7.2.1 O bloco try 77 7.2.2 O bloco catch 78 7.3 Exceções checadas e exceções não checadas 80 7.4 Como declarar novos tipos de exceções 80 7.5 Como lançar exceções 81 7.6 Hierarquia das exceções 82 7.7 Exercícios 83 fluxo de dados 85 8.1 A classe File 85 8.2 Como escrever em arquivos 85 8.3 Como ler arquivos 86 8.4 Um editor de texto simples 87 8.5 Serialização de objetos 89 8.6 Um trocador de mensagens simples 90 8.7 Exercícios 93 genéricos e coleções 95 9.1 o que são genéricos 95 9.2 Introdução a coleções 97 9.3 Listas 97 9.4 Conjuntos 99 9.5 Mapas 99 9.5.1 Properties 101 9.6 Pilhas 103 9.7 Filas 104 9.8 Ordenação de Listas 104 9.9 Exercícios 106 uml: unified modeling language 109 10.1 Diagrama de Classe 109 10.1.1 Classe 109 10.1.2 Associações de Classe 110 10.2 Diagrama de Caso de Uso 112 10.2.1 Caso de Uso 112 10.2.2 Ator 113 10.2.3 Descrição do Caso de Uso 113 10.3 Demais diagramas 113 threads 115 11.1 Processos e Threads 115 11.1.1 Processos 115 11.1.2 Threads 115 11.2 Criação de Threads 116 http://solutioin.com Francisco Calaça, Otávio Calaça ix Versão 1.2-beta 12 13 14 15 x 11.3 A classe Executors 117 11.4 Métodos sleep e yield 118 11.5 Sincronização 118 11.6 O verificador de primos 121 11.7 Exercícios 123 strings e datas 125 12.1 As classes Date e Calendar 125 12.2 Formatação de Datas 126 12.3 A classe String 127 12.4 A classe StringBuffer 127 12.5 Saída formatada 128 12.5.1 Caracteres de conversão 128 12.6 Exercícios 130 jdbc 133 13.1 Conexão com banco de dados 133 13.2 A linguagem SQL 135 13.2.1 SELECT 135 13.2.2 Cláusula WHERE 135 13.2.3 O Operador LIKE 135 13.2.4 INSERT 136 13.2.5 UPDATE 136 13.2.6 DELETE 136 13.3 Como executar instruções SQL e obter registros 13.3.1 PreparedStatement 138 13.4 Execução em Lote 138 13.5 Tabela de Clientes 140 13.6 Exercícios 143 java persistence api com hibernate 145 14.1 Mapeamento objeto relacional 145 14.2 Configurações iniciais 145 14.3 A criação do primeiro exemplo 146 14.4 O arquivo persistence.xml 148 14.5 O EntityManager 150 14.6 A inclusão de clientes com JPA 151 14.6.1 Persistindo entidades 151 14.6.2 Localizando entidades 152 14.6.3 Removendo entidades 152 14.6.4 Mesclando entidades 152 14.7 Relacionamento entre classes 152 14.8 Formas de obtenção de id’s 155 14.9 JPQL - A linguagem consulta da Jpa 156 14.9.1 Passagem de parâmetros 156 14.10Exercícios 157 aplicativos web 159 15.1 XML 159 15.2 HTML 160 conteúdo 136 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 15.2.1 A estrutura básica de um documento HTML 15.2.2 Outras tags HTML 161 15.3 JavaScript 162 15.4 CSS 163 15.5 Aplicativos Web com Java 165 15.5.1 Instalação do Tomcat 165 15.6 Exercícios 166 16 servlets 167 16.1 Estrutura de uma aplicação web Java 167 16.2 Construindo o primeiro Servlet 167 16.3 Como fazer no eclipse 169 16.4 Atendendo requisições com o método get 170 16.5 Atendendo requisições com o método post 176 16.6 Redirect 177 16.7 Forward 179 16.8 Escopo de objetos web 180 16.8.1 Request 180 16.8.2 Session 181 16.8.3 Application 181 16.9 Como distribuir uma aplicação web 181 16.10Exercícios 182 17 java server pages 183 17.1 Elementos do Jsp 183 17.1.1 Scriptlet 183 17.1.2 Expressões 184 17.1.3 Declarações 185 17.2 Diretivas 185 17.2.1 Diretiva include 185 17.2.2 Diretiva Page 186 17.3 Ações do JSP 188 17.4 Biblioteca de tags JSTL 188 17.4.1 EL - Expressão de Linguagem 189 17.5 MVC - Model View Control 190 17.5.1 O cadastro de clientes 190 17.6 Exercícios 192 18 introdução ao javaserver faces 193 18.1 Fazendo JavaServer Faces funcionar 193 18.2 Managed bean 193 18.3 Tags básicas 197 18.3.1 Tags JSF para renderização de HTML 197 18.3.2 Tags Core do JSF 197 18.3.3 Exemplo de uso das Tags 197 18.4 Expressões de Ligação - EL 199 18.4.1 Ligações com atributos 200 18.4.2 Ligações com métodos 200 18.5 Configurar o Primefaces 201 http://solutioin.com Francisco Calaça, Otávio Calaça conteúdo 160 xi Versão 1.2-beta 18.6 Cadastro de Clientes 202 18.7 Cadastro de Produtos (com JPA) 205 18.8 Conversores 212 18.8.1 Conversores personalizados 212 18.9 Exercícios 215 19 padrões de projeto 217 19.1 Padrões GoF 217 19.2 Abstract Factory 218 19.2.1 Utilização 219 19.3 Factory Method 219 19.3.1 Utilização 219 19.3.2 Command 220 19.3.3 Problema 220 19.3.4 Aplicação 221 19.4 Data Access Object (DAO) 221 19.4.1 Vantagens 221 19.5 MVC 222 19.5.1 Componentes 222 19.5.2 Justificativa 222 a montagem do ambiente de trabalho 223 a.1 Obtenção e instalação do JDK 223 a.2 O que é a Máquina virtual Java 223 a.3 Obtenção e instalação do eclipse 223 b erros comuns enfrentados por iniciantes b.1 Exceções que costumam serem vistas 225 b.1.1 ClassNotFoundException 225 b.1.2 NoSuchMethodError 225 b.1.3 LazyInitializationException 225 b.1.4 NoClassDefFoundError 225 b.1.5 NullPointerException 225 b.1.6 ClassCastException 225 b.2 Erros comuns do HTTP 225 xii conteúdo 225 http://solutioin.com Francisco Calaça, Otávio Calaça 1 INTRODUÇÃO A computação pode ser definida como a busca de uma solução para um problema, a partir de entradas (inputs), e através de um algoritmo. É com isto que lida a teoria da computação, subcampo da ciência da computação e da matemática. Durante milhares de anos, a computação foi executada com caneta e papel, ou com giz e ardósia, ou mentalmente, por vezes com o auxílio de tabelas, ou utensílios artesanais. A primeira ferramenta conhecida para a computação foi o ábaco, inventado na Mesopotâmia em torno de 2400 a.C. Sua versão original consistia em desenhar linhas na areia com rochas. Os ábacos ainda são usadas como instrumento de cálculo hoje. 1.1. Algoritmos O matemático indiano Brahmagupta foi o primeiro a descrever o sistema de numeração hindu-arábico, no século VII. Nesta época, aparecem os primeiros relatos de utilização do número 0. Por volta de 820, o matemático persa Al-Khwarizmi escreveu o livro Calculando com Numerais Hindus. Este matemático foi responsável pela difusão do sistema de numeração hindu-arábico no Oriente Médio, e posteriormente na Europa. No século XII começaram traduzir este livro para o latim: Algoritmi de numero Indorum. Tais livros apresentaram novos conceitos para definir sequências de passos para completar tarefas (definição de algorítimos), como aplicações de aritmética e álgebra. Por derivação do nome, atualmente usa-se o termo algorítmo. 1.2. Lógica binária O matemático indiano Pingala inventou o sistema de numeração binário por volta do século III a.C. Este sistema de numeração ainda é utilizado atualmente no processamento de todos computadores, o sistema estabelece que sequências de uns e zeros podem representar qualquer número. Fisicamente estas sequências são substituidas pelos estados ligado e desligado. George Boole, em 1854, publicou a álgebra booleana com um sistema completo que permitia a construção de modelos matemáticos para o processamento computacional. Em 1801 apareceu o tear controlado por cartão perfurado, invenção de Joseph Marie Jacquard. Neste tear os buracos indicavam os uns, e áreas não furadas indicavam os zeros. O sistema ainda não pode ser considerado um computador, mas demonstrou que as máquinas poderiam ser controladas pelo sistema binário. 1 Versão 1.2-beta 1.3. introdução Nascimento da ciência da computação Antes da década de 1920, computador era um termo associado a pessoas que realizavam cálculos, geralmente físicos e matemáticos. Milhares de computadores, em sua maioria mulheres, eram empregados em projetos no comércio, governo e pesquisa. Após a década de 1920, a expressão máquina computacional começou a ser usada para referir-se a qualquer máquina que realize o trabalho de um profissional computador. No final da década de 1940 o termo máquina computacional perdeu espaço para o termo computador. As máquinas digitais estavam cada vez mais difundidas. Alan Turing, um dos pioneiros da Ciência da Computação, inventou a Máquina de Turing, que posteriormente evoluiu para o computador moderno. Em 1930 os engenheiros eletricistas já podiam construir circuitos eletrônicos para resolver problemas lógicos e matemáticos, mas a maioria o fazia sem qualquer processo, de forma particular, sem rigor teórico, ou qualquer estudo ou padronização. Isso mudou com a tese de mestrado de Claude E. Shannon de 1937, A Symbolic Analysis of Relay and Switching Circuits. Enquanto tomava aulas de Filosofia, Shannon foi exposto ao trabalho de George Boole, e percebeu que tal conceito poderia ser aplicado em conjuntos eletro-mecânicos para resolver problemas de lógica. Tal idéia, que utiliza propriedades de circuitos eletrônicos para a lógica, é o conceito básico de todos os computadores digitais. Shannon desenvolveu a teoria da informação no artigo de 1948 A Mathematical Theory of Communication, cujo conteúdo serve como fundamento para áreas de estudo como compressão de dados e criptografia. 1.4. Java A linguagem de programação orientada a objetos Java foi criada em 1991 pelo engenheiro James Gosling, da Sun, e anunciada em 1995. O projeto da sua criação surgiu num contexto de um outro projeto, em que certos problemas da linguagem C++, como, por exemplo, a falta de funcionalidades do ’garbage collection’, levaram a optar pela criação de uma nova linguagem, então denominada Oak (palavra inglesa para as árvores da família Quercus, como o carvalho) em "homenagem" à árvore que se encontrava plantada do lado de fora do escritório de James Gosling. Em 1994 esta linguagem foi renomeada para Java porque, após uma pesquisa de marcas, foi descoberta que já existia uma linguagem de computador denominada Oak. Desta forma, em 1996 o Java 1.0 foi finalmente apresentado à comunidade. Em 2009, a Oracle adquire a Sun Microsystems e tornou-se a detentora dos direitos e da marca Java. As especificações da linguagem Java são mantidas uniformes através de um processo comunitário gerido pela Sun Microsystems, o JCP (Java Community Process). Fazem parte do JCP várias empresas como a Oracle, Google, IBM, Nokia dentre outras. Para mais informações sobre o JCP acesse o site http://jcp.org. As características principais da linguagem Java são: • é orientada a objetos; 2 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta introdução • é independente de plataforma; • integra mecanismos e bibliotecas de funções para programação distribuída; • foi projetada para executar código remotamente sem perda de segurança. http://solutioin.com Francisco Calaça, Otávio Calaça 3 2 P R E PA R A Ç Ã O D O A M B I E N T E D E ESTUDOS Neste capítulo você montrará seu ambiente de estudos Java. A sua principal ferramenta é o JDK (Java Development Kit). Esta sigla significa: “Kit de Desenvolvimento Java”. O JDK contém uma vasta quantidade de aplicativos necessários para resolver problemas do dia a dia do desenvolvimento Java. Outra ferramenta importante é a IDE (Integrated Development Environment). Esta sigla significa: “Ambiente de desenvolvimento integrado”. Trata-se de uma ferramenta que contém vários recursos, necessários para a construção eficiente de um software. Hoje é possível encontrar diversas IDE’s para desenvolvimento em Java. Dentre elas estão o Eclipse1 e o NetBeans2 , que são ide’s Open Source e que contam com colabração de grandes comunidades e empresas ao redor do mundo. Os exemplos deste livro serão feitos utilizando o Eclipse. Apesar disto, nada impede você de instalar o netbeans e também testar estes exemplos nele. 2.1. Padronização do ambiente de trabalho É muito importante ter um ambiente de trabalho organizado e padronizado para prosseguimento dos estudos. Esta padronização te ajudará a encontrar dependências, aplicativos e exemplos e está ilustrada na Figura 2.1. Onde em: • Aplicativos: contém os aplicativos utilizados no desenvolvimento de software. Exemplo: JDK, eclipse, etc. • Material: contém bibliotecas, tutoriais, etc • Projetos: contém os seus projetos criados no decorrer da sua aprendizagem. 1 http://www.eclipse.org 2 http://www.netbeans.org Figura 2.1: Padronização do ambiente de trabalho utilizada 5 Versão 1.2-beta preparação do ambiente de estudos Se você quiser, pode baixar um arquivo compactado contendo esta estrutura já montada. Este arquivo pode ser obtido no site http://solutioin.com/java. Após ter realizado o download no seu computador, descompacte o arquivo em algum lugar de sua preferência e pronto! Você já está apto para começar os estudos em Java. Bons estudos! Dica: Se você ficou curioso em como este ambiente foi montado, acesse o Apêncie A que saberá como. 2.2. Primeiros testes no ambiente de trabalho Primeiro, inicialize o eclipse. Isto pode ser feito executando o programa eclipse (Linux) ou eclipse.exe (Windows) da pasta eclipse, dentro da pasta Aplicativos da estrutura baixada. Com o eclipse inicializado, crie um novo projeto Java. Depois crie uma classe. Será a primeira classe criada neste curso. O objetivo é que você entenda como funciona um programa bem simples em Java. O código deste exemplo inicial está apresentado na Listagem 2.1. Esta classe, após executada, gera a saída no console: Veja como é fácil Listagem 2.1: Exemplo do primeiro Programa 1 2 3 4 5 public class PrimeiroPrograma { public static void main(String[] args) { System.out.println("Veja como é fácil"); } } No momento, não se preocupe com as instruções desta classe. O que você deve entender agora é que o comando da linha 3 imprime no console o texto que se encontra entre aspas. Outra forma de apresentar texto para o usuário está ilustrada no código da Listagem 2.2. Observe, que após executar este código, a mensagem é apresentada em uma janela, conforme ilustrado na Figura 2.2. Listagem 2.2: Exemplo de apresentação de mensagem 1 import javax.swing.JOptionPane; 2 3 4 5 6 7 public class SegundoPrograma { public static void main(String[] args) { JOptionPane.showMessageDialog(null, "Olá , como vai ?"); } } Para um terceiro exemplo, será apresentado um código que faz a leitura de informações teclado. Isto será bastante útil nesta primeira fase do curso, onde estamos estudando os elementos iniciais da programação. A Listagem 2.3 exemplifica uma das formas de se obter informações do usuário. 6 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta preparação do ambiente de estudos Figura 2.2: Saída apresentada pelo segundo programa Listagem 2.3: Exemplo de apresentação de mensagem 1 import javax.swing.JOptionPane; 2 3 4 5 6 7 8 public class TerceiroPrograma { public static void main(String[] args) { String texto = JOptionPane.showInputDialog("Digite um texto:"); System.out.println("Texto digitado: " + texto); } } Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 2.3. Exercícios 1. Crie uma classe que apresente no console a seguinte mensagem: “Meu primeiro código Java”. 2. Crie uma classe que apresente em uma janela a mensagem: “Estou ficando bom nisto”. 3. Crie uma classe que solicite ao usuário as seguintes informações: nome, endereço e telefone. Após o usuário ter digitado estas informações, apresente em uma janela. http://solutioin.com Francisco Calaça, Otávio Calaça 7 3 L Ó G I C A D E P R O G R A M A Ç Ã O E M J AVA Todo programa é constituído por uma sequência lógica de passos que executará tarefas necessárias para a solução do problema a que o programa se propõem. Neste capítulo, serão apresentados os passos necessários para construção de um programa simples em Java. 3.1. Fluxograma Fluxograma é uma representação esquemática do processo. Ilustra graficamente a transição de informações ao longo da execução deste processo. É útil para compreensão de controle de fluxo quando o algoritmo é complexo ou extenso. A Figura 3.1 ilustra um fluxograma. Observe que cada ação é representada por um retângulo. O losango representa uma tomada de decisão. As elípses representam o início e o fim do processo. Figura 3.1: Exemplo de fluxograma 9 Versão 1.2-beta lógica de programação em java 3.2. Para entender os programas criados a partir de agora 3.2.1 Informações iniciais Para que haja um completo entendimento inicial nos programas que faremos neste capítulo, é importante apresentar alguns conceitos. 3.2.1.1 Pacote java.lang Não é necessário importar o pacote java.lang, ou seja, todas as classes deste pacote estão acessíveis sem a necessidade de que seja feito qualquer import. Algumas destas classes são: System, String, Integer, Double, Character, etc. 3.2.1.2 Nomeclatura dos métodos e das classes Java utiliza um padrão de escrita chamado CamelCase1 . • nomes de classes iniciam com letras maiúsculas e o restante das letras são minúsculas. Exemplo: PrimeiraClasse, PessoaFisica, etc. • nomes de métodos iniciam com letras minúsculas. Uma nova palavra no nome inicia com letra maiúscula (sem o caracter sublinhado _). Exemplo: realizarAcao(), fazerAlgo(), etc. 3.2.1.3 Método main Todo aplicativo Java inicia sua execução pelo método main. A única forma de escrever esta assinatura é: public static void main(String [] args) O significado de cada uma destas palavras será descrito posteriormente. É necessário que o leitor apenas utilize esta assinatura como está. 3.2.1.4 Case sensitive Em Java existe diferença entre letras maiúsculas e minúsculas. Assim, os identificadores teste, Teste e TesTe são todos diferentes. 1 CamelCase é a denominação em inglês para a prática de escrever palavras compostas ou frases, onde cada palavra é iniciada com Maiúsculas e unidas sem espaços. É um padrão largamente utilizado em diversas linguagens de programação, como Java, Ruby, PHP e Python, principalmente nas definições de Classes e Objetos. Exemplo: iPod, GameCube, OpenOffice.org, CamelCase, dataNascimento, enderecoEntregaMercadoria, ItemPedido. 10 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta lógica de programação em java 3.2.1.5 Nome da classe é o nome do arquivo Todo código Java deve ser escrito dentro de classes. O nome da classe deve ser o mesmo nome do arquivo. Isto não é uma regra, mas evitará alguns problemas. Posteriormente será apresentado mais detalhes sobre este assunto. 3.2.1.6 Outras observações Após cada instrução deve ser colocado um ponto-vírgula (;). Em Java as funções são chamadas de métodos. As variáveis declaradas fora dos métodos são chamadas de atributos ou variáveis de classe. 3.2.1.7 Comentários Existem três tipos de comentários em Java, conforme apresentado na Listagem 3.1. Listagem 3.1: Exemplo de comentários 1 //Comentário de linha 2 3 4 5 6 7 8 /* * Comentário * de * bloco */ 9 10 11 12 13 14 15 /** * Exemplo de comentário * de Javadoc. * */ 3.3. Strings Strings são cadeias de caracteres. Em java são representadas pela classe String e são expressas entre aspas. Strings literais como “abcdef” também são instâncias desta classe. É possível utilizar o operador + para concatenação de Strings: ‘‘Primeira String ’’ + ‘‘Segunda String’’ resulta em: ‘‘Primeira String Segunda String’’ Existem alguns caracteres que necessitam de alguns truques para serem expressos em Strings. Eles estão descritos na tablela da figura 3.2. A listagem 3.2 apresenta mais exemplos de sequências de escape. A saída deste exemplo é: http://solutioin.com Francisco Calaça, Otávio Calaça 11 Versão 1.2-beta lógica de programação em java Figura 3.2: Caracteres especiais e sua forma de representação em Strings Como colocar "aspas" na String. Exemplo de tabulação c:\diretorio\arquivo Observe que, para imprimir apenas uma barra, utiliza-se duas. Listagem 3.2: Exemplos de sequência de escape 1 2 public class ExemploSequenciaEscape { 3 public static void main(String[] args) { System.out.println("Como colocar \"aspas\" na String."); System.out.println("Exemplo\n\tde\n\t\ttabulação"); System.out.println("c:\\ diretorio \\ arquivo"); } 4 5 6 7 8 9 10 } 3.4. Saída Formatada O Java possui o recurso de saída formatada. Com este recurso é possível definir uma String de formatação e após isto, passar parâmetros para a mesma. Isto evita concatenação excessiva de String e aumenta a legibilidade do código. A utilização destes caracteres está descrita na Tabela 12.1. Para cada caractere de conversão existe um parâmetro que será colocado no seu lugar: ("O aluno %s foi %s", "Marcos", "aprovado") Neste caso palavra “Marcos” será colocada no lugar do primeiro %s e a palavra “aprovado” será colocada no lugar do segundo %s resultando no seguinte: "O aluno Marcos foi aprovado" A listagem 12.4 apresenta exemplos de saída formatada. 12 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta Caracter lógica de programação em java Aplicado em %s String %d Inteiro %f Ponto flutuante Tabela 3.1: Caracteres de conversão utilizados na saída formatada Listagem 3.3: Saída formatada 1 import javax.swing.JOptionPane; 2 3 4 public class ExemploSaidaFormatada { 5 public static void main(String[] args) { String nome = JOptionPane.showInputDialog("Nome:"); String resultado = JOptionPane.showInputDialog("Resultado:"); System.out.printf("O aluno %s foi %s\n", nome, resultado); System.out.printf("\nFormatação numérica :%.2f", 12.356); } 6 7 8 9 10 11 12 13 } 3.5. Conceito de Variável Para resolver problemas em programas de computador é necessário manipular vários dados, sejam eles números ou caracteres. Se você precisa calcular o resultado de uma única conta, provavelmente o melhor seria utilizar uma calculadora. A utilidade de se escrever um programa aparece quando usamos várias variáveis. Estas possuem a capacidade de conter valores. Desta forma, é possível então calcular o resultado de várias contas. As variáveis são declaradas com um identificador e seu nome. Exemplo: String nome; int idade; String endereco; Também é possível passar valores para variáveis no momento de sua declaração: String nome = "José Maria"; int idade = 5; String endereco = "Rua 2 nr 3 Centro"; http://solutioin.com Francisco Calaça, Otávio Calaça 13 Versão 1.2-beta 3.6. lógica de programação em java Palavras reservadas e identificadores Palavras reservadas, são as palavras que não podem ser usadas como identificadores, ou seja, não podem ser usadas como nome de variáveis, nome de classes, etc. Estas palavras são assim definidas ou porque já têm uso na sintaxe da linguagem ou porque serão usadas em algums momento, seja para manter compatibilidade com versões anteriores ou mesmo com outras linguagens. No caso do Java, as palavras reservadas estão descritas na Tabela 3.2. abstract continue for new switch assert default goto package synchronized boolean do if private this break double implements protected throw byte else import public throws case enum instanceof return transient catch extends int short try char final interface static void class finally long strictfp volatile const float native super while Tabela 3.2: As palavras reservadas do Java De acordo com a Java Language Specification2 , null, true e false são tecnicamente chamados de valores literais, e não keywords. Se você tentar criar algum identificador com estes valores, você também terá um erro de compilação. Utilizamos, em Java, as seguintes regras para criação do identificador: • não pode ser uma palavra reservada (Tabela 3.2); • não pode ser true nem false - literais que representam os tipos lógicos (booleanos); • não pode ser null - literal que represanta o tipo nulo; • não pode conter espaços em brancos ou outros caracteres de formatação; • deve ser a combinação de uma ou mais letras e dígitos (letras maíusculas, minúsculas, números, sublinha (_) e cifrão ($)). Os identificadores não podem começar com números. As letras maiúsculas e minúsculas diferenciam os identificadores, ou seja, x é um identificador diferente de X, nome é diferente de Nome, etc. Exemplos: X 2 http://docs.oracle.com/javase/specs/ 14 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta lógica de programação em java Y_1 nome Pessoa j3 _teste 3.7. Tipos Primitivos Tipos primitivos são tipos que não necessitam instanciação, ou seja, sua declaração já cria a variável na memória não sendo necessário construtores. Existem oito tipos primitivos em Java que são divididos em quatro grupos: • inteiros • ponto flutuante • caractere • booleano. 3.7.1 Tipos primitivos inteiros Os quatro tipos primitivos inteiros são utilizados para armazenamento de números inteiros, sem casas decimais. Eles estão descritos na Tabela 3.3. Tipo Tamanho Intervalo byte 1 byte −128 até +127 short 2 bytes −32.768 até +32, 767 int 4 bytes −2.147.483.648 até 2.147.483.647 long 8 bytes −9.223.372.036.854.775.808 até 9.223.372.036.854.775.807 Tabela 3.3: Tipos primitivos inteiros do Java Por padrão, os tipos primitivos inteiros são do tipo int, ou seja, se apenas for escrito o número 5, este será do tipo int. Para explicitar o tipo long deve-se acrescentar, após o número, a letra L (maiúscula ou minúscula): long numero = 45L; 3.7.2 Tipos primitivos de ponto flutuante Existem dois tipos de ponto flutuante, conforme descrito na tabela da figura 3.4. Estes tipos são utilizados para armazenamento de números com casas decimais. Utiliza-se o símbolo ponto (.) para separação decimal: http://solutioin.com Francisco Calaça, Otávio Calaça 15 Versão 1.2-beta lógica de programação em java 1234.566 4343.1212 Tipo Tamanho Intervalo float 4 byte +/ − 3.4E − 38 até +/ − 3.4E + 38 double 8 bytes +/ − 1.7E − 308 até +/ − 1.7E + 308 Tabela 3.4: Tipos primitivos de ponto flutuante do Java Por padrão, os tipos primitivos com casas decimais são do tipo double, ou seja, se apenas for escrito o número 3.5, este será do tipo double. Para explicitar o tipo float deve-se acrescentar, após o número, a letra F (maiúscula ou minúscula): float numero = 3.5F; 3.7.3 Tipo primitivo char O tipo primitivo char é utilizado para representar caracteres. Ocupa dois bytes para armazenamento e o intervalo vai de 0 até 65535. Note que o tipo char não abrange números negativos e possui dois bytes de armazenamento pois o Java suporta caracteres Unicode. Dica: O Unicode possui o objetivo explícito de transcender as limitações de codificações de carácter tradicionais, como as definidas pelo padrão ISO 8859, que possuem grande uso em vários países mas que permanecem em sua maioria incompatíveis umas com as outras. Várias codificações de carácter tradicionais compartilham um problema comum, ao permitirem processamento bilíngue (geralmente usando caracteres romanos e a língua local), mas não processamento multilíngue (processamento de línguas arbitrárias misturadas umas com as outras). 3.7.4 Tipo primitivo boolean O tipo primitivo boolean é utilizado para representar dois estados, verdadeiro ou falso. Exemplo: boolean ativo = true; boolean cancelado = false; 16 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta lógica de programação em java 3.7.5 Conversões de variáveis É possível realizar automáticamente conversões entre variáveis primitivas do Java seguindo a figura 3.3. Segundo esta figura não é possível converter automaticamente tipos maiores como long para tipos menores como byte. Neste caso é necessário realizar a operação cast: long maior = 56L; byte menor = (byte)maior; Observe que para realizar a operação de cast basta colocar o tipo que se deseja converter entre parêntesis na frente da variável a ser convertida. O código da listagem 3.4 apresenta um exemplo do que acontece quando é feito um cast de uma variável maior para uma menor. Existe o risco de truncamento do número. A saída deste exemplo é: Numero:300 Após truncamento:44 Isto ocorre porque 300 escrito em binário é: 100101100. Contando os primeiros oito bits da direita para esquerda, temos: 00101100. Este valor em decimal vale 44. O restante do número em binário fui truncado, ou seja, descartado. Listagem 3.4: Exemplo de truncamento de números 1 public class ExemploTruncamento { 2 public static void main(String[] args) { int numero = 300; byte menor = (byte) numero; System.out.printf("\nNumero:%d \nApós truncamento :%d", numero, menor); } 3 4 5 6 7 8 9 } 3.8. Operadores Quando o computador foi concebido ele era puramente uma máquina de cálculos. Apesar de atualmente o computador estar associado a diversas atividades da vida cotidiana, o mesmo ainda não passa de uma super máquina de fazer cálculos. Desta forma, a linguagem Java possui vários operadores cujo objetivo é realizar este cálculos. Nesta seção serão apresentados os operadores que irão nos auxiliar em operações matemáticas e lógicas. 3.8.1 Aritméticos A aritmética do Java é realizada por meio dos cinco operadores. Eles são divididos em dois grupos, os de maior prioridade, listados na Tabela 3.5 e os de menor prioridade, listados http://solutioin.com Francisco Calaça, Otávio Calaça 17 Versão 1.2-beta lógica de programação em java Figura 3.3: Conversões automáticas de tipos primitivos na Tabela 3.6. Os operadores de maior prioridade são executados antes dos operadores de menor prioridade, ou seja, se em uma expressão matemática existirem os dois tipos inicialmente realiza-se as operações de maior prioridade e somente após são executados os operadores de menor prioridade. A expressão: 5 + 3 * 5 Resultará em 20. A operação 3 ∗ 5 será executada primeiro. A ordem de execução do Java dá-se da esquerda para a direita, ou seja, o nosso sentido de leitura. Existindo, na mesma expressão matemática, dois ou mais operadores de maior prioridade será executado o que vier primeiro: 8/2 ∗ 3 resultará em 12 porque a divisão 8/2 veio primeiro. É possível alterar a órdem de execução com parêntesis. Após a execução de: x = (5 + 3) * 2 o valor da variável x será 16 pois a soma será feita primeiro devido aos parêntesis. 3.8.2 Atribuição Em Java é utilizado o operador = para realizar a atribuição. Sua ordem de execução é da direita para a esquerda, ou seja, os valores mais à direita são atribuídos às variáveis mais a esquerda: x = 4 equivale a dizer que o valor 4 será atribuído à variável x e, após a execução desta instrução a variável x passará a conter o valor 4. 18 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta Operador lógica de programação em java Operação realizada * Multiplicação / Divisão % Resto da divisão inteira Tabela 3.5: Operadores com maior prioridade Operador Operação realizada + Adição - Subtração Tabela 3.6: Operadores com menor prioridade Em Java, é possível combinar o operador de atribuição (=) com os operadores de aritmética. Desta forma são criados mais operadores de atribuição. Estes operadores estão listados na Tabela 3.7. Uma dica, para entender melhor estes operadores, é colocar o operador de aritmética antes do operador de atribuição. Sendo assim, se for necessário realizar as operações de soma e atribuição, primeiro escreva o operador de soma e depois o de atribuição: + =, x += 3; Após a execução desta instrução o valor da variável x será acrescido de 3. Operador Exemplo Equivalente a += s += 7 s=s+7 -= s -= 7 s=s-7 *= m *= 7 m=s*7 /= d /= 7 d=s/7 %= r %= 7 r=s%7 Tabela 3.7: Exemplos de operadores de atribuição 3.8.3 Incremento/Decremento Os operadores de incremento e decremento são utilizados quando existe a necessidade de somar ou subtrair em apenas uma unidade os valores contidos em uma variável utilizando dois sinais de soma, para incremento e dois sinais de subtração para decremento: Assim, x + + incrementará o valor de x e x − − decrementará o valor de x. Estes operadores se dividem em dois grupos: http://solutioin.com Francisco Calaça, Otávio Calaça 19 Versão 1.2-beta lógica de programação em java 1. Pré-incremento/Pré-decremento: primeiro é incrementado/decrementado e somente depois o valor é utilizado. O operador é colocado antes da variável: x = 4; y = ++x + 5; O resultado de y após esta execução é 10. Inicialmente o valor de x é incrementado passando a valer 5. Só após o incremento o valor da variável é utilizado na operação de soma. 2. Pós-incremento/Pós-decremento: primeiro utiliza-se o valor e somente depois a variável é incrementada/decrementada. O operador é colocado após a variável. x = 4; y = x++ + 5; O resultado de y após esta execução é 9. Inicialmente o valor de x é somado, assim 4 + 5 vale 9. O valor só é incrementado após as operações aritméticas. 3.8.4 Relacionais São utilizados para comparar duas variáveis. O resultado da comparação é um valor booleano. A relação de comparadores do Java pode ser vista na Tabela 3.8. Operador Operação == Igualdade != Diferença > Maior que >= < <= Maior ou igual que Menor que Menor ou igual que Tabela 3.8: Operadores de comparação do Java 3.8.5 Lógicos Existem quatro operações lógicas, cujos operadores estão ilustrados na Figura 3.9: 1. E, o resultado de uma operação lógica E só é verdadeiro se os dois operandos também forem verdadeiros; 20 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta lógica de programação em java 2. OU, o resultado de uma operação lógica OU só é falso se os dois operandos também forem verdadeiros; 3. NAO, o resultado é a negação do operando, assim o que é verdadeiro se torna falso e o que é falso se torna verdadeiro após esta operação; 4. OU EXCLUSIVO, o resultado de uma operação lógica OU EXCLUSIVO só é verdadeiro se os dois operandos forem diferentes. Operador Operação || OU curto-circuito && E curto-circuito | OU lógico & E lógico ˆ OU exclusivo ! Não lógico Tabela 3.9: Tabela de operadores lógicos A tabela verdade do Operador E pode ser vista na figura 3.11, do Operador OU na figura 3.10 e a tabela do Operador OU EXCLUSIVO na figura 3.12. Observe na Figura 3.9 que existem dois tipos de operadores para a operação OU: | (OU simples) e || (OU curto-circuito) e dois tipos de operadores para a operação E: & (simples) e && (E curto-circuito). Basicamente o que diferem estes dois tipos de operadores são o seguinte. OU e E curtocircuito (|| e &&) são utilizados apenas para operações condicionais. Em uma operação condicional, já sendo possível a obtenção do resultado, analisando apenas o primeiro operando, não é analisado o segundo operando. Neste caso a resposta já é retornada, daí o nome curto circuito. Exemplo: V || ? = V F && ? = F Note, no exemplo, que na operação de OU, independente do valor do segundo operando, a resposta será sempre verdadeira se o primeiro operando também for. Na operação de E, a resposta será sempre falsa se o primeiro operando também for. Como você pode perceber, não é necessário analisar o segundo operando para retornar as respostas nestes casos. Já os operadores OU e E lógico (| e &) são utilizados em operações lógicas bit a bit. Por exemplo: 410 = 1002 310 = 0112 410 |310 ⇒ 1002 |0112 Desta forma, 410 |310 = 7, pois 1002 |0112 = 1112 http://solutioin.com Francisco Calaça, Otávio Calaça 21 Versão 1.2-beta lógica de programação em java Entrada 1 Entrada 2 Saída V V V V F V F V V F F F Tabela 3.10: Tabela verdade da operação OU Entrada 1 Entrada 2 Saída V V V V F F F V F F F F Tabela 3.11: Tabela verdade da operação E 3.9. Estruturas de seleção Estrutura de seleção (expressão condicional ou ainda construção condicional) é uma estrutura de desvio do fluxo de controle que executa diferentes instruções dependendo se a seleção (ou condição) é verdadeira ou falsa, em que a expressão é processada e transformada em um valor booleano. 3.9.1 if . . . else A instrução if . . . else se comporta da seguinte maneira. Quando o teste do “if” for verdadeiro, é executado o código que se encontra logo em seguida do if. No caso do teste ser falso, é executado o código que se encontra logo em seguida do else. O bloco else não é obrigatório. A figura 3.4 ilustra o fluxo da instrução if . . . else. Na listagem 3.5 pode ser visto um exemplo de uso. Sua sintaxe é: Entrada 1 Entrada 2 Saída V V F V F V F V V F F F Tabela 3.12: Tabela verdade da operação OU EXCLUSIVO 22 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta lógica de programação em java if(teste){ //executa somente se o teste for verdadeiro }else{ //executa somente se o teste for falso } Figura 3.4: Fluxo de execução do if Listagem 3.5: Exemplo de uso do if . . . else 1 import javax.swing.JOptionPane; 2 3 4 5 6 7 8 public class ExemploIf { public static void main(String[] args) { //Obtenção dos dados do usuário String notaString = JOptionPane.showInputDialog("Digite a nota:"); //Conversão em int int nota = Integer.parseInt(notaString); 9 if (nota >= 5) { JOptionPane.showMessageDialog(null, "Aprovado"); } else { JOptionPane.showMessageDialog(null, "Reprovado"); } 10 11 12 13 14 } 15 16 } http://solutioin.com Francisco Calaça, Otávio Calaça 23 Versão 1.2-beta lógica de programação em java Dica: Para converter String em int, utilize o código: int nota = Integer.parseInt(notaString); e para converter String em double: double nota = Double.parseDouble(notaString); 3.9.2 Operador condicional ou ternário O operador condicional pode ser utilizado como um if ... else. Este operador é conhecido também como operador ternário porque ele possui três operandos: (teste ? "quando teste verdadeiro" : "quando teste falso" )); Um exemplo de uso deste operador está na Listagem 3.6. Na listagem 3.7 pode ser visto outro exemplo de aplicação do operador condicional na listagem 3.7; Listagem 3.6: Exemplo de uso do operador condicional. 1 import javax.swing.JOptionPane; 2 3 4 5 6 7 8 9 10 11 public class ExemploCondicional { public static void main(String[] args) { String notaString = JOptionPane.showInputDialog("Digite a nota:"); int nota = Integer.parseInt(notaString); String resultado = nota >= 5 ? "aprovado" : "reprovado"; String msg = "O aluno foi " + resultado; JOptionPane.showMessageDialog(null, msg); } } Listagem 3.7: Outro exemplo de uso do operador condicional. 1 import javax.swing.JOptionPane; 2 3 4 5 6 public class ImprimeMaior { public static void main(String[] args) { String primeiroNumero = JOptionPane.showInputDialog("Digite um número:"); String segundoNumero = JOptionPane.showInputDialog("Digite um número:"); 7 int n1 = Integer.parseInt(primeiroNumero); int n2 = Integer.parseInt(segundoNumero); 8 9 10 int maior = n1 > n2 ? n1 : n2; 11 12 JOptionPane.showMessageDialog(null, "O maior numero é: " + maior); 13 } 14 24 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 15 lógica de programação em java } 3.9.3 switch Diferente das instruções if e if . . . else, a instrução switch permite um maior número de possibilidades de caminhos de execução. A palavra chave switch pode ser utilizada somente com o tipo primitivo int (byte, short, char por conversão automática e seus tipos Wrappers), o tipo Enum e, a partir da versão 7 do Java, String. Sua sintaxe é: switch(tipo){ case a: //instrucao; case b: //instrucao; default: //instrucao; } Na Listagem 3.8 está o código de exemplo da instrução switch. É comum utilizar a instrução switch juntamente com o break para que apenas uma opção seja executada. Listagem 3.8: Exemplo de utilização do switch 1 import javax.swing.JOptionPane; 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class ExemploSwitch { public static void main(String[] args) { String numeroString = JOptionPane.showInputDialog("Digite o número de um mês (1 a 12):"); int num = new Integer(numeroString); String msg; switch (num) { case 1: msg = "Janeiro"; break; case 2: msg = "Fevereiro"; break; case 3: msg = "Março"; break; case 4: msg = "Abril"; break; case 5: msg = "Maio"; break; http://solutioin.com Francisco Calaça, Otávio Calaça 25 Versão 1.2-beta case 6: msg = "Junho"; break; case 7: msg = "Julho"; break; case 8: msg = "Agosto"; break; case 9: msg = "Setembro"; break; case 10: msg = "Outubro"; break; case 11: msg = "Novembro"; break; case 12: msg = "Dezembro"; break; default: msg = "Número incorreto"; } JOptionPane.showMessageDialog(null, msg); 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 } 50 51 lógica de programação em java } 3.10. Estruturas de Repetição Estrutura de repetição é uma estrutura de desvio do fluxo de controle que realiza e repete diferentes ações, dependendo se uma condição é verdadeira ou falsa, em que a expressão é processada e transformada em um valor booleano. Estão associados a uma estrutura de repetição uma condição (também chamada "expressão de controle" ou "condição de parada") e um bloco de código: verifica-se a condição, e caso seja verdadeira, o bloco é executado. Após o final da execução do bloco, a condição é verificada novamente, e caso ela ainda seja verdadeira, o código é executado novamente. 3.10.1 for A instrução for provê um caminho rápido para percorer uma faixa de valores. Com esta instrução é possível repetir determinadas instruções enquanto a condição for verdadeira. A sintaxe do for é a seguinte: for (inicialização; condição; incremento) { instruções(s) } 26 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta lógica de programação em java É bom lembrar que: • A inicialização é executada apenas quando o loop inicia; • Quando a condição for false o loop terminará; • O incremento é invocado depois de cada iteração, local adequado para incrementos e decrementos de variáveis; Veja na listagem 3.9 um exemplo de uso do laço for. Neste exemplo são impressas quinze linhas no console. Listagem 3.9: Exemplo de uso do laço for 1 2 3 4 5 6 7 public class ExemploFor { public static void main(String[] args) { for (int i = 0; i < 15; i++) { System.out.printf("\nlinha: %d", i); } } } 3.10.2 while A instrução while executa um bloco de instruções enquanto uma condição particular for verdadeira (true). Sua sintaxe é: while (teste) { statement(s) } A expressão while avalia o teste, que deve retornar um tipo booleano. Se a espressão avaliada for verdadeira (true), o bloco while executa as instruções dentro do bloco. A expressão while continua testando o teste até que este seja falso (false). O código da listagem 3.10 calcula a soma de inteiros enquanto a opção de saída não é informada. Listagem 3.10: Exemplo de utilização do laço while 1 import javax.swing.JOptionPane; 2 3 4 5 public class ExemploWhile { public static void main(String[] args) { int status = 0; 6 7 8 int qtd = 0; double soma = 0; 9 10 11 12 while (status != 1) { String numStr1 = JOptionPane.showInputDialog("Digite um inteiro"); int n1 = Integer.parseInt(numStr1); 13 http://solutioin.com Francisco Calaça, Otávio Calaça 27 Versão 1.2-beta lógica de programação em java soma += n1; qtd++; 14 15 16 String msg = "Digite 1 para sair ou qualquer outro número para continuar"; String statusStr = JOptionPane.showInputDialog(msg); 17 18 19 status = Integer.parseInt(statusStr); 20 21 } 22 23 double media = soma / qtd; JOptionPane.showMessageDialog(null, "Média: " + media); 24 25 26 } 27 28 } 3.10.3 do . . . while A linguagem Java provê a instrução do . . . while que pode ser vista abaixo: do { statement(s) } while (teste); A principal diferença entre do . . . while e while é que while primeiro avalia o teste e somente após executa o loop, enquanto do . . . while primeiro executa a instrução e somente após isto é avaliado o teste. Em resumo, do . . . while garante pelo menos uma execução das instruções do bloco. 3.11. Exercícios 1. Crie um código que executa a seguinte ação: solicita ao usuário uma idade. Se esta for maior ou igual a 16, imprime: “Pode votar”. Se não for, imprime: “Não pode votar”. 2. Melhore o código do exercício anterior para imprimir também “Voto obrigatório” quando a idade estiver entre 18 e 70 anos. 3. Crie um código que imprima o seguinte: ************ ************ ************ ************ 4. Crie um código que solicita ao usuário um número entre 1 e 7. Após isto, o sistema imprime: Domingo se o número for 1, Segunda se o número for 2, Terça se o número for 3, etc. . . 28 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta lógica de programação em java 5. Altere o código da listagem 3.10 para utilizar do. . . while no lugar de while. Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! http://solutioin.com Francisco Calaça, Otávio Calaça 29 4 I N T R O D U Ç Ã O À O R I E N TA Ç Ã O A OBJETOS O Objetivo da orientação a objetos é facilitar o reuso de software. Hoje ao ir a uma loja para comprar uma lâmpada, a única coisa que é necessário saber é a potência desta. O fabricante da lâmpada, sem ter medido nada na sua sala, consegue fabricar uma lâmpada que servirá para você. Hoje é fácil reutilizar lâmpadas por conta que estas seguem alguns padrões que facilitam sua utilização. Não é necessário rever toda a fiação da sua residência quando uma lâmpada queima, nem substituir nada. Basta tirar a lâmpada defeituosa e colocar outra nova no seu lugar. Desta forma, a orientação a objetos traz para o mundo do software as facilidades encontradas no mundo real. Neste capítulo você verá os conceitos inicias da orientação a objetos, tais como classes e seus elementos. Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 4.1. O conceitos Classe e Objeto Os conceitos iniciais de Orientação a Objetos são: • Classe, significa grupo ou conjunto. Representa um tipo de dados que pode conter atributos e métodos, como por exemplo, Carro. A classe Carro define todo o conjunto de carros. A este conjunto é possível associar atributos como potência, número de passageiros, etc. Mas lembre-se, trata-se de apenas um conjunto, este ainda pode estar vazio. • Objeto, representa um elemento do conjunto Carro, ou seja, o carro construído. Sabendo o que é um carro (seus atributos) é possível construir quantos objetos do tipo carros forem necessários. Em resumo: Objeto é a instância de uma classe. Mas o que significa instância ? Instância siginifica a concretização de algo, ou seja, a materizalização de um objeto. Assim a frase: “Objeto é a instância de uma classe” pode ser traduzida como: “Objeto é a concretização de uma classe”. 31 Versão 1.2-beta introdução à orientação a objetos Assim uma classe é o arquivo, o código digitado, enquanto o objeto será construído pelo programa, a partir da classe, e executado pelo computador. Para declarar classes utiliza-se a palavra chave class: class Carro { //campos, construtores, e declaração de métodos } Para instanciar, ou criar, objetos a partir de uma classe utiliza-se o operador: new. Carro seuCarro = new Carro(); Note que uma classe é também um tipo. Você acabou de criar um novo tipo de variáveis no Java! O tipo Carro. Antes de serem instanciadas, as variáveis objeto valem null. A palavra chave null é utilizada para expressar a não existencia de uma instância de um objeto em determinada variável, ou seja, representa o nulo. Esta forma, uma variável não instanciada possui o valor null. 4.2. Elementos de uma classe Uma classe possui atributos e métodos. Existe também um tipo especial de método: o método construtor. Nesta seção serão apresentados estes elementos. 4.2.1 Atributos Atributos de uma classe são as propriedades da mesma. No exemplo do Carro, atributos poderiam ser: cor, dataDeFabricacao, potência, etc. Observe que atributos são substantivos que descrevem a Classe e que são exclusivos de cada objeto, ou seja, apesar de todos os Carros possuirem o atributo cor, cada Carro pode ter uma cor diferente. Na classe da listagem 4.1 existem os atributos cor e velocidade. Após a execução da classe da Listagem 4.2, você verá a seguinte saída: Cor: Branco - Velocidade:80.0 Listagem 4.1: Carro com seus atributos 1 2 3 4 public class Carro { double velocidade; String cor; } Listagem 4.2: Classe que cria um objeto do tipo Carro 1 2 3 public class CarroTeste { public static void main(String[] args) { Carro obj = new Carro(); 32 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta introdução à orientação a objetos obj.cor = "Branco"; obj.velocidade = 80; 4 5 6 System.out.printf("Cor: %s - Velocidade :%s\n", obj.cor, obj.velocidade); 7 } 8 9 } 4.2.2 Métodos Métodos são como funções. Possuem instruções que são executadas quando o método é invocado. Em Orientação a Objetos os métodos descrevem ações realizadas pelos objetos. Em Java os métodos devem possuir tipo de retorno: int realizaAlgo(){ //instruções return 5; } Neste caso é obrigatório explicitar o que o método retorna com a palavra chave return. Se o método não retornar algo, o tipo de retorno utilizado é void (note que sempre deve ser informado o tipo de retorno. Mesmo quando o método não retorna nada!): void realizaAlgo(){ //instruções } Os métodos também podem receber parâmetros: void realizaAlgo(int parametro){ //instruções } Havendo a necessidade de múltiplos parâmetros em um método utiliza-se vírgula para separá-los: void realizaAlgo(int parametro, double outroParametro){ //instruções } A Listagem 4.3 inclui métodos na classe Carro. Estes métodos são responsáveis por alterar a velocidade e parar o carro. A Listagem 4.4 apresenta um exemplo de execução destes métodos. Após sua execução, você verá a seguinte saída: Mudando a velocidade para 80,000000 Km/h Velocidade atual: 80,000000 Km/h Parando veículo. Velocidade 0 Km/h. Cor: Branco Mudando a velocidade para 60,000000 Km/h Velocidade atual: 60,000000 Km/h Parando veículo. Velocidade 0 Km/h. Cor: Vermelho http://solutioin.com Francisco Calaça, Otávio Calaça 33 Versão 1.2-beta introdução à orientação a objetos Listagem 4.3: Carro com atributos e métodos 1 public class Carro { 2 double velocidade; String cor; 3 4 5 void mudarVelocidade(double v) { velocidade = v; System.out.printf("\n\nMudando a velocidade para %f Km/h", velocidade) ; } 6 7 8 9 10 void pararCarro() { System.out.printf("\nVelocidade atual: %f Km/h", velocidade); System.out.printf("\nParando veículo. Velocidade 0 Km/h. Cor: %s", cor ); } 11 12 13 14 15 } Listagem 4.4: Classe que cria um objeto do tipo Carro 1 2 3 4 5 6 public class CarroTesteMetodo { public static void main(String[] args) { Carro meuCarro = new Carro(); meuCarro.cor = "Branco"; meuCarro.mudarVelocidade(80); meuCarro.pararCarro(); 7 Carro carroDaEsposa = new Carro(); carroDaEsposa.cor = "Vermelho"; carroDaEsposa.mudarVelocidade(60); carroDaEsposa.pararCarro(); 8 9 10 11 } 12 13 } 4.2.3 Métodos construtores Métodos construtores são um tipo especial de métodos. Eles são invocados quando objetos são criados. A declaração de um construtor é similar a declaração de um método, exceto o tipo de retorno: Construtores não possuem tipo de retorno. Nem void. Toda classe Java possui um construtor. Se não for implementado um construtor o compilador criará um automaticamente. Este construtor criado, é chamado de construtor padrão por não receber parâmetros. Dica: Construtor padrão é aquele que não recebe parâmetros. 34 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta introdução à orientação a objetos É possível passar parâmetros para construtores conforme apresentado na listagem 4.5. É uma forma de criar objetos e ao mesmo tempo ajustar os atributos iniciais. O código da listagem 4.6 possui a seguinte saída: Fabricando uma Motocicleta. Cor: Azul, Potência: 125,000000 cilindradas Fabricando uma Motocicleta. Cor: Vermelho, Potência: 250,000000 cilindradas Fabricando uma Motocicleta. Cor: Prata, Potência: 400,000000 cilindradas Listagem 4.5: Exemplo de construtor que recebe atributos 1 2 3 public class Motocicleta { String cor; double potencia; 4 public Motocicleta(String c, double p) { cor = c; potencia = p; System.out.printf("\n\nFabricando uma Motocicleta." + "\nCor: %s, Potência: %f cilindradas", cor, potencia); } 5 6 7 8 9 10 11 } Listagem 4.6: Criação de motocicletas 1 2 3 4 5 6 7 public class MotocicletaTeste { public static void main(String[] args) { Motocicleta moto1 = new Motocicleta("Azul", 125); Motocicleta moto2 = new Motocicleta("Vermelho", 250); Motocicleta moto3 = new Motocicleta("Prata", 400); } } 4.2.4 Padrões de nomenclatura Os padrões de nomenclatura utilizados pelos programadores Java são: • Os nomes das classes começam com letras maiúsculas; • Os nomes dos métodos e variáveis começam com letras minúsculas; • Não é utilizado o caracter _ para mudança de palavra e sim a colocacação da primeira letra da palavra em maiúsculo. • Variáveis constantes são escritas em maiúsculo. http://solutioin.com Francisco Calaça, Otávio Calaça 35 Versão 1.2-beta introdução à orientação a objetos Dica: Esta padronização, dentre outras da linguagem Java, estão descritas no documento chamado: Code Conventions for the Java Programming Language. Este documento pode ser acessado através do site: http://www.oracle.com/technetwork/java/codeconv-138413.html 4.3. Atributos e métodos static Até agora todos os atributos e métodos de uma classe só estavam acessíveis atravéz de suas instâncias. Se você observar o campo out da classe System verá que é possível acessa-lo diretamente da classe, sem qualquer instância. Os campos podem ser da classe ou do objeto. Até agora todos os campos criados foram de objetos, pois só são acessíveis a partir de objetos. Para que determinados atributos possam ser compartilhados por todos os objetos de determinada classe, estes atributos devem possuir o modificador static. Na listagem 4.7 é apresentada uma classe com um atributo static. Observe que este atributo é incrementado a cada nova instância desta classe. A classe da listagem 4.8 cria três objetos do tipo ObjetoTeste e no final acessa a variável quantidadeInstancias para saber este número. Note que é possível acessar elementos statics sem a necessidade de instanciar a classe. Listagem 4.7: Objeto para testes da palavra chave static 1 2 public class ObjetoTeste { 3 static int quantidadeInstancias; 4 5 public ObjetoTeste() { quantidadeInstancias ++; } 6 7 8 9 10 } Listagem 4.8: Demonstração da palavra chave static 1 2 public class ExemploStatic { 3 public static void main(String[] args) { ObjetoTeste obj1 = new ObjetoTeste(); ObjetoTeste obj2 = new ObjetoTeste(); ObjetoTeste obj3 = new ObjetoTeste(); 4 5 6 7 8 System.out.printf("\nQuantidade de instâncias do Objeto" + "Teste:%d" , ObjetoTeste.quantidadeInstancias); 9 10 } 11 12 36 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 13 introdução à orientação a objetos } 4.3.1 Import static Permite importar métodos e campos static de determinadas classes. Exemplo: import static javax.swing.JOptionPane.*; import static java.lang.Math.*; Observe no código da listagem 4.9 a utilização de vários métodos do tipo static das classes JOptionPane e Math. A cada utilização de um método destas classes como: JOptionPane.showMessageDialog(...); Um exemplo equivalente está no código da listagem 4.10. Nesta classe foi utilizado o import static o que tornou desnecessário a referência das classes JOptionPane e Math: showMessageDialog(...); Listagem 4.9: Código sem import static 1 import javax.swing.JOptionPane; 2 3 4 5 6 7 8 9 public class ExemploSemImportStatic { public static void main(String[] args) { String numeroTexto = JOptionPane.showInputDialog("Digite um número:"); int numero = new Integer(numeroTexto); double raizQuadrada = Math.sqrt(numero); double cubo = Math.pow(numero, 3); double seno = Math.sin(numero); 10 JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(null, 11 12 13 14 "Raiz Quadrada:" + raizQuadrada); "Cubo:" + cubo); "Seno:" + seno); } 15 16 "Numero:" + numero); } Listagem 4.10: Código com import static 1 2 3 import static javax.swing.JOptionPane.*; import static java.lang.Math.*; 4 5 6 7 8 9 10 11 public class ExemploImportStatic { public static void main(String[] args) { String numeroTexto = showInputDialog("Digite um número:"); int numero = new Integer(numeroTexto); double raizQuadrada = sqrt(numero); double cubo = pow(numero, 3); double seno = sin(numero); http://solutioin.com Francisco Calaça, Otávio Calaça 37 Versão 1.2-beta introdução à orientação a objetos 12 showMessageDialog(null, showMessageDialog(null, showMessageDialog(null, showMessageDialog(null, 13 14 15 16 "Numero:" + numero); "Raiz Quadrada:" + raizQuadrada); "Cubo:" + cubo); "Seno:" + seno); } 17 18 19 } 4.4. Tipos Wrapper As classes wrappers tem o papel de encapsular os tipos primitivos para a possibilidade de operações como: conversões, mudança de bases decimais, e algumas operação que somente a objetos é permitido, como por exemplo, trabalhar com conjuntos. Java possui oito tipos wrapper, que adicionam funcionalidades aos tipos primitivos: 1. Byte - byte 2. Short - short 3. Integer - int 4. Long - long 5. Float - float 6. Double - double 7. Character - char 8. Boolean - boolean Basicamente os tipos wrapper possuem os mesmos nomes dos tipos primitivos, com a primeira letra maiúscula, exceto para os tipos int que é Integer e char que é Character. Algumas destas funcionalidades são: a conversão de tipo primitivo para objeto, conversão para String, conversão à partir de String, etc. 4.4.1 Auto-boxing e Auto-unboxing Este conceito permite converter automaticamente tipos primitivos em equivalentes objetos utilizando a classe Wrapper respectiva. Isto economiza código e facilita o entendimento do programa. • Auto-boxing, conversão automática de um tipo primitivo para seu respectivo tipo Wrapper; • Auto-unboxing, conversão automática de um tipo Wrapper para seu respectivo tipo primitivo; 38 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta introdução à orientação a objetos Veja na listagem 4.11 um exemplo de boxing e unboxing. Listagem 4.11: Exemplo de auto boxing 1 2 3 4 5 6 7 public class ExemploAutoBoxing { public static void main(String[] args) { /* * Exemplo de auto boxing. Observe o número 16, tipo int e primitivo, foi * automaticamente convertido para o tipo Wrapper Integer. */ Integer idade = 16; 8 /* * Exemplo de auto unboxing. Observe a utilização da classe Integer para * conversão da String 56 em tipo int. */ int quantidade = new Integer("56"); 9 10 11 12 13 14 } 15 16 } 4.5. Regras de escopo Entenda por escopo área de atuação. Os escopos do Java são definidos por chaves. As variáveis declaradas dentro de um escopo somente podem ser acessadas dentro deste mesmo escopo. Observe que os blocos if, while, for, métodos, etc. definem escopos. Seus códigos são escritos entre chaves. Todas as variáveis declaradas dentro de um bloco if somente podem ser acessadas dentro de um bloco if. Cada método define um novo escopo, por isto as variáveis declaradas dentro de um método não podem ser acessadas por outro método, ou seja, outro escopo. Observe o código da listagem 4.12. Neste código existe um bloco for no método main. Dentro do bloco for foi declarada as variáveis numero e i. Estas variáveis não podem ser acessadas fora do bloco for. Listagem 4.12: Exemplo de regras de escopo 1 2 3 4 5 6 7 8 public class ExemploEscopo { public static void main(String[] args) { for (int i = 0; i < 10; i++) { int numero = i; System.out.println("linha " + i); } } } http://solutioin.com Francisco Calaça, Otávio Calaça 39 Versão 1.2-beta 4.6. introdução à orientação a objetos Sobrecarga de métodos Java trabalha com o conceito da assinatura de métodos. A assinatura de um método consiste no nome do mesmo juntamente com seus atributos de entrada. Assim o método: void acao(String texto) possui a assinatura acao(String), pois o método se chama acao e recebe uma String como parâmetro de entrada. Não entra no conceito de assinatura de um método o seu tipo de retorno, ou seja, dois métodos: void acao(String texto) int acao(String texto) possuem a mesma assinatura: acao(String) pois o tipo de retorno não é considerado na definição da assinatura. O código da listagem 4.13 apresenta um exemplo de sobrecarga de métodos. Neste código todos os métodos se chamam metodoQualquer e diferem apenas na quantidade e tipo de parâmetros. Observe que suas assinaturas são diferentes. O método main invoca cada um destes métodos passando parâmetros diferentes. A JVM consegue descobrir o método correto a ser executado em função da quantidade e tipo dos parâmetros informados. Listagem 4.13: Exemplo de sobrecarga de métodos 1 2 3 4 5 6 7 8 9 10 11 12 13 public class ExemploSobrecarga { static void metodoQualquer(int i){ System.out.printf("\nEste método recebe um INT: %d", i); } static void metodoQualquer(double d){ System.out.printf("\nEste método recebe um DOUBLE: %f", d); } static void metodoQualquer(String texto){ System.out.printf("\nEste método recebe um BYTE: %s", texto); } static void metodoQualquer(){ System.out.printf("\nEste método não recebe parâmetros"); } 14 public static void main(String[] args) { metodoQualquer(1); metodoQualquer(1.0); metodoQualquer("teste"); metodoQualquer(); } 15 16 17 18 19 20 21 } 40 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta introdução à orientação a objetos Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 4.7. Exercícios 1. Qual a diferença entre classe e objeto? 2. Quais são os elementos de uma classe? 3. O que são métodos construtores? 4. Para que serve a palavra chave static? 5. O que faz o import static? 6. O que é um escopo? 7. O que é sobrecarga de métodos? 8. O que são tipos wrappers ? Quais são eles ? 9. Crie uma classe java com atributos e métodos (à sua escolha). Crie outra classe que instancia a primeira, seta seus atributos e invoca seus métodos. 10. Adicione um construtor na classe do exercício anterior. http://solutioin.com Francisco Calaça, Otávio Calaça 41 5 A R R AY S Arrays são estruturas de dados que permitem o armazenamento de objetos o que facilita a manipulação e transporte destes. No mundo real são utilizadas caixas quando é necessário agrupar ou transportar objetos. No mundo do Java uma das estruturas utilizadas são Arrays. Para trabalhar adequadamente com Arrays é necessário que você saiba como inicializa-los. O próprio método main recebe um array de strings quando é feito String [] args. O Java 5 trouxe uma nova estrutura for, mais adequada para percorrer valores de arrays. Esta estrutura é mais rápida e mais simples de implementar. Trata-se do for aprimorado. 5.1. O que são arrays Um array é um objeto continer utilizado para armazenar outros objetos. Possui um tamanho fixo. O tamanho de um array é estabelecido quando este é criado. Após sua criação não é mais possível alterar este tamanho. Em capítulos posteriores será apresentado as coleções que podem ter seus tamanhos alterados. Cada item em um array é chamado de elemento e cada elemento pode ser acessado por um índice numérico. Este índice é um inteiro e sempre se inicia com 0, ou seja, um array com 10 elementos terá os índices de 0 até 9. Um bom exemplo para ilustrar um array é a caixa de ovos. Pense em uma caixa de ovos com 9 unidades. A caixa de ovos é um array com 9 elementos. Todos do tipo ovo. A figura 5.1 ilustra isto. Note que quando se cria um array este é uma caixa de ovos vazia mas com um espaço pré-determinado, no caso 9. Este espaço é o tamanho do array. Somente após a criação do array é possível “colocar” elementos nele. Para acessar determinado elemento de um array é necessário utilizar colchetes: int n = numeros[4]; Este exemplo acessa o quinto elemento do array (a numeração dos índices de um array inicia com 0, por isto o indice 4 representa o quinto elemento). Se ocorrer uma tentativa de acesso a um elemento não existente em um array ocorrerá um erro. Por exemplo, ao tentar acessar o sexto elemento de um array com 3 elementos será visto um erro: int [] numeros = new int[3]; int n = numeros[5]; Ocasionará o erro: java.lang.ArrayIndexOutOfBoundsException No capítulo sobre exceções será apresentado como tratar estes tipos de erros. 43 Versão 1.2-beta arrays Figura 5.1: Um array pode ser comparado a um porta ovos, cada elemento do array pode ser comparado a um ovo 5.2. Declaração e inicialização de arrays É possível declarar arrays da seguinte forma: int [] primeiroArray; Como nas declarações de variáveis de qualquer tipo no Java, a declaração possui duas partes: o tipo e o nome da variável. Note que o tipo do array é escrito como tipo[], onde tipo é o tipo de dados que será colocado no array. Também é possível, ao declarar arrays, colocar os colchetes após a variável: int primeiroArray []; Mas esta forma é menos usual no Java. Um array é inicializado utilizando o operador new porque este é um objeto: primeiroArray = new int[10]; Este exemplo cria um array com capacidade de armazenamento de 10 elementos. Esta operação apenas inicializa o array, mas não os elementos internos a este. Os elementos devem ser inicalizados um a um: primeiroArray[0] = 2; primeiroArray[1] = 3; . . . primeiroArray[8] = 4; primeiroArray[9] = 5; Outra forma de se inicializar um array e, ao mesmo tempo, inicializar os elementos de um array é: int [] primeiroArray = {1, 2, 3, 4, 5, 6, 7, 8, 9}; Observe neste exemplo que é, na mesma linha, declarado um array, inicializado com 10 elementos e, cada elemento, é inicializado com um determinado valor. Uma observação importante, que costuma cair nas provas de certificação, é que quando o array é de tipos primitivos todos os elementos deste são inicializados com 0 ou false, se for 44 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta arrays de tipo boolean. Em array de Objetos, os elementos não são inicializados, todos continuarão valendo null. Array possui um atributo chamado length. Este atributo possui a quantidade de elementos do array. O código da listagem 5.1 apresenta um exemplo de declaração e inicialização de arrays. Observe neste exemplo que foi declarado dois tipos de arrays: um array de int e um array de String. Os elementos destes arrays não foram inicializados mas após a iteração entre seus elementos é possível notar que os elementos do array de int valem 0 e os elementos dos array de tipo String valem null. A saída deste exemplo é a seguinte: Array de tipo int Posição [0] = 0 Posição [1] = 0 Posição [2] = 0 Posição [3] = 0 Posição [4] = 0 Posição [5] = 0 Posição [6] = 0 Posição [7] = 0 Posição [8] = 0 Posição [9] = 0 Array de tipo String Posição [0] = null Posição [1] = null Posição [2] = null Posição [3] = null Posição [4] = null Posição [5] = null Posição [6] = null Posição [7] = null Posição [8] = null Posição [9] = null Listagem 5.1: Exemplo de declaração de arrays 1 2 3 4 5 6 public class DeclaracaoArray { public static void main(String[] args) { //Criando um array de tipo int int [] numeros = new int[10]; //Criando um array de String String [] textos = new String[10]; 7 8 9 System.out.println("\nArray de tipo int"); for (int i = 0; i < numeros.length; i++) { http://solutioin.com Francisco Calaça, Otávio Calaça 45 Versão 1.2-beta arrays System.out.printf("Posição [%d] = %d\n", i, numeros[i]); 10 } 11 12 System.out.println("\nArray de tipo String"); for (int i = 0; i < textos.length; i++) { System.out.printf("Posição [%d] = %s\n", i, textos[i]); } 13 14 15 16 17 } 18 19 } 5.3. Método main Agora é possível explicar toda a assinatura do método main: public static void main(String [] args){ . . . } Sempre deverá ser assim! Este método deve: • Ser public pois deve ser acessado externamente; • Ser static pois, como é o primeiro método a ser acessado em um programa Java, ainda não é possível existir uma instância de um objeto, logo, é necessário um método static, que pode ser acessado fora de qualquer instância de um objeto; • Deve, sempre, receber um array de String como parâmetro. São os parâmetros para o programa. O código da listagem 5.2 ilustra como obter os parâmetros informados pela linha de comando a um programa Java. Neste exemplo observe a utilização do atributo length no laço for. Para configurar o eclipse basta clicar no botão descrito na figura 5.2. Após isto crie um novo Java Application, conforme ilustrado na figura 5.3. Clique na aba Arguments e coloque os parâmetros no campo Program Arguments. Para executar via linha de comandos basta acrescentar, após a classe, os parâmetros para a aplicação, conforme ilustrado na figura 5.4. Listagem 5.2: Obtenção dos parâmetros informados ao programa 1 2 3 4 5 6 7 8 public class ParametrosPrograma { public static void main(String[] args) { System.out.println("Os parâmetros digitados foram:"); for (int i = 0; i < args.length; i++) { System.out.println(args[i]); } } } 46 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta arrays Figura 5.2: Início das configurações de execução Figura 5.3: Configuração do eclipse para passagem de parâmetros para a aplicação Figura 5.4: Passagem de parâmetros para uma aplicação Java via linha de comando http://solutioin.com Francisco Calaça, Otávio Calaça 47 Versão 1.2-beta 5.4. arrays Laço for aprimorado O Java 5 trouxe uma nova funcionalidade para iteração de arrays: o for aprimorado. Esta nova forma de utilização do for permite iterações de coleções e arrays de forma compacta e mais fácil de ser lida. Para demonstrar um exemplo, considere o exemplo da listagem 5.3. Neste exemplo é utilizada a seguinte estrutura for: for (String meioTransporte : transportes) { . . . } Observe que este for necessita apenas de dois parâmetros: A variável que receberá cada item do array e o array. Este for percorrerá todo o array transportes e coloca, cada elemento deste, na variável meioTransporte. Listagem 5.3: Exemplo de uso do for aprimorado 1 2 3 public class ForAprimorado { public static void main(String[] args) { String [] transportes = {"Terrestre", "Aquático", "Aéreo"}; 4 for (String meioTransporte : transportes) { System.out.printf("\nTransporte: %s", meioTransporte); } 5 6 7 } 8 9 } 5.5. Passagem de parâmetros no Java Em Java todos os parâmetros são passados por valor. Isto significa que o valor da variável passado sempre será copiado para o valor da variável que está recebendo o parâmetro. Mas isto provoca dois tipos de comportamentos diferentes: • Quando a variável passada é primitiva (byte, short, int long, float, double, char e boolean), o valor é copiado para a variável que está recebendo, ou seja, esta pode sofer alterações que não serão replicadas no valor da variável passada. • Quando é passado uma variável Objeto, o valor desta também é copiado. A diferença é que o valor de uma variável Objeto é apenas a referência a este Objeto, por isto, tem-se a impressão que ocorreu uma passagem por referência, mas ainda é por valor, pois este foi copiado. Lembre-se o valor de uma variável Objeto é a referência a este objeto. Se, neste caso, for alterada a variável passada, esta também sofre alterações na origem. Para poder entender melhor isto, veja o código da listagem 5.5. Esta classe utiliza a classe Pessoa descrita na listagem 6.4. 48 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta arrays Observe, na classe da listagem 5.5, a existência de dois métodos chamados metodoQualquer. O primeiro método recebe um int, que é um tipo primitivo, e o segundo método recebe uma Pessoa, que é um objeto. Quando invocado o metodoQualquer pela primeira vez no método main, foi passado como parâmetro a variável valor que é um tipo primitivo. Note que o valor desta variável não mudou, antes e depois da execução do metodoQualquer continuou tendo 4 como valor. Quando é invocado o metodoQualquer passando um objeto do tipo Pessoa, este teve sua referência copiada. Assim quando alterado em metodoQualquer, esta alteração será percebida no método main. Observe que, apesar de se ter a impressão que ocorreu uma passagem por referência, não foi isto que ocorreu no Java. O que ocorreu foi uma passagem por valor. Lembre-se que em Java as varáveis Objeto armazenam apenas a referência a um objeto. Na passagem de parâmetros por valor, o valor (no caso a referência ao objeto do tipo Pessoa) foi copiado para o método metodoQualquer. A figura 5.5 ilustra a cópia de uma referência. Observe que, apesar de serem variáveis e referência diferentes, o Objeto é o mesmo. Assim, uma alteração realizada pela referência referencia 01 - variável 01 também será percebida pela referência referencia 02 - variável 02. Um outro exemplo está no código da listagem 5.6. Lembre-se que array é um objeto, logo terá sua referência copiada. O método alteraArray recebe um array de int. Este array (que é um objeto) é criado no método main e passado como parâmetro para o método passagemArray. Gerando a seguinte saída: Antes: 1 2 3 4 5 6 7 8 9 Depois: 11 12 13 14 15 16 17 18 19 Figura 5.5: Comportamento das referências do Java Listagem 5.4: Classe Pessoa utilizada no exemplo de passagem de parâmetros 1 2 3 public class Pessoa { String nome; http://solutioin.com Francisco Calaça, Otávio Calaça 49 Versão 1.2-beta public Pessoa(String n) { nome = n; } 4 5 6 7 arrays } Listagem 5.5: Exemplo de passagem de parâmetros no Java 1 2 3 4 public class PassagemParametros { static void metodoQualquer(int a) { a++; } 5 static void metodoQualquer(Pessoa p) { p.nome = p.nome + "[NOME ALTERADO]"; } 6 7 8 9 public static void main(String[] args) { System.out.println("Passagem tipo primitivo:"); int valor = 4; System.out.printf("\nValor antes: %d", valor); metodoQualquer(4); System.out.printf("\nValor depois: %d", valor); 10 11 12 13 14 15 16 Pessoa pessoa = new Pessoa("Maria"); System.out.printf("\n\nValor antes: %s", pessoa.nome); metodoQualquer(pessoa); System.out.printf("\nValor depois: %s", pessoa.nome); 17 18 19 20 } 21 22 } Listagem 5.6: Passagem de um array como parâmetro 1 2 3 4 5 6 public class PassagemArray { static void alteraArray(int[] array) { for (int i = 0; i < array.length; i++) { array[i] += 10; } } 7 public static void main(String[] args) { int[] numeros = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; System.out.println("\n\nAntes:"); for (int n : numeros) { System.out.printf(" %d ", n); } alteraArray(numeros); System.out.println("\n\nDepois:"); for (int n : numeros) { System.out.printf(" %d ", n); } } 8 9 10 11 12 13 14 15 16 17 18 19 20 } 50 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 5.6. arrays Arrays multidimensionais É possível, mas não aconselhado, utilizar arrays multidimensionais no Java. Basta acrescentar o par abre e fecha colchetes para cada dimensão. Note que os arrays criados até agora possuem dimensão unitária. Um exemplo de array bi-dimenssional é: int [][] matriz = new int [3][4]; Neste exemplo foi declarado um array bi-dimensional e inicializado com 3 x 4 posições de armazenamento, podendo ser utilizado para representação de uma matriz com 3 linhas e 4 colunas. 5.7. Lista de parâmetros com comprimento variável Mais uma funcionalidade acrescentada no Java 5 foi a Lista de parâmetros com comprimento variável: vararg. A declaração é feita utilizando o tipo, reticências e nome da variável: metodoQualquer(double ... variável){ } Este exemplo cria o metodoQualquer que pode receber qualquer quantidade de valores do tipo double: metodoQualquer(1, 2, 3); metodoQualquer(3.5, 6.4); metodoQualquer(); São todas as chamadas válidas para metodoQualquer. Um outro exemplo de vararg é o método printf. Note que este método pode receber uma quantidade qualquer de parâmetros. Para utilização de vararg deve-se seguir as seguintes regras: 1. Um método pode receber no máximo uma lista de parâmetros variáveis; 2. A lista de parâmetros variáveis deve ser o último argumento; 3. Entenda que a lista de parametros variáveis será convertida, pelo compilador, em um array; 4. É possível passar de 0 a muitos parâmetros para um vararg; O código da listagem 5.7 apresenta um exemplo de utilização de vararg. Esta classe possui um método chamado calcularMedia(double . . . variável) que recebe uma quantidade qualquer de parâmetros. http://solutioin.com Francisco Calaça, Otávio Calaça 51 Versão 1.2-beta arrays Listagem 5.7: Exemplo de utilização de vararg 1 2 3 4 5 6 7 8 public class ExemploVararg { public static double calcularMedia(double... notas) { double soma = 0; for(double n : notas){ soma += n; } return soma / notas.length; } 9 public static void main(String[] args) { double media = calcularMedia(5, 6, 5, 8); System.out.printf("\nA média é: %f", media); } 10 11 12 13 14 } Também é possível utilizar vararg no método main, apesar de pouco usual: public static void main(String ... args) { } Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 5.8. Exercícios 1. O que são arrays? 2. Quais as formas de se declarar um array? 3. Explique o for aprimorado. 4. Como passar parâmetros para o método main? 5. Explique a passagem de parâmetros no Java. 6. O que são lista de parâmetros com comprimento variável? 7. Crie uma classe chamada Calculadora. Esta classe deverá possuir os métodos somar e multiplicar que recebam uma quantidade variável de parâmetros do tipo double. O método somar retorna a soma de todos eles e o método multiplicar o valor do produto entre eles. 52 http://solutioin.com Francisco Calaça, Otávio Calaça 6 U M P O U C O M A I S D E O R I E N TA Ç Ã O A OBJETOS No capítulo 4 foi realizada uma introdução à orientação a objetos. Neste capítulo será apresentado mais detalhes deste novo paradigma: Encapsulamento, Herança, Abstração e Polimorfismo. Estes elementos promovem o melhor reuso de software o que torna possível a concepção de sistemas mais complexos e menos propensos a erros. Outro assunto abordado neste capítulo é o coletor de lixo. Algumas tecnologias demandam uma preocupação do desenvolvedor em desalocar recursos. Em Java não é necessário preocupar-se com isto. Os objetos criados uma vez não mais referenciados são coletados pelo Garbage Collector (Coletor de lixo). Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 6.1. Coletor de lixo É chamado de heap space o espaço onde ficam armazenados os objetos Java instanciados. Os objetos são criados pelo operador new e alocados no heap space em tempo de execução. A coleta do lixo é o processo automático que remove os objetos que não estão sendo mais referenciados liberando espaço neste heap space. O coletor de lixo ou gc (garbage collector em inglês) é um processo executado paralelamente à aplicação e é responsável pela liberação de memória. Nas listagens 6.1 e 6.2 é apresentado uma demonstração de funcionamento do coletor de lixo. Todas as instâncias de ObjetoColetado, ao serem instanciadas, escrevem a linha: ++ Construindo o objeto: 0 e toda as vezes que estas instâncias são finalizadas pelo gc, é executado o método void finalize(). Desta forma, é impressa a linha: -- Finalizando o objeto: 0 Assim a saída do programa é: ++ Construindo o objeto: 0 ++ Construindo o objeto: 1 53 Versão 1.2-beta um pouco mais de orientação a objetos ++ Construindo o objeto: 2 ++ Construindo o objeto: 3 -- Finalizando o objeto: 3 -- Finalizando o objeto: 2 . . . ++ Construindo o objeto: 1200 ++ Construindo o objeto: 1201 Quando você executar na sua máquina o comportamento será ligeiramente diferente. Os objetos coletados bem como a ordem que isto é realizado serão diferentes. Isto ocorre por não ser possível prever o momento em que determinado objeto será coletado. É possível solicitar à máquina virtual a invocação do coletor de lixo. Para isto, deve ser executado o método System.gc(). Isto não é aconselhado uma vez que existe um algoritmo, bastante otimozado, para realizar esta tarefa. Listagem 6.1: Objeto a ser coletado na demonstração do coletor de lixo 1 public class ObjetoColetado { 2 int numero; 3 4 public ObjetoColetado(int n) { numero = n; System.out.printf("\n++ Construindo o objeto: %d", numero); } 5 6 7 8 9 protected void finalize() throws Throwable { System.out.printf("\n-- Finalizando o objeto: %d", numero); } 10 11 12 13 14 } Listagem 6.2: Demonstração do coletor de lixo 1 2 public class ExemploColetorLixo { 3 public static void main(String[] args) { for (int i = 0; i < 5000; i++) { new ObjetoColetado(i); } } 4 5 6 7 8 9 10 } 6.2. A palavra-chave this A palavra chave this pode ser utilizada de duas formas: • como método 54 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta um pouco mais de orientação a objetos • como referência Quando utilizada como método, este acessa o construtor da própria classe. Observe que um dos construtores do código abaixo: public class Ponto { public int x = 0; public int y = 0; //construtor public Ponto(int a, int b) { x = a; y = b; } public Ponto() { this(0, 0); } } invoca um outro construtor com a chamada this(0, 0) passando os parâmetros para outro construtor. Quando utilizada como referência esta referencia o objeto da própria classe. Com this é possível acessar os elementos da instância do objeto a partir da classe. Note que a palavra chave this não pode ser utilizada dentro de contextos static porque nestes contextos não são acessados a partir de instâncias da classe e sim diretamente. Lembre-se this acessa membros do objeto criado a partir da classe em que é utilizado. Por exemplo a classe Ponto pode ser escrita assim: public class Ponto { public int x = 0; public int y = 0; //construtor public Ponto(int a, int b) { x = a; y = b; } } Mas também pode ser escrito assim: public class Ponto { public int x = 0; public int y = 0; //construtor public Ponto(int x, int y) { http://solutioin.com Francisco Calaça, Otávio Calaça 55 Versão 1.2-beta um pouco mais de orientação a objetos this.x = x; this.y = y; } } Cada argumento do segundo exemplo se possui o mesmo nome dos atributos da classe: x e y. Para diferencia-los é utilizado this. A referência this indica que this.x e this.y são as variáveis x e y da classe e não do construtor. Assim: this.x = x; Significa que o valor declarado de x será atribuido a um elemento da classe chamado x. 6.3. Variáveis do tipo final Variáveis do tipo final são constantes no Java. Isto significa que: • É obrigatória a inicialização; • Após ser inicializada seu valor não pode mais ser alterado; É um padrão utilizar letras maiúsculas nos identificadores de variáveis do tipo final: final int CONSTANTE = 7; 6.4. Encapsulamento Encapsulamento significa, na íntegra, colocar dentro de uma cápsula. Imagine o seguinte cenário: Um parque municipal, sem grades, muros, etc. Todos os visitantes podem entrar no parque por qualquer lugar. O parque é muito extenso. Um dia o administrador do parque deseja entregar um aviso dizendo que no dia seguinte não será aberto. Como entregar os avisos? Dificil! O que fazer para facilitar a entrega de informações aos visistantes do parque? Solução: Criar grades ao redor do parque e colocar uma portaria! Assim qualquer aviso a ser dado aos visitantes do parque pode ser dado por meio de uma determinada portaria. Fica muito mais fácil avisar a todos uma vez que é obrigatória a passagem dos visitantes pela portaria. Encapsulamento é justamente isto. Significa fechar todas as entradas a um atributo e construir uma portaria onde é possível entrar e sair valores para melhorar o controle sobre os valores deste atributo. Encapsulamento é um dos pilares da Orientação a Objetos e no java é feito da seguinte forma: • Para fechar todos os acessos utiliza-se o modificador de acesso private no atributo. Este modificador impede que o atributo da classe possa ser acessado de outra classe. 56 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta um pouco mais de orientação a objetos • Para construir a “portaria” devem ser criados os métodos acessores: getAtributo() para ler o resultado e setAtributo para gravar no atributo. Suponha o seguinte atributo: String nome; Para ecapsulá-lo é necessário: Proibir o acesso ao nome a partir de outra classe: private String nome; Construir os métodos acessores get. . . e set. . . : public String getNome(){ } public void setNome(String nome){ } Apesar dos termos get e set estarem em inglês é obrigatório que estes sejam usados desta forma. Mais adiante este padrão será necessário para correto funcionamento de determinadas API’s. Não se preocupe com isto. Hoje a maior parte das IDE’s fazem este trabalho. No eclipse basta criar a classe, escrever os atributos nela (com o modificador private), conforme a figura 6.1. Após isto clique com o botão direito na tela e selecione a opção source - Generate getters and setters, conforme a figura 6.2. Clique nos parâmetros que deseja criar os métodos getters e setters conforme a figura 6.3. A figura 6.4 apresenta os métodos criados. Figura 6.1: Exemplo do encapsulamento no eclipse: Criando o atributo http://solutioin.com Francisco Calaça, Otávio Calaça 57 Versão 1.2-beta um pouco mais de orientação a objetos Figura 6.2: Exemplo do encapsulamento no eclipse: Invocando o assistente para criação do encapsulamento Figura 6.3: Exemplo do encapsulamento no eclipse: Escolha dos campos que serão encapsulados 58 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta um pouco mais de orientação a objetos Figura 6.4: Exemplo do encapsulamento no eclipse: Resultado final 6.5. Enumerações As enumerações (ou enums) são tipos especiais de Java que permite lista limitada dos valores. Estes valores podem ser passados às indicações de controle (switch(), if() ex.) Em liberações prévias, a maneira padrão representar um tipo enumerated era o teste padrão interno de Enum: teste padrão interno de Enum - tem problemas severos! final static public int INVERNO = 0; final static public int PRIMAVERA = 1; final static public int VERAO = 2; final static public int OUTONO = 3; Este teste padrão tem muitos problemas, como: • Como os tipos são int é possível passar o número 10, por exemplo, que não corresponde a nenhuma estação do ano. • É provável que ocorram conflitos entre constantes, por exemplo, pode existir uma constante MASCULINO = 1 que conflitará com PRIMAVERA, ou seja, neste caso PRIMAVERA = MASCULINO!. 6.6. Pacotes Para facilitar a localização, melhorar a organização e os conflitos de nomes entre classes é utilizado pacotes que agrupam tipos relacionados. Definição: Um pacote é um agrupamento de tipos relacionados que facilitam o gerenciamento de algumas classes. http://solutioin.com Francisco Calaça, Otávio Calaça 59 Versão 1.2-beta um pouco mais de orientação a objetos Os tipos (classes, enumerações, interfaces) que fazem parte da plataforma java sao membros de vários pacotes como: • Pacote java.lang, classes fundamentais do java • Pacote java.io, classes para leitura e escrita em dispositivos É possível colocar as suas classes dentro de pacotes também, utilizando a palavra chave package: package livro.capitulo08; Não é permitida a existência de mais que uma declaração package. Isto se dá pelo fato de que um tipo (classe, enum ou interface) pode estar em apenas um pacote. A declaração package deve ser a primeira declaração do arquivo. Antes dos import’s, antes de tudo. Suponha que você escreveu um grupo de classes que representa objetos gráficos, como círculos, retângulos, linhas e pontos. public class Circulo { . . . } public class Retangulo{ . . . } public class Ponto{ . . . } public class Linha{ . . . } Você deve colocar estas classes em um pacote por várias rasões, incluindo: • Você ou outros programadores podem facilmente determinar que estes tipos estão relacionados entre si. • Você e outros programadores sabem onde encontrar os tipos que fornecem funcionalidades gráficas. • Os nomes dos seus tipos não conflitarão com os nomes de tipos com outros pacotes • Você pode permitir tipos que serão acessados apenas por elementos de dentro do mesmo pacote ou tipos que serão acessados externamente 60 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta um pouco mais de orientação a objetos 6.6.1 Como usar tipos dentro de outros pacotes É possível utilizar tipos (classes, enums ou interfaces) dentro de outros pacotes de três formas: • Referencie o tipo com o seu nome qualificado. Ex.: java.util.Date • Importe o tipo: import java.util.Date • Importe todos os tipos dentro do pacote: import java.util.* A listagem 6.3 apresenta esses três exemplos. Nesta listagem é possível ver a declaração de: • import java.io.* - que importa todos os tipos do pacote java.io • import java.util.Date - que importa apenas o tipo Date do pacote java.util • java.util.List - que referencia diretamente o tipo dentro do pacote sem a necessidade do import. Listagem 6.3: Exemplo de uso de pacotes 1 2 import java.io.*; import java.util.Date; 3 4 public class ExemploPacote { 5 public static void main(String[] args) { /* * A classe Date foi importada através da declaração: * import java.util.Date; * contida no cabeçalho da classe */ Date hoje = new Date(); System.out.println(hoje); 6 7 8 9 10 11 12 13 14 /* * Note a referência direta à List, sem a necessidade * de realizar um import. */ java.util.List lista = new java.util.ArrayList(); 15 16 17 18 19 20 /* * Esta classe foi importada do pacote java.io, através * da declaração: * import java.io.*; */ File arquivo = new File("c:\\ arquivo.txt"); 21 22 23 24 25 26 } 27 28 } http://solutioin.com Francisco Calaça, Otávio Calaça 61 Versão 1.2-beta 6.7. um pouco mais de orientação a objetos Herança Na Orientação a Objetos uma classe pode derivar de outras classes atributos e métodos. Uma classe que deriva, ou herda de outra classe é chamada de subclasse (também classe derivada, classe extendida, ou classe filha). A classe é herdada por uma subclasse é chamada de superclasse (também classe ancestral, classe pai). A Herança define uma especialização. Desta forma uma subclasse, pode ser entendida como uma especialização de determinada classe. Por exemplo, seja a classe Medico. Uma especialização é Pediatra. Desta forma, um Pediatra possui todos os métodos e atributos de Medico, afinal um Pediatra ainda é Medico. Mas, além destes, possui também atributos e métodos específicos de Pediatra. Exceto a classe Object, que não possui superclasses, todas as classes tem uma, e somente uma superclasse direta (herança simples). Se uma classe não tiver herdando de outra explicitamente, então esta herda da classe Object de forma implícita. Heraça somente é aplicado a atributos e métodos de classes. Construtores não são herdados por herança. 6.7.1 Um exemplo de Herança O código da listagem 6.4 apresenta a classe Pessoa que será ancestral das demais classes em nosso exemplo. Observe a existencia dos atributos nome e telefone nesta classe. A classe Aluno, apresentada na listagem 9.14, herda de pessoa. Esta herança faz comv que Aluno também possua os atributos e métodos de Pessoa, como nome e telefone. A listagem 6.6 apresenta o uso das classes Aluno e Pessoa. Note que o método imprimirDados é utilizado para imprimir os dados referentes à classe. Listagem 6.4: Classe Pessoa 1 2 public class PessoaFisica { 3 private String nome; private String telefone; 4 5 6 7 8 public PessoaFisica(String nome, String telefone) { this.nome = nome; this.telefone = telefone; } 9 10 11 12 13 public void imprimirDados(){ System.out.printf("\nNome: %s - Telefone :%s", nome, telefone); } 14 15 16 17 public String getNome() { return nome; } 18 19 20 62 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta public void setNome(String nome) { this.nome = nome; } public String getTelefone() { return telefone; } public void setTelefone(String telefone) { this.telefone = telefone; } 21 22 23 24 25 26 27 28 29 30 um pouco mais de orientação a objetos } Listagem 6.5: Classe Aluno - filha de Pessoa 1 2 public class Aluno extends PessoaFisica{ 3 private double nota; 4 5 public Aluno(String nome, String telefone, double nota) { super(nome, telefone); this.nota = nota; } 6 7 8 9 10 public void imprimirDados() { super.imprimirDados(); System.out.printf(" Nota: %.2f", nota); } 11 12 13 14 15 public double getNota() { return nota; } 16 17 18 19 public void setNota(double nota) { this.nota = nota; } 20 21 22 23 } Listagem 6.6: Exemplo da utilização da herança com as classes Pessoa e Aluno 1 2 public class ExemploHeranca { 3 public static void main(String[] args) { PessoaFisica pessoa = new PessoaFisica("Maria", "3231 -2323"); Aluno aluno = new Aluno("Claudia", "3132 -5656", 8.5); 4 5 6 7 pessoa.imprimirDados(); aluno.imprimirDados(); 8 9 } 10 11 12 } http://solutioin.com Francisco Calaça, Otávio Calaça 63 Versão 1.2-beta um pouco mais de orientação a objetos 6.7.2 Sobrescrita de métodos Note que a classe Aluno possui um método com mesmo nome e assinatura de sua ancestral, Pessoa. A isto da-se o nome de sobrescrita de métodos. Mais adiante será apresentado o Polimorfismo e a Sobrescrita de métodos possui papel fundamental no Polimorfismo. 6.7.3 A palavra-chave super A palavra chave super pode ser utilzada de duas formas: • como método • como referência. Quando utilizada como método, este acessa o método construtor da classe Pai. Note no construtor da classe da listagem 9.14 que foi utilizado super(nome, telefone); para referenciar o construtor da super-classe. Quando utilizada como referência, este acessa métodos ou membros da classe Pai. Note no método imprimirDados() o uso de super.imprimirDados(); para também imprimir os dados de pessoa. 6.8. Alguns Modificadores de acesso Veja agora o uso de quatro modificadores de acesso: 6.8.1 private A palavra private restringe o acesso do método ou do atributo somente à classe que o definiu, ou seja, um método ou atributo privado só poderá ser acesso dentro da classe que o definiu.! A listagem 6.4 descreve uma classe que possui um atributo com esse modificador. Veja que não é possível acessar o atributo nome de fora desta classe. 6.8.2 pacote É utilizado quando não existe nenhum modificador de acesso antes da variável. Restringe o acesso somente a classes definidas dentro do mesmo pacote, ou seja, quando não é informado nenhum modificador de acesso, o elemento pode apenas ser acessado de uma classe que esta no mesmo pacote. 64 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta um pouco mais de orientação a objetos 6.8.3 protected Ele é um pouco mais liberal que o modificador padrão ou pacote, pois ele permite que um método de uma classe definida em um pacote possa ser acessado por uma classe definida em outro pacote desde que esta classe seja filha da anterior. 6.8.4 public Um método público pode ser acessado por qualquer classe em qualquer pacote. Utilizado para estabelecer uma interface entre os componentes do programa. É boa prática definir todos os membros de uma classe private e ir aumentando a acessibilidade quando for necessário. Evite criar tudo do tipo public. 6.9. Classe object A classe Object é uma classe que serve de superclasse para todas as classes existentes em Java. Isso significa que ao criar uma classe, se não for especificada nenhuma superclasse após a palavra extends, então a classe Object será assumida automaticamente como superclasse. Portanto toda classe é subclasse de Object, e com isso herda alguns métodos automaticamente. 6.9.1 método equals() Um método muito interessante presente na classe Object é o equals. Suponha que haja duas instâncias de uma mesma classe e é necessário testar se elas contém a mesma informação. O operador: == retorna apenas o valor true apenas se seus operandos forem precisamente o mesmo objeto. Porém, o operador equals retorna quando os objetos contém o mesmo estado, através da comparação campo-a-campo. Por exemplo, eu e você podemos ter carro do mesmo modelo. Nesse caso: meuCarro == seuCarro seria false pois embora nossos carros sejam do mesmo modelo, são carros diferentes. Entretanto, meuCarro.equals(seuCarro); poderia ser true se os atributos de ambos os carros fossem idênticos, por exemplo, mesmo ano, mesma cor, etc. A listagem 6.7 apresenta um exemplo de comparação de objetos. Note que apesar das Strings possuirem o mesmo valor: texto, ao compará-las com == não é visto o resultado esperado. Apenas com equals. http://solutioin.com Francisco Calaça, Otávio Calaça 65 Versão 1.2-beta um pouco mais de orientação a objetos A saída deste exemplo é: s1 = texto s2 = texto s1 diferente de s2 com == s1 igual a s2 com equals Listagem 6.7: Exemplo de comparação entre objetos com equals 1 public class ExemploEquals { 2 public static void main(String[] args) { String s1 = new String("texto"); String s2 = new String("texto"); 3 4 5 6 System.out.printf("s1 = %s\n", s1); System.out.printf("s2 = %s\n", s2); 7 8 9 if (s1 == s2) { System.out.println("s1 igual a s2 com =="); } else { System.out.println("s1 diferente de s2 com =="); } 10 11 12 13 14 15 if (s1.equals(s2)) { System.out.println("s1 igual a s2 com equals"); } else { System.out.println("s1 diferente de s2 com equals"); } 16 17 18 19 20 21 } 22 23 24 } 6.9.2 método toString() Outro método bastante utilizado da classe Object é o método toString. Este método é invocado pela máquina virtual toda vez que se deseja converter determinado objeto em String. O código da listagem 6.8 apresenta um exemplo de utilização do toString. Observe no método main o código: System.out.println(exemplo); Este código imprime o objeto e, ao ser convertido em String para a impressão, a máquina virtual executará o método toString para descobrir como fazer isto. Listagem 6.8: Exemplo de utilização do método toString 1 66 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 2 um pouco mais de orientação a objetos public class ExemploToString { 3 public String toString() { return "Exemplo da implementação do toString"; } 4 5 6 7 public static void main(String[] args) { ExemploToString exemplo = new ExemploToString(); System.out.println(exemplo); } 8 9 10 11 12 } 6.10. Polimorfismo Uma característica importante das classes reside no fato de que as subclasses de uma dada classe são consideradas do mesmo tipo de seu parente. Assim no exemplo anterior de Pessoa e Aluno, pode-se dizer que Aluno é do tipo Pessoa, ou seja, Aluno é uma Pessoa. Note que a herança define, desta forma, o relacionamento É UM. Nestes casos também é possível que exista a sobrescrita de métodos. Isto permite a realização de uma mesma operação sobre diferentes tipos de classes, desde que mantenham algo em comum. Este efeito se chama Polimorfismo. 6.10.1 Abstração Para que você entenda melhor a abstração veja um exemplo com o mundo real. Tome inicialmente algumas verdades: 1. Todo animal locomove; 2. Todo Peixe é um animal; 3. Todo Sapo é um animal; 4. Todo Tigre é um animal; Pergunta: Como o Animal Locomove? A resposta é complicada pois Peixes, Sapos e Tigres se locomovem de forma diferente. Na verdade a resposta é: depende. Mas, para cumprir a verdade 1, que todo animal se locomove, é necessário definir um método locomover em animal. Mesmo não sabendo ainda como este o faz: nadando, pulando ou correndo. É neste cenário que entra o conceito de abstração: Existe, mas não é possível saber como é, como é feito. Desta forma, o método locomover deve ser abstrato utilzando a palavra chave abstract. Para isto deve-se cumprir algumas regras: • Todo método abstrato não possui corpo, ou seja, no lugar dos vírgula: ;. http://solutioin.com Francisco Calaça, Otávio Calaça é colocado ponto- 67 Versão 1.2-beta um pouco mais de orientação a objetos • Quando uma classe possui pelo menos um método abstrato, esta também deve ser declarada como abstrata • As classes abstratas não podem ser instanciadas. • As classes filhas de uma classe abstrata devem, obrigatoriamente ou implementar os métodos abstratos da classe pai, ou também ser abstrata. 6.10.2 Exemplo de Polimorfismo Para explicar melhor o Polimorfismo veja o exemplo da folha de pagamento de uma empresa. O código da listagem 6.9 apresenta a classe Empregado. Observe que esta classe é abstrata (pelo modificador abstract na sua declaração). O método calcularSalario também é abstrato, pois apesar de todos os empregados possuirem salário, esta característica só poderá ser descrita se for possível saber o tipo de empregado: Assalariado, Comissionado ou Horista. A classe Empregado herda de Pessoa os atributos nome e telefone, não sendo mais necessários sua implementação. Essa classe também sobrescreve o método toString que define um comportamento personalizado quando for necessário a converssão de objetos do tipo Empregado em String. O código da listagem 6.10 apresenta a classe EmpregadoAssalariado. Esta classe herda de Empregado alguns métodos, inclusive os de Pessoa. É possível dizer que EmpregadoAssalariado é um Empregado e por consequencia, uma Pessoa. A classe EmpregadoAssalariado não é abstrata, logo deve obrigatoriamente implementar o método calcularSalario. Observe que, para EmpregadoAssalariado, é possível dizer como se calcula o salário. Basta retornar o salário mensal do empregado. O código da listagem 6.11 apresenta a classe EmpregadoComissionado. Esta classe também herda de Empregado alguns métodos. Note que o método calcularSalario de EmpregadoComissionado retorna o resultado da multiplicação das vendas brutas com o valor da comissão do empregado. O código da listagem 6.12 apresenta a classe EmpregadoHorista. Esta classe também é filha de Empregado. O seu método calcularSalario também é específico apenas para empregados que trabalham por hora. Até agora forão apresentadas quatro classes em nosso exemplo: • Empregado • EmpregadoAssalariado • EmpregadoComissionado • EmpregadoHorista Todos estes empregados são do tipo Pessoa. Os empregados assalariados, horistas e comissionados são do tipo empregados. Isto se deve por causa da herança. Para finalizar este exemplo será construída a classe FolhaPagamento, descrita na listagem 6.13. Obseve neste exemplo que todos os empregados são instanciados e colocados em um 68 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta um pouco mais de orientação a objetos array de tipos Empregado. Quando este array é iterado pelo for os dados salariais são impressos de acordo com o tipo de empregado. Isto é o polimorfismo: Apesar de todos os empregados possuirem o método calcularSalario, este se comporta de forma diferente em função do tipo do empregado. Polimorfismo quer dizer: várias formas de executar a mesma ação, ou seja, várias formas de executar o calcularSalario. Listagem 6.9: Código da classe Empregado 1 2 public abstract class Empregado extends PessoaFisica { 3 public Empregado(String nome, String telefone) { super(nome, telefone); } 4 5 6 7 public String toString() { return String.format("Nome:%s Telefone :%s getTelefone(), calcularSalario()); } 8 9 10 11 Salario :%.2f" , getNome(), 12 public abstract double calcularSalario(); 13 14 15 } Listagem 6.10: Código da classe EmpregadoAssalariado 1 2 public class EmpregadoAssalariado extends Empregado{ 3 private double salario; 4 5 public EmpregadoAssalariado(String nome, String telefone, double salario) { super(nome, telefone); this.salario = salario; } 6 7 8 9 10 public double calcularSalario() { return salario; } 11 12 13 14 public double getSalario() { return salario; } 15 16 17 18 public void setSalario(double salario) { this.salario = salario; } 19 20 21 22 } Listagem 6.11: Código da classe EmpregadoComissionado 1 http://solutioin.com Francisco Calaça, Otávio Calaça 69 Versão 1.2-beta 2 um pouco mais de orientação a objetos public class EmpregadoComissionado extends Empregado{ 3 private double vendasBrutas; private double comissaoVendas; public EmpregadoComissionado(String nome, String telefone, double vendasBrutas, double comissaoVendas) { super(nome, telefone); this.vendasBrutas = vendasBrutas; this.comissaoVendas = comissaoVendas; } 4 5 6 7 8 9 10 11 12 public double calcularSalario() { return vendasBrutas * comissaoVendas; } 13 14 15 16 public double getVendasBrutas() { return vendasBrutas; } 17 18 19 20 public void setVendasBrutas(double vendasBrutas) { this.vendasBrutas = vendasBrutas; } 21 22 23 24 public double getComissaoVendas() { return comissaoVendas; } 25 26 27 28 public void setComissaoVendas(double comissaoVendas) { this.comissaoVendas = comissaoVendas; } 29 30 31 32 } Listagem 6.12: Código da classe EmpregadoHorista 1 2 public class EmpregadoHorista extends Empregado{ 3 private int qtdHoras; private double valorHora; public EmpregadoHorista(String nome, String telefone, int qtdHoras, double valorHora) { super(nome, telefone); 4 5 6 7 8 9 this.qtdHoras = qtdHoras; this.valorHora = valorHora; 10 11 } 12 13 public double calcularSalario() { return qtdHoras * valorHora; } 14 15 16 17 public int getQtdHoras() { return qtdHoras; 18 19 70 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta um pouco mais de orientação a objetos } 20 21 public void setQtdHoras(int qtdHoras) { this.qtdHoras = qtdHoras; } 22 23 24 25 public double getValorHora() { return valorHora; } 26 27 28 29 public void setValorHora(double valorHora) { this.valorHora = valorHora; } 30 31 32 33 } Listagem 6.13: Código da classe FolhaPagamento 1 2 public class FolhaPagamento { 3 public static void main(String[] args) { Empregado [] empregados = new Empregado[3]; empregados[0] = new EmpregadoAssalariado("Maria", "231 -1234", 1500); empregados[1] = new EmpregadoComissionado("Antonio", "241 -9876", 5000, 0.25); empregados[2] = new EmpregadoHorista("Jose", "241 -9876", 40, 50); 4 5 6 7 8 9 for (int i = 0; i < empregados.length; i++) { System.out.println(empregados[i]); } 10 11 12 13 } 14 15 16 } 6.11. Conversão e casting Após ter sido colocados, no exemplo da seção anterior, todos os empregados no Array empregados como pode ser obtido o valor da comissão do empregado comissionado? Observe que dentro do laço for isto não é mais possível pois todos os empregados são tratados como do tipo Empregado. Para isto existe o casting. A tradução de casting é atuar. Com o casting é possível fazer o Empregado atuar como EmpregadoComissionado e assim buscar o valor da comissão. Assim como nos filmes não é qualquer ator que pode atuar em um determinado papel, também não será qualquer objeto que poderá atuar como EmpregadoComissionado, apenas aqueles que foram instanciados como tal. O casting é feito colocando o tipo desejado dentro de parêntesis na frente do objeto: EmpregadoComissionado empComiss = (EmpregadoComissionado) empregados[i]; http://solutioin.com Francisco Calaça, Otávio Calaça 71 Versão 1.2-beta 6.11.1 um pouco mais de orientação a objetos A palavra-chave instanceof Para testar o objeto é instancia de determinada classe e consequentemente pode ser feito uma operação de casting dele para essa classe é utilizado a palavra-chave instanceof. O código da listagem 6.14 apresenta um exemplo de utilização do operador instanceof. Observe o teste do objeto empregados[i]. Este teste retornará true se esse objeto for do tipo EmpregadoComissionado. if(empregados[i] instanceof EmpregadoComissionado){ . . . } Listagem 6.14: Exemplo de utilização do operador instanceof 1 2 public class FolhaPagamentoMelhorado { 3 public static void main(String[] args) { Empregado [] empregados = new Empregado[3]; empregados[0] = new EmpregadoAssalariado("Maria", "231 -1234", 1500); empregados[1] = new EmpregadoComissionado("Antonio", "241 -9876", 5000, 0.25); empregados[2] = new EmpregadoHorista("Jose", "241 -9876", 40, 50); 4 5 6 7 8 9 for (int i = 0; i < empregados.length; i++) { System.out.println(empregados[i]); if(empregados[i] instanceof EmpregadoComissionado){ EmpregadoComissionado empComiss = (EmpregadoComissionado) empregados[i]; System.out.printf("\nEmpregado comissionado , comissão: %d", empComiss.getComissaoVendas()); } System.out.println(); } 10 11 12 13 14 15 16 17 18 19 } 20 21 22 } 6.12. Métodos e classe do tipo final Em uma seção anterior foi apresentado que variáveis do tipo final representam constantes. O modificador final também pode ser usando em classes e em métodos. Uma classe do tipo final não pode ser herdada, ou seja, não pode ter sub-classes. Um método do tipo final não pode ser sobrescrito. 72 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 6.13. um pouco mais de orientação a objetos Interfaces Interfaces são equivalentes a classes com todos os métodos abstratos. A palavra chave interface é utilizada para declara-la. Há um vários motivos na engenharia de software onde é importante que os programadores concordem com um contrato que diz como determinados componentes de software se comunicarão. Cada grupo precisa estar habilitado a escrever código sem o conhecimento de como este trabalha. Geralmente estes contratos são as interfaces. É como dirigir! Vários tipos de motoristas, em locais diferentes do mundo, é capaz de dirigir qualquer carro sem conhecer como este funciona. Porque para os motoristas basta conhcecer a interface que faz o carro funcionar. Para o motorista, basta saber que o freio, acelerador, câmbio, etc, se comportarão conforme ele espera. Não é necessário saber se o carro possui direção elétrica ou hidráulica, como foi implementado os freios ou se o motor funciona com combustíveis renováveis ou não. Basta conhecer a interface de comunicação que é oferecida ao motorista. Outro exemplo são os eletrodomésticos. Quando você adquire um eletrodoméstico, como um liquidificador, não é necessário preocupar-se se os plugues deste servirá nas tomadas de nossas casas. Existe a certeza que sim porque o fabricante do eletrodoméstico construiu o plugue de acordo com a interface das tomadas residenciais. 6.13.1 Interfaces em Java Em Java as interfaces também são tipos de dados similar às classes. As interfaces contém apenas constantes, e assinaturas de métodos. Os métodos não possuem corpo. Interfaces não podem ser instanciadas. São somente implementadas por classes ou herdadas de outras interfaces. O código da listagem 6.15 apresenta um exemplo de interface. Note o uso da palavrachave interface e que os métodos desta não possuem corpo, apenas estão declarados. Os códigos das listagens 6.17 e 6.16 apresentam as classes que implementam a interface Animal. Observe o uso da palavra chave implements. Na listagem 6.18 é apresentado a utilização das interfaces. Note o uso do método newInstance para instanciação das classes. Nesta classe é apresentado um prompt para o usuário indagando-o qual animal deseja instanciar. Após a instanciação do animal é executado os métodos alimentar e locomover deste. Não se preocupe com o uso das palavras-chaves: try e catch. Apenas utilize conforme o exemplo. Em um capítulo posterior será apresentado mais detalhes sobre estas palavras. Listagem 6.15: Interface Animal 1 2 3 public interface Animal { 4 5 6 void alimentar(); void locomover(); 7 http://solutioin.com Francisco Calaça, Otávio Calaça 73 Versão 1.2-beta 8 um pouco mais de orientação a objetos } Listagem 6.16: Classe Aguia para o exemplo de interfaces 1 2 3 public class Aguia implements Animal{ 4 public void alimentar() { System.out.println("A águia caça a sua presa em voo e a devora!"); } 5 6 7 8 public void locomover() { System.out.println("A águia se locomove voando!"); } 9 10 11 12 @Override public String toString() { return "Aguia"; } 13 14 15 16 17 } Listagem 6.17: Classe Tigre para o exemplo de interfaces 1 2 3 public class Tigre implements Animal{ 4 public void alimentar() { System.out.println("O tigre caça a sua presa e a devora!"); } 5 6 7 8 public void locomover() { System.out.println("O tigre se locomove correndo!"); } 9 10 11 12 @Override public String toString() { return "Tigre"; } 13 14 15 16 17 18 } Listagem 6.18: Exemplo da aplicação de interfaces 1 2 3 4 public class Zoo { 5 public static void main(String[] args) { Animal [] animais = new Animal[2]; animais[0] = new Aguia(); 6 7 8 74 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta um pouco mais de orientação a objetos animais[1] = new Tigre(); for (Animal a : animais) { System.out.println(a); a.alimentar(); a.locomover(); } 9 10 11 12 13 14 15 } 16 17 18 } Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 6.14. Exercícios 1. O que é o coletor de lixo? 2. Explique a referência this. 3. O que é encapsulamento? 4. O que são enumerações? Crie um Enum para representar o estado civil. 5. O que são pacotes? 6. Qual a relação entre pacotes e diretórios? 7. O que é herança? 8. O que é sobrescrita de métodos? 9. Explique a palavra chave super. 10. Qual a diferença entre a palavra-chave super e a palavra-chave this? 11. Explique o modificador de acesso protected. 12. O que é a classe Object? 13. Qual a diferença entre utilizar == e equals para comparar objetos? 14. Para que serve o método toString? 15. O que é polimorfismo? 16. O que é casting? http://solutioin.com Francisco Calaça, Otávio Calaça 75 Versão 1.2-beta um pouco mais de orientação a objetos 17. Explique a utilidade do operador instanceof. 18. O que são interfaces? 76 http://solutioin.com Francisco Calaça, Otávio Calaça 7 T R ATA M E N T O D E E X C E Ç Õ E S Os aplicativos devem estar preparados para resolver situações inesperadas como quando um usuário digita um campo texto onde devia ser numérico ou uma data fora do padrão. Nestes casos ocorrem exceções à forma normal da execução da rotina. Neste capítulo será apresentado o mecanismo de exceções do Java, as palavras chaves try cath throw e throws. 7.1. O que são exceções Uma exceção é um evento, que ocorre durante a execução de um programa, e interrompe o fluxo normal deste. Quando ocorre uma exceção em um método, este cria um objeto que contem informaçoes sobre o tipo de exceção, ou erro, incuido o seu tipo, o estado do programa, a pilha de chamada de métodos. Quando é criada uma exceção esta deve ser lançada para que possa ser capturada em um local específico. Depois do método ter laçado uma exceção, a execução do sistema procurará, na pilha de chamada de métodos, algum bloco de código que poderá manipular essa exceção. As instruções que serão executadas para manipular determinada exceção deve ser escrito dentro de blocos catch (Em inglês, capturas). Se não for encontrado um bloco catch apropriado para tratar a exceção, o programa terminará. 7.2. Como tratar exceções 7.2.1 O bloco try O primeiro passo para tratar exceções é envolver o código que pode lançar uma com um bloco try. Em geral, o bloco try é escrito da seguinte forma: try { código que pode lançar exeção } catch(Exception e){ código que será exeucutado quando uma exceção ocorrer. } Observe que todo o código que poderá lançar alguma exceção é colocado dentro de um bloco try. 77 Versão 1.2-beta tratamento de exceções 7.2.2 O bloco catch As exceções são associadas a tipos. Mais adiante você saberá sobre estes tipos. Qualquer erro que pode ocorrer dentro de um bloco try poderá ser capturado por um bloco catch. Neste bloco deve ficar todo o código necessário ao tratamento de determinada exceção como, por exemplo, apresentar uma mensagem de erro ao usuário. O código da listagem 7.1 apresenta um exemplo de código em que pode acontecer os seguintes erros: • O usuário pode informar um valor não numérico. • O usuário pode informar zero no denominador. Como exercício, escreva este código e execute. Tente executá-lo passando informações incorretas, como zero no denominador, ou valores não numéricos. Para tratar estes erros adequadamente utilize o bloco try . . . catch. O código da listagem 7.2 apresenta o código da listagem 7.1 com tratamento de erros. Observe que os possíveis locais para ocorrencia de erros são: int numerador = new Integer(numeradorString); int denominador = new Integer(denominadorString); Quando o usuário informar um valor não numérico e este o programa tentar converte-lo para int. outro local: int quociente = numerador / denominador; int resto = numerador % denominador; Quando o usuário informar ZERO como denominador. Para tratar estes dois possíveis erros estes códigos foram envolvidos com o bloco try e os blocos catch’s responsáveis pelo tratamento de cada erro específico: catch (NumberFormatException e) { showMessageDialog(null, "Informe apenas números inteiros."); } catch (ArithmeticException e) { showMessageDialog(null, "O denominador não pode ser ZERO."); } Observe que é possível colocar quantos blocos catch’s quantos forem necessários e que as exceções possuem tipos, neste caso, NumberFormatException para erros de formatação numérica e ArithmeticException para erros de aritimética, como divisão por zero. Em cada bloco catch foi adicionado o código necessário para tratar este tipo de erro, neste caso, apenas a apresentação de uma mensagem ao usuário. 78 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta tratamento de exceções Listagem 7.1: Exemplo de código que poderá lançar uma exceção 1 package capitulo7; 2 3 import javax.swing.JOptionPane; 4 5 public class Divisao { 6 public static void main(String[] args) { String numeradorString = JOptionPane.showInputDialog("Digite o númerador:"); String denominadorString = JOptionPane.showInputDialog("Digite o denominador:"); 7 8 9 10 int numerador = new Integer(numeradorString); int denominador = new Integer(denominadorString); 11 12 13 int quociente = numerador / denominador; int resto = numerador % denominador; 14 15 16 String texto = String.format("Quociente :%d, Resto:%d", quociente, resto); 17 18 19 JOptionPane.showMessageDialog(null, texto); 20 } 21 22 } Listagem 7.2: Exemplo do tratamento de exceções 1 package capitulo7; 2 3 import javax.swing.JOptionPane; 4 5 public class DivisaoMelhorado { 6 7 8 9 public static void main(String[] args) { String numeradorString = JOptionPane.showInputDialog("Digite o númerador:"); String denominadorString = JOptionPane.showInputDialog("Digite o denominador:"); 10 11 12 13 try { int numerador = new Integer(numeradorString); int denominador = new Integer(denominadorString); 14 15 16 int quociente = numerador / denominador; int resto = numerador % denominador; 17 18 19 String texto = String.format("Quociente :%d, Resto:%d", quociente, resto); 20 21 22 23 24 25 26 JOptionPane.showMessageDialog(null, texto); } catch (NumberFormatException e) { JOptionPane.showMessageDialog(null, "Informe apenas números inteiros."); } catch (ArithmeticException e) { JOptionPane.showMessageDialog(null, "O denominador não pode ser ZERO."); } http://solutioin.com Francisco Calaça, Otávio Calaça 79 Versão 1.2-beta } 27 28 tratamento de exceções } 7.3. Exceções checadas e exceções não checadas O Java possui dois tipos de exceções: • as checadas em tempo de compilação; • as não checadas em tempo de compilação; As exceções checadas em tempo de compilação devem, obrigatoriamente, serem tratadas na compilação, ou seja, o uso do try . . . catch é obrigatório. Em capítulos posteriores serão apresentados elementos que lançam exceções que possuem essa característica - obrigatoriedade no tratamento. As exceções não checadas em tempo de compilação não possuem obrigatoriedade no seu tratamento. As exceções apresentadas no código da listagem 7.2 não possuem esta obrigatoriedade. Todas as exceções não checadas devem herdar de RuntimeException ou suas subclasses. Porque os projetistas decidem em forçar um método a lançar uma exceção? Qualquer exceção checada pode ser lançada por um método como parte da lógica do método como tratamento de erros de usuário, etc. A próxima questão é: Se é interessante lançar exceções checadas e obrigar o tratamento no código, porque lançar exceções que herdam de RuntimeException, ou seja, exeções não checadas? A resposta é que qualquer exceção não checada representa um erro do sistema, como divisão por zero, acesso a elementos inexistentes de arrays, etc. Em Geral, não lance uma RuntimeException ou sua subclasse simplesmente porque você não quer obrigar o tratamento de determinado problema. Uma boa regra para lançamento de exceções é: Se a aplicação cliente pode resolver o problema lance uma exceção checada em tempo de compilação. Se a aplicação cliente não pode resolver, lance uma exceção não checada em tempo de compilação. 7.4. Como declarar novos tipos de exceções Toda exceção deve, obrigatoriamente, herdar de Exception. O código da listagem 7.3 apresenta um exemplo. Lembre-se que quando a exceção herda de RuntimeException (que é subclasse de Exception) esta torna-se uma exceção não checada. Se a exceção não herdar de RuntimeException (ou suas subclasses) ela passa a ser uma exceção checada. Observe que a classe Exception herda de Throwable, ou seja, toda exceção é do tipo throwable. Listagem 7.3: Exemplo de declaração de uma nova exceção 1 package capitulo7; 2 80 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 3 tratamento de exceções public class AutenticacaoException extends Exception{ 4 public AutenticacaoException(String mensagem) { super(mensagem); } 5 6 7 8 9 } 7.5. Como lançar exceções É utilizada a palavra chave throw para lançar uma exceção: throw new AutenticacaoException("Erro ao realizar a autenticação"); Observe que a expressão throw necessita apenas de um argumento: O objeto do tipo Throwable. O código da listagem 7.4 mostra um exemplo. Observe o método autenticar. Ele verifica duas coisas: Se o login estiver vazio e se a senha e o login informado estão corretos. Note que para cada tipo de problema é lançada a Exceção AutenticacaoException com uma mensagem apropriada. O método main invoca o método autenticar e este captura as exceções do tipo AutenticacaoException mostrando a mensagem para o usuário. Listagem 7.4: Exemplo de lançamento de uma exceção 1 package capitulo7; 2 3 import javax.swing.JOptionPane; 4 5 public class Autenticador { 6 7 8 9 10 11 12 13 public static void autenticar(String login, String senha) throws AutenticacaoException{ /* * Verifica se o usuário digitou um login. */ if(login.length() == 0){ throw new AutenticacaoException("Login vazio"); } 14 /* * Verifica o login e a senha do usuário. * Esta verificação normalmente é feita com dados vindos de um Banco de Dados * ou LDAP. Colocamos o usuario e a senha no código para facilitar * o entendimento. */ if(!"java".equals(login) || !"123".equals(senha)){ throw new AutenticacaoException("Usuário ou senha inválidos"); } 15 16 17 18 19 20 21 22 23 24 } http://solutioin.com Francisco Calaça, Otávio Calaça 81 Versão 1.2-beta tratamento de exceções 25 public static void main(String[] args) { String login = JOptionPane.showInputDialog("Digite o Login:"); String senha = JOptionPane.showInputDialog("Digite a Senha:"); try { autenticar(login, senha); JOptionPane.showMessageDialog(null, "Autenticado"); } catch (AutenticacaoException e) { JOptionPane.showMessageDialog(null, e.getMessage()); } } 26 27 28 29 30 31 32 33 34 35 36 37 } 7.6. Hierarquia das exceções A Hierarquia das exceções é apresentada na figura 7.1. A classe pai de todas as Exceções é Throwable. Observe que existem duas derivações: Exception e Error. Error são erros não tratáveis em código como falta de memória. Exception são exceções tratáveis. A classe Exception possui uma subclasse especial: RuntimeException. Todas as exceções que derivam de RuntimeException são exceções não verificadadas (nao existe obrigtoriedade no seu tratamento). As outras exceções, que não herdam de RuntimeException, mas são subclasses de Exception são exceções verificadas (existe a obrigatoriedade no seu tratamento). Figura 7.1: Hierarquia da exceções 82 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta tratamento de exceções Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 7.7. Exercícios 1. Explique o que são exceções. 2. Qual a utilidade do bloco try? 3. Explique o bloco catch. 4. Qual a diferença entre exceões checadas e exceções não checadas? 5. Como criar novas exceções? 6. Qual a palavra chave utilizada para lançar novas exeções? http://solutioin.com Francisco Calaça, Otávio Calaça 83 8 FLUXO DE DADOS No mundo corporativo é vital a transferência de informações entre computadores. Esta troca é feita através de fluxos de informação. Qualquer troca de dados, como rede, arquivos, dispositivos IO é vista como um fluxo de dados em Java. Este capítulo apresentará exemplos de fluxo de dados de arquivos e de rede com a construção de um editor de texto simples e a construção de um trocador de mensagens entre computadores. Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 8.1. A classe File A classe File existe para representar um arquivo. Ela não é utilizada para escrever, ler, ou alterar arquivos. Simplesmente para representá-los. Possui um construtor onde é informado a localização do arquivo: File arquivo = new File(‘‘c:\\arquivo.txt’’) 8.2. Como escrever em arquivos Para escrever em arquivos será utilizada a classe Formatter do pacote java.util. Existem outras formas de escrever em um arquivo utilizando classes como FileWriter, DataOutputStream, etc. Para entender os exemplos preocupe-se apenas com a classe Formatter. O código da listagem 8.1 apresenta um exemplo de escrita em arquivos. Note o uso da classe Formatter para realizar a escrita. Nesse exemplo também foi utilizado a classe File. Observe o uso do método close(). Este método fecha o fluxo. Nunca se esqueça dele. Listagem 8.1: Exemplo de escrita em arquivos 1 package capitulo8; 2 3 4 5 import java.io.File; import java.io.FileNotFoundException; import java.util.Formatter; 85 Versão 1.2-beta fluxo de dados 6 7 8 public class ExemploEscrita { 9 public static void main(String[] args) { File arquivo = new File("c:\\ arquivo.txt"); try { Formatter fluxo = new Formatter(arquivo); fluxo.format("Exemplo de escrita do capitulo 10"); fluxo.close(); System.out.println("Arquivo criado ..."); } catch (FileNotFoundException e) { e.printStackTrace(); } } 10 11 12 13 14 15 16 17 18 19 20 21 22 } 8.3. Como ler arquivos Para ler um arquivo texto será utilizada a classe Scanner do pacote java.util. Como na escrita existem outras formas de ler arquivos. Para entender os exemplos preocupe-se apenas com a classe Scanner. O código da listagem 8.2 apresenta um exemplo de leitura de arquivos. Note o uso da classe Scanner para ler o arquivo. Assim como no exemplo de escrita, a classe File foi utilizada para representar um arquivo. Após a leitura do arquivo não se esqueça de fechar o fluxo com o método close(). Listagem 8.2: Exemplo de leitura em arquivos 1 package capitulo8; 2 3 4 5 import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; 6 7 public class ExemploLeitura { 8 public static void main(String[] args) { File arquivo = new File("c:\\ arquivo.txt"); System.out.println("Lendo arquivo :\n"); try { Scanner fluxo = new Scanner(arquivo); while(fluxo.hasNext()){ System.out.println(fluxo.nextLine()); } fluxo.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } 9 10 11 12 13 14 15 16 17 18 19 20 86 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta fluxo de dados } 21 22 23 } 8.4. Um editor de texto simples Este tópico apresentará um editor de texto que reunirá todos os conhecimentos apresentados até agora. O código está na listagem 10.6. O código: Container c = getContentPane(); c.setLayout(new BorderLayout()); c.add(botaoAbrir, BorderLayout.NORTH); c.add(botaoSalvar, BorderLayout.SOUTH); c.add(new JScrollPane(areaTexto), BorderLayout.CENTER); cria a tela. Note o uso da classe BorderLayout. Esta classe define um layout que posiciona componentes com informações NORTH para o topo, SOUTH para colocar algo abaixo, CENTER para colocar algo no centro, etc. A tela do editor de texto é apresenta na figura 10.6. O código: botaoAbrir.addActionListener(this); botaoSalvar.addActionListener(this); adiciona o listener de evento nos botões. Neste exemplo a classe JFileChooser foi utilizada para criar a tela de escolha de arquivos: para salvar ou para abrir. Figura 8.1: Tela do editor de Texto Listagem 8.3: Editor de texto simples http://solutioin.com Francisco Calaça, Otávio Calaça 87 Versão 1.2-beta 1 2 3 4 5 6 7 8 9 10 fluxo de dados package capitulo8; import java.awt.BorderLayout; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.FileNotFoundException; import java.util.Formatter; import java.util.Scanner; import java.util.StringTokenizer; 11 12 13 14 15 16 17 import import import import import import javax.swing.JButton; javax.swing.JFileChooser; javax.swing.JFrame; javax.swing.JOptionPane; javax.swing.JScrollPane; javax.swing.JTextArea; 18 19 20 21 22 public class EditorTexto extends JFrame implements ActionListener{ JButton botaoAbrir = new JButton("Abrir"); JButton botaoSalvar = new JButton("Salvar"); JTextArea areaTexto = new JTextArea(); 23 24 25 public EditorTexto(){ Container c = getContentPane(); 26 c.setLayout(new BorderLayout()); c.add(botaoAbrir, BorderLayout.NORTH); c.add(botaoSalvar, BorderLayout.SOUTH); c.add(new JScrollPane(areaTexto), BorderLayout.CENTER); 27 28 29 30 31 botaoAbrir.addActionListener(this); botaoSalvar.addActionListener(this); 32 33 34 setTitle("Editor de Texto"); setSize(800,600); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); 35 36 37 38 39 } 40 41 42 public void actionPerformed(ActionEvent e) { JFileChooser jfc = new JFileChooser(); 43 try { if(e.getSource() == botaoAbrir){ jfc.showOpenDialog(this); File file = jfc.getSelectedFile(); abrirArquivo(file); }else if(e.getSource() == botaoSalvar){ jfc.showSaveDialog(this); File file = jfc.getSelectedFile(); salvarArquivo(file); 44 45 46 47 48 49 50 51 52 88 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta fluxo de dados } }catch (FileNotFoundException e1) { JOptionPane.showMessageDialog(null, "Arquivo não encontrado!"); } 53 54 55 56 } 57 58 private void salvarArquivo(File file) throws FileNotFoundException{ Formatter saida = new Formatter(file); StringTokenizer token = new StringTokenizer(areaTexto.getText(), "\n"); while(token.hasMoreElements()){ saida.format("%s%n", token.nextElement()); } saida.close(); } 59 60 61 62 63 64 65 66 67 private void abrirArquivo(File file) throws FileNotFoundException{ String texto = ""; Scanner scan = new Scanner(file); while(scan.hasNext()){ texto += scan.nextLine() + "\n"; } areaTexto.setText(texto); scan.close(); } 68 69 70 71 72 73 74 75 76 77 public static void main(String[] args) { new EditorTexto(); } 78 79 80 81 } 8.5. Serialização de objetos Até agora os fluxos apresentados foram apenas de String. É possível também trafegar objetos em fluxos de dados. Objetos Java podem ser salvos em arquivos, transmitido pela rede, etc. Para que os objetos possam ser transmitidos de um lugar para o outro é necessário que eles implementem a interface Serializable do pacote java.util. Quando a classe implementa esta interface é necessário criar um atributo: private static final long serialVersionUID = 1L; para que não haja problemas com versões de classes. Esta é a única garantia que o objeto trafegado, apesar de estar com os pacotes, métodos, etc idênticos possuam a mesma versão de suas classes nos computadores envolvidos. O eclipse possui um assistente para criar este atributo. http://solutioin.com Francisco Calaça, Otávio Calaça 89 Versão 1.2-beta 8.6. fluxo de dados Um trocador de mensagens simples O próximo exemplo será de um trocador de mensagens. A mensagem trafegará atravéz de objetos da classe Mensagem apresentada na listagem 8.4. Observe que esta classe implementa a interface Serializable e possui o atributo: private static final long serialVersionUID = 1L; não se preocupe em criar este atributo. Peça para o eclipse criar para você. A classe Enviador, apresentada na listagem 8.5 envia as mensagens. O código responsável por isto é: Socket socket = new Socket("127.0.0.1", 12345); ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); oos.writeObject(mens); a classe Socket cria uma comunicação com o ip 127.0.0.1 (que é a sua máquina local) na porta 12345. A classe ObjectOutputStream cria um fluxo de dados de saida e utiliza o socket criado na linha anterior. O método writeObjetct(mens) escreve o objeto no fluxo criado na linha anterior. A classe Receptor, apresentada na listagem 8.6 recebe as mensagens e as imprime no console. Note que esta classe possui um laço infinito while(true). Este laço fará com que o receptor receba mensagens enquanto estiver rodando. server = new ServerSocket(12345); Socket socket = server.accept(); ObjectInput ois = new ObjectInputStream(socket.getInputStream()); Mensagem mens = (Mensagem) ois.readObject(); System.out.println(mens); a classe ServerSocket cria um socket na máquina e abre a porta 12345 (esta deverá estar disponível). O método server.accept() aguarda até alguém enviar uma mensagem por meio destar porta (lembre-se do Enviador que enviará mensagens por esta porta). Foi utilizado o método readObject() para ler o objeto que está sendo trafegado, no caso, Mensagem. Listagem 8.4: Classe Mensagem 1 package capitulo8; 2 3 import java.io.Serializable; 4 5 public class Mensagem implements Serializable { 6 private static final long serialVersionUID = 1; 7 8 private String remetente; private String descricao; 9 10 90 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta fluxo de dados 11 public String getDescricao() { return descricao; } 12 13 14 15 public void setDescricao(String descricao) { this.descricao = descricao; } 16 17 18 19 public String getRemetente() { return remetente; } 20 21 22 23 public void setRemetente(String remetente) { this.remetente = remetente; } 24 25 26 27 public String toString() { return String.format("%-30s-%s", remetente, descricao); } 28 29 30 31 } Listagem 8.5: Classe que envia mensagens 1 package capitulo8; 2 3 4 5 6 import import import import java.io.IOException; java.io.ObjectOutputStream; java.net.Socket; java.net.UnknownHostException; 7 8 import javax.swing.JOptionPane; 9 10 11 12 13 14 15 16 17 public class Enviador { public static void main(String[] args) { String resposta; do { resposta = JOptionPane.showInputDialog("Mensagem:"); Mensagem mens = new Mensagem(); mens.setRemetente("Seu Nome"); mens.setDescricao(resposta); 18 19 20 21 22 23 24 25 26 27 28 try { Socket socket = new Socket("127.0.0.1", 12345); ObjectOutputStream oos = new ObjectOutputStream(socket .getOutputStream()); oos.writeObject(mens); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } 29 http://solutioin.com Francisco Calaça, Otávio Calaça 91 Versão 1.2-beta } while (!resposta.equals("sair")); 30 } 31 32 fluxo de dados } Listagem 8.6: Receptor de mensagens 1 package capitulo8; 2 3 4 5 6 import import import import java.io.ObjectInput; java.io.ObjectInputStream; java.net.ServerSocket; java.net.Socket; 7 8 public class Receptor { 9 public static void main(String[] args) { ServerSocket server = null; while (true) { try { server = new ServerSocket(12345); Socket socket = server.accept(); 10 11 12 13 14 15 16 ObjectInput ois = new ObjectInputStream(socket.getInputStream()); Mensagem mens = (Mensagem) ois.readObject(); System.out.println(mens); 17 18 19 20 ois.close(); socket.close(); server.close(); } catch (Throwable e) { e.printStackTrace(); } finally { try { server.close(); } catch (Exception e) { e.printStackTrace(); } } 21 22 23 24 25 26 27 28 29 30 31 32 33 } 34 } 35 36 37 } 92 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 8.7. fluxo de dados Exercícios Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 1. Qual a utilidade da classe File? 2. Descreva o processo para escrita em arquivos. 3. Descreva o processo para leitura de arquivos. 4. O que é serialização de objetos? 5. Na serialização de objetos para que serve o atributo serialVersionUID? http://solutioin.com Francisco Calaça, Otávio Calaça 93 9 GENÉRICOS E COLEÇÕES Em um capítulo anterior foi abordado os Arrays. Um dos problemas dos arrays é a impossibilidade de alterar seu tamanho. Neste capítulo serão abordadas outras coleções como Listas, Conjuntos e Mapas. Estas coleções permitem ter seu tamanho alterado em tempo de execução e se comportam de forma diferente se aproximando ao comportamento do mundo real. 9.1. o que são genéricos Genéricos existem para diminuir os erros de Conversão de classes do tipo ClassCastExceptions. Veja o código da listagem 9.1. Esta listagem apresenta a classe Caixa que pode aceitar qualquer tipo de objeto. A listagem 9.2 mostra o uso dessa classe. Observe na listagem 9.3 um erro comum. Apesar da caixa aceitar qualquer tipo de objetos, são esperados apenas objetos do tipo Integer o que, por falta de atenção, pode ser de outros tipos (a caixa aceita qualquer tipo de dados). Com Generics é possível restringir os tipos para tipos específicos. O código da listagem 9.4 apresenta a nova caixa, com suporte a generics. Observe, na listagem 9.5 que, na declaração da caixa, é possível informar qual o tipo de objetos que a caixa conterá, assim evitando erros de conversão. Voltando ao código da CaixaGenérica (listagem 9.4) note a declaração da classe: public class CaixaGenerica <E> observe o uso de: < E >. Este trecho de código Especifica que tudo o que for informado dentro das chaves < ... > será considerado apenas como E. No código da listagem 9.5 foi colocado < Integer >, ou seja, onde tiver “E” será considerado “Integer”. Assim o método: public void setObjeto(E objeto) será considerado: public void getObjeto(Integer objeto) Se, na declaração da classe CaixaGenérica for utilizado < String > onde tiver < E > será considerado como String. Assim, evita-se erros de conversão por ser possível informar o tipo que estará na caixa no moment da sua declaração. 95 Versão 1.2-beta genéricos e coleções Listagem 9.1: Classe Caixa 1 2 package capitulo9; public class Caixa { 3 private Object objeto; 4 5 public Object getObjeto() { return objeto; } 6 7 8 9 public void setObjeto(Object objeto) { this.objeto = objeto; } 10 11 12 13 14 } Listagem 9.2: Classe CaixaDemo1 1 2 3 package capitulo9; public class CaixaDemo1 { public static void main(String[] args) { 4 Caixa caixaDeInteiros = new Caixa(); 5 6 caixaDeInteiros.setObjeto(10); Integer someInteger = (Integer) caixaDeInteiros.getObjeto(); System.out.println(someInteger); 7 8 9 } 10 11 } Listagem 9.3: Classe CaixaDemo2 1 2 3 package capitulo9; public class CaixaDemo2 { public static void main(String[] args) { 4 Caixa caixaDeInteiros = new Caixa(); 5 6 /* * note que estamos adicionando String na caixa * propositalmente para provocar um erro de conversão */ 7 8 9 10 11 caixaDeInteiros.setObjeto("10"); 12 13 Integer someInteger = (Integer) caixaDeInteiros.getObjeto(); System.out.println(someInteger); 14 15 } 16 17 } Listagem 9.4: Classe CaixaGenerica 96 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 1 2 genéricos e coleções package capitulo9; public class CaixaGenerica <E>{ 3 private E objeto; 4 5 public E getObjeto() { return objeto; } 6 7 8 9 public void setObjeto(E objeto) { this.objeto = objeto; } 10 11 12 13 14 } Listagem 9.5: Classe CaixaGenericaDemo 1 2 3 package capitulo9; public class CaixaGenericaDemo { public static void main(String[] args) { 4 CaixaGenerica<Integer> caixaDeInteiros = new CaixaGenerica<Integer>(); 5 6 caixaDeInteiros.setObjeto(10); Integer someInteger = caixaDeInteiros.getObjeto(); System.out.println(someInteger); 7 8 9 } 10 11 } 9.2. Introdução a coleções Uma coleção é um objeto que representa um grupo de objetos facilitando a manipulação destes. Existem várias formas de reunir informações: • Listas • Conjuntos • Mapas • Filas • Pilhas 9.3. Listas As Listas apresentam as seguintes características: • Podem conter elementos duplicados http://solutioin.com Francisco Calaça, Otávio Calaça 97 Versão 1.2-beta genéricos e coleções • Podem ser ordenadas Para exemplificar, compare com as listas do mundo real. Pense em uma lista de compras que você fará em um supermercado. Os elementos desta lista podem ser ordenados, seguindo um critério qualquer. Outro detalhe é que os elementos desta lista podem ser duplicados. A interface List é a interface de todas as listas. Implementam esta interface as classes ArrayList e Vector. O código da listagem 9.6 apresenta um exemplo do uso de listas. Note o uso da interface List para declarar as listas. Neste exemplo foi utilizada a classe ArrayList para instanciar a lista. O código: Collections.sort(cores); ordena a lista de cores em ordem alfabética. Listagem 9.6: Exemplo de uso de Lista 1 2 3 4 package capitulo9; import java.util.ArrayList; import java.util.Collections; import java.util.List; 5 6 7 8 9 10 11 12 13 14 15 16 public class ExemploLista { public static void main(String[] args) { List<String> cores = new ArrayList<String>(); cores.add("Azul"); cores.add("Vermelho"); cores.add("Preto"); cores.add("Cinza"); cores.add("Laranja"); cores.add("Amarelo"); cores.add("Verde"); cores.add("Azul"); 17 for(String c : cores){ System.out.printf("Cor: %s\n",c); } 18 19 20 21 Collections.sort(cores); System.out.println("Cores após ordenação"); for(String c : cores){ System.out.printf("Cor: %s\n",c); } 22 23 24 25 26 27 } 28 29 } 98 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 9.4. genéricos e coleções Conjuntos Os conjuntos apresentam as seguintes características: • Não podem conter elementos duplicados • Não podem ser ordenados Para exemplificar, pense no conjunto de laranjas em uma sacola. Não é possível dizer qual é a primeira laranja, ou seja, não é possível ordena-las. Também não é possível duplicar laranjas. Cada laranja é única. Os conjuntos são definidos pela interface Set. Implementam esta interface as classes HashSet e TreeSet. O código da listagem 9.7 apresenta um exemplo do uso de conjuntos. Observe o uso da interface Set para declarar o conjunto. Neste exemplo foi utilizada a classe HashSet para instanciar o conjunto. Nessa listagem foram inseridas, propositalmente, duas entradas para a cor azul. Após a execução desta classe, observe que a saída do programa imprime a cor azul apenas uma vez. Isto demonstra a incapacidade dos conjuntos em conter elementos duplicados. Note também que a ordem impressa não é igual a ordem inserida no código. Listagem 9.7: Exemplo de uso de Conjuntos 1 2 3 package capitulo9; import java.util.HashSet; import java.util.Set; 4 5 6 7 8 9 10 11 12 13 public class ExemploConjunto { public static void main(String[] args) { Set<String> cores = new HashSet<String>(); cores.add("Azul"); cores.add("Vermelho"); cores.add("Preto"); cores.add("Amarelo"); cores.add("Verde"); cores.add("Azul");//Repetido propositalmente 14 for(String c : cores){ System.out.printf("\nCor: %s",c); } 15 16 17 } 18 19 } 9.5. Mapas Os mapas apresentam as seguintes características: • Associam chaves a valores http://solutioin.com Francisco Calaça, Otávio Calaça 99 Versão 1.2-beta genéricos e coleções • As chaves não podem ser repetidas O código da listagem 9.8 apresenta um exemplo do uso de mapas. Assim como nos exemplos de Listas e Conjuntos, foi utilizada uma interface para referenciar, no caso Map. Uma das classes que implementa esta interface é a classe HashMap. Observe nesse exemplo a associação de vegetações com regiões brasileiras. Se for adicionado uma outra chave “cerrado”, por exemplo, esta sobrescreverá a existente pois nos mapas não podem existir chaves duplicadas. Listagem 9.8: Exemplo de uso de Mapas 1 2 3 package capitulo9; import java.util.HashMap; import java.util.Map; 4 5 import javax.swing.JOptionPane; 6 7 8 9 public class ExemploMapa { public static void main(String[] args) { Map<String, String> vegetacoes = new HashMap<String, String>(); 10 vegetacoes.put("cerrado", "centro -oeste"); vegetacoes.put("floresta tropical", "norte"); vegetacoes.put("caatinga", "nordeste"); vegetacoes.put("mata atlântica", "costa brasileira"); 11 12 13 14 15 String escolha = JOptionPane.showInputDialog("Digite uma vegetação:" + vegetacoes.keySet()); JOptionPane.showMessageDialog(null, vegetacoes.get(escolha)); 16 17 18 } 19 20 } A Listagem 9.9 apresenta um exemplo um pouco mais complexo de mapa. Neste exemplo é realizada a contagem da quantidade de produtos com o mesmo nome existe na lista. Observe que no final o código: for(Entry<String, Integer> e : mapaContagem.entrySet()){ System.out.printf("%s: %d\n", e.getKey(), e.getValue()); } é utilizado para percorrer os elementos do mapa que associa os produtos com suas respectivas quantidades. Listagem 9.9: Exemplo de uso de Mapas na contagem de elementos de uma lista 1 2 3 4 5 6 package capitulo9; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; 7 8 100 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 9 genéricos e coleções public class ExemploMapaContagem { 10 public static void main(String[] args) { 11 12 List<String> lista = new ArrayList<String>(); lista.add("Cerveja"); lista.add("Carvão"); lista.add("Picanha"); lista.add("Cerveja"); lista.add("Cerveja"); lista.add("Cerveja"); lista.add("Cerveja"); lista.add("Cerveja"); lista.add("Costela"); lista.add("Costela"); lista.add("Pão com alho"); lista.add("Pão com alho"); lista.add("Pão com alho"); lista.add("Pão com alho"); 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 Map<String, Integer> mapaContagem = new HashMap<String, Integer>(); for (String s : lista) { Integer qtd = mapaContagem.get(s); if(qtd == null){ qtd = 0; } qtd++; mapaContagem.put(s, qtd); } 29 30 31 32 33 34 35 36 37 38 for(Entry<String, Integer> e : mapaContagem.entrySet()){ System.out.printf("%s: %d\n", e.getKey(), e.getValue()); } 39 40 41 } 42 43 44 } 9.5.1 Properties As propriedades são mapas que podem ser persistidos, ou seja, salvos em algum lugar. Um exemplo de arquivo properties é: #Propriedades do Sistema telefone=3131-2363 descricao=Supermercado da Esquina endereco=Rua 2 Observe a semelhança com os mapas, para cada entrada existe uma informação, ou seja,para a entrada telefone tem-se a informação: 3131-2363. http://solutioin.com Francisco Calaça, Otávio Calaça 101 Versão 1.2-beta genéricos e coleções Java possui um tipo de mapa que tem a habilidade de persistir suas informações, são as Properties. Estas classes possuem o método: prop.store( . . .); para a escrita dos dados, conforme pode ser visto na listagem 9.10 e o método: prop.load( . . . ); para carregar os dados a partir de um fluxo, conforme pode ser visto na listagem 9.11 Listagem 9.10: Exemplo de escrita em arquivos properties 1 2 3 4 5 package capitulo9; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties; 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class ExemploPropertiesEscrita { public static void main(String[] args) { Properties prop = new Properties(); prop.put("descricao", "Supermercado da Esquina"); prop.put("endereco", "Rua 2"); prop.put("telefone", "3131 -2363"); try { FileOutputStream fos = new FileOutputStream("c:\\ prop.properties"); prop.store(fos, "Propriedades do Sistema"); fos.close(); System.out.println("Propriedades salvas"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } Listagem 9.11: Exemplo de leitura de arquivos properties 1 2 3 4 5 package capitulo9; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Properties; 6 7 import javax.swing.JOptionPane; 8 9 10 11 12 13 public class ExemploPropertiesLeitura { public static void main(String[] args) { try { FileInputStream fis = new FileInputStream("c:\\ prop.properties"); Properties prop = new Properties(); 102 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta prop.load(fis); fis.close(); String nomeProp = JOptionPane.showInputDialog("Qual propriedade " + "deseja ver? (descricao , endereco , telefone)" ); JOptionPane.showMessageDialog(null, prop.getProperty(nomeProp)); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } 14 15 16 17 18 19 20 21 22 23 } 24 25 genéricos e coleções } 9.6. Pilhas Pilhas são estrutura de dados onde o último elemento que entra é o primeiro que sai - LIFO (last-in-first-out). É possível exemplificar com uma pilha de livros. O primeiro livro a ser emplilhado é o último que sai da pilha. Um exemplo de pilha pode ser visto no código da listagem 9.12. Após executar este exemplo o primeiro nome a ser impresso foi “Carlos” mas foi o último a ser adicionado na pilha. Listagem 9.12: Exemplo de pilha 1 package capitulo9; 2 3 import java.util.Stack; 4 5 public class ExemploPilha { 6 public static void main(String[] args) { Stack<String> alunos = new Stack<String>(); alunos.push("Maria"); alunos.push("Antonio"); alunos.push("Joaquim"); alunos.push("Carlos"); 7 8 9 10 11 12 13 while(!alunos.empty()){ System.out.println(alunos.pop()); } 14 15 16 } 17 18 19 } http://solutioin.com Francisco Calaça, Otávio Calaça 103 Versão 1.2-beta 9.7. genéricos e coleções Filas Filas são estruturas de dados onde o primeiro elemento que entra é o primeiro elemento que sai - FIFO (first-in-first-out). Como nas filas dos caixas, a primeira pessoa que entra é a primeira pessoa que poderá pagar. O código da listagem 9.13 apresenta um exemplo de Fila. Listagem 9.13: Exemplo de Fila 1 package capitulo9; 2 3 4 import java.util.LinkedList; import java.util.Queue; 5 6 public class ExemploFila { 7 public static void main(String[] args) { Queue<String> alunos = new LinkedList<String>(); alunos.offer("Maria"); alunos.offer("Antonio"); alunos.offer("Joaquim"); alunos.offer("Carlos"); 8 9 10 11 12 13 14 while(!alunos.isEmpty()){ System.out.println(alunos.poll()); } 15 16 17 } 18 19 20 } 9.8. Ordenação de Listas Uma das características de Listas é poder ser ordenada. Para ordenar uma lista pode-se utilizar a interface Comparator e o método sort da classe Collections. Observe o exemplo onde existem alunos que serão ordenados por idade. A classe Aluno está na listagem 9.14. Possui os atributos nome e idade. O método compare retorna um int, que pode ser: • negativo se o primeiro objeto for menor que o segundo • zero se os objetos forem iguais • positivo se o primeiro objeto for maior que o segundo Não se preocupe com o código: return (int)(a1.getIdade() - a2.getIdade(); 104 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta genéricos e coleções Apenas se atenha ao fato de que este método retornará algo negativo se a1 for menor que a2, zero se forem iguais e positivo se a1 for maior. O código do comparador por idade está na Listagem 9.15 e Listagem 9.14: Classe Aluno do exemplo de ordenação 1 package capitulo9; 2 3 public class Aluno { 4 private String nome; 5 6 private int idade; 7 8 public Aluno(String nome, int idade) { this.nome = nome; this.idade = idade; } 9 10 11 12 13 public String toString(){ return String.format("Aluno: %-10s - %3d", nome, idade); } 14 15 16 17 public String getNome() { return nome; } 18 19 20 21 public void setNome(String nome) { this.nome = nome; } 22 23 24 25 public int getIdade() { return idade; } 26 27 28 29 public void setIdade(int idade) { this.idade = idade; } 30 31 32 33 } Listagem 9.15: Comparador por idade 1 2 package capitulo9; import java.util.Comparator; 3 4 public class ComparadorIdade implements Comparator<Aluno>{ 5 public int compare(Aluno a1, Aluno a2) { return a1.getIdade() - a2.getIdade(); } 6 7 8 9 10 } http://solutioin.com Francisco Calaça, Otávio Calaça 105 Versão 1.2-beta genéricos e coleções Listagem 9.16: Exemplo de ordenacao 1 package capitulo9; 2 3 4 5 import java.util.ArrayList; import java.util.Collections; import java.util.List; 6 7 8 public class ExemploOrdenacao { 9 public static void main(String[] args) { List<Aluno> alunos = new ArrayList<Aluno>(); for(int i = 0; i < 15; i++){ int idade = (int)(Math.random() * 5) + 10; String nome = "Aluno nr. " + i; Aluno a = new Aluno(nome, idade); alunos.add(a); } 10 11 12 13 14 15 16 17 18 System.out.println("Lista original:"); 19 20 for(Aluno a : alunos){ System.out.println(a); } 21 22 23 24 System.out.println("\nLista ordenada por idade:"); 25 26 Collections.sort(alunos, new ComparadorIdade()); for(Aluno a : alunos){ System.out.println(a); } 27 28 29 30 31 } 32 33 } 9.9. Exercícios Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 1. O que são genéricos? 2. Descreva sobre Listas. 3. Descreva sobre Conjuntos. 106 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta genéricos e coleções 4. Descrevas sobre Mapas. 5. Qual as diferenças entre listas e conjuntos? 6. O que são properties? Qual a classe responsável por persistir as properties em um arquivo? 7. O que é pilha? 8. O que é fila? 9. Quais os procedimentos necessários para ordenar uma lista de String’s? E uma lista de objetos da classe Pessoa? 10. Adicione o atributo nota na classe da Listagem 9.14. Crie a classe ComparadorNota seguindo o exemplo da Listagem 9.15. Altere o código da Listagem 9.16 para também ordenar os alunos por nota. http://solutioin.com Francisco Calaça, Otávio Calaça 107 10 UML: UNIFIED MODELING LANGUAGE Este capítulo lhe fornecerá uma visão rápida dos fundamentos da UML. Tenha em mente que isto não é um tutorial detalhado sobre UML, mas apenas uma rápida introdução a UML que pode ser lida como um tutorial UML. Se você gostaria de aprender mais sobre a Linguagem de Modelagem Unificada, ou generalidades sobre análise e desenho de software, consulte um dos muitos livros disponíveis sobre o tópico. Existem também muitos tutoriais na Internet os quais você pode usar como ponto de partida. A Unified Modelling Language (UML) é uma linguagem ou notação de diagramas para especificar, visualizar e documentar modelos de ’software’ orientados por objetos. O UML não é um método de desenvolvimento, o que significa que não lhe diz o que fazer primeiro ou o que fazer depois ou como desenhar o seu sistema, mas ajuda-o a visualizar o seu desenho e a comunicar com os outros. O UML é controlado pelo Object Management Group (OMG) e é a norma da indústria para descrever graficamente o ’software’. O UML está desenhado para o desenho de ’software’ orientado por objetos e tem uma utilização limitada para outros paradigmas de programação. A UML é composta por muitos elementos de modelo que representam as diferentes partes de um sistema de software. Os elementos UML são usados para criar diagramas, que representam um determinada parte, ou um ponto de vista do sistema. Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 10.1. Diagrama de Classe Diagramas de Classe mostram as diferentes classes que fazem um sistema e como elas se relacionam. Os Diagramas de Classe são chamados diagramas “estáticos” porque mostram as classes, com seus métodos e atributos bem como os relacionamentos estáticos entre elas: quais classes “conhecem” quais classes ou quais classes “são parte” de outras classes, mas não mostram a troca de mensagens entre elas. 10.1.1 Classe Um Classe define os atributos e os métodos de um conjunto de objetos. Todos os objetos desta classe (instâncias desta classe) compartilham o mesmo comportamento, e possuem 109 Versão 1.2-beta uml: unified modeling language o mesmo conjunto de atributos (cada objeto possui seu próprio conjunto). O termo “Tipo” é algumas vezes usado ao invés de Classe, mas é importante mencionar que estes dois termos não são a mesma coisa, e Tipo é um termo mais genérico. Em UML Classes são representadas por retângulos, com o nome da classe, e podem também mostrar os atributos e operações da classe em dois outros “compartimentos” dentro do retângulo. Figura 10.1: Representação visual de uma Classe em UML 10.1.1.1 Atributos Na UML, atributos são mostrados com pelo menos seu nome, e podem também mostrar seu tipo, valor inicial e outras propriedades. Atributos podem também ser exibidos com sua visibilidade: • + indica atributos públicos • # indica atributos protegidos • - indica atributos privados 10.1.1.2 Operações Operações (métodos) também são exibidos com pelo menos seu nome, e podem também mostrar seus parâmetros e valores de retorno. Operações podem, como os Atributos, mostras sua visibilidade: • + indica operações públicas • # indica operações protegidas • - indica operações privadas 10.1.2 Associações de Classe Classes podem relacionar-se (ser associada com) com outras de diferentes maneiras: 10.1.2.1 Generalização A herança é um dos conceitos fundamentais da programação orientada por objetos, nos quais uma classe “ganha” todos os atributos e operações da classe que herda, podendo 110 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta uml: unified modeling language sobrepor ou modificar algumas delas, assim como adicionar mais atributos ou operações próprias. EM UML, uma associação Generalização entre duas classes coloca-as numa hierarquia representando o conceito de herança de uma classe derivada de uma classe base. Em UML, Generalizações são representadas por uma linha conectando duas classes, com uma seta no lado da classe base. Figura 10.2: Representação visual de uma generalização em UML 10.1.2.2 Associações Um associação representa um relacionamento entre classes, e fornece a semântica comum e a estrutura para muitos tipos de “conexões” entre objetos. Associações são o mecanismo que permite objetos comunicarem-se entre si. Elas descrevem a conexão entre diferentes classes (a conexão entre os objetos atuais é chamada conexão do objeto, ou link. Associações podem ter um regra que especifica o propósito da associação e pode ser uni ou bidirecional (indicando se os dois objetos participantes do relacionamento podem mandar mensagens para o outro, ou se apenas um deles sabe sobre o outro). Cada ponta da associação também possui uma valor de multiplicidade, que dita como muitos objetos neste lado da associação pode relacionar-se com o outro lado. Em UML, associações são representadas como linhas conectando as classes participantes do relacionamento, e podem também mostrar a regra e a multiplicidade de cada um dos participantes. A multiplicidade é exibida como um intervalo [min...máx] de valores não negativos, com uma estrela (*) no lado máximo representando infinito. Figura 10.3: Representação visual de uma Associação em UML 10.1.2.3 Agregação Agregações são um tipo especial de associação no qual as duas classes participantes não possuem em nível igual, mas fazem um relacionamento “todo-parte”. Uma Agregação descreve como a classe que possui a regra do todo, é composta (tem) de outras classes, que http://solutioin.com Francisco Calaça, Otávio Calaça 111 Versão 1.2-beta uml: unified modeling language possuem a regra das partes. Para Agregações, a classe que age como o todo sempre tem uma multiplicidade de um. Em UML, Agregações são representadas por uma associação que mostra um romboide no lado do todo. Figura 10.4: Representação visual de um relacionamento Agregação em UML 10.1.2.4 Composição Composições são associações que representam agregações muito fortes. Isto significa que Composições formam relacionamentos todo-parte também, mas o relacionamento é tão forte que as partes não pode existir independentes. Elas existem somente dentro do todo, e se o todo é destruído as partes morrem também. Em UML, Composições são representadas por um romboide sólido no lado do todo. Figura 10.5: Representação visual de um relacionamento Composição em UML 10.2. Diagrama de Caso de Uso Diagramas de Caso de Uso descrevem relacionamentos e dependências entre um grupo de Caso de Uso e os Atores participantes no processo. É importante observar que Diagramas de Caso de Uso não são adequados para representar o desenho, e não podem descrever os mecanismos internos de um sistema. Diagramas de Caso de Uso são feitos para facilitar a comunicação com os futuros usuários do sistema, e com o cliente, e são especialmente úteis para determinar os recursos necessários que o sistema deve ter. Diagramas de Caso de Uso dizem o quê o sistema deve fazer, mas não fazem - e não podem - especificar como isto será conseguido. 10.2.1 Caso de Uso Um Caso de Uso descreve - do ponto de vista dos atores - um grupo de atividades num sistema que produz um resultado concreto e tangível. Casos de Uso são descrições de interações típicas entre os usuários de um sistema e o sistema propriamente dito. Eles representam a interface externa do sistema e especificam um conjunto de exigências do que o sistema deve fazer (lembre-se: somente o quê, não como). 112 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta uml: unified modeling language Quando trabalhar com Casos de Uso, é importante lembrar-se de algumas regras simples: • Cada Caso de Uso está relacionado com no mínimo um ator; • Cada Caso de Uso possui um iniciador (isto é um ator); • Cada Caso de Uso liga-se a um resultado relevante (um resultado com “valor de negócio”); Casos de Uso também podem ter relacionamentos com outros Casos de Uso. Os três tipos mais comuns de relacionamento entre Casos de Uso são: • «inclui-se» que especifica que um Caso de Uso toma lugar dentro de outro Caso de Uso • «estende» que especifica que em determinadas situações, ou em algum ponto (chamado um ponto de extensão) um Caso de Uso será estendido por outro. • Generalização especifica que um Caso de Uso herda as características do “Super” Caso de Uso, e pode sobrepor algumas delas ou adicionar novas de maneira semelhante a herança entre classes. 10.2.2 Ator Um ator é uma entidade externa (fora do sistema) que interage com o sistema participando (e frequentemente iniciando) um Caso de Uso. Atores podem ser pessoas reais (por exemplo usuários do sistema), outro sistema de computador ou eventos externos. Atores não representam as pessoa física ou sistemas, mas sua regra. Isto significa que quando uma pessoa interage com o sistema de diferentes maneiras (assumindo diferentes regras) ela será representada por diversos atores. Por exemplo um pessoa que fornece suporte ao cliente por telefone e recebe ordens do cliente para o sistema pode ser representado por um ator da “Equipe de Suporte” e um ator “Representante de Vendas” 10.2.3 Descrição do Caso de Uso Descrição do Caso de Uso são narrativas de texto do Caso de Uso. Elas usualmente tomam a forma de uma nota ou um documento que é de alguma maneira ligado ao Caso de Uso, e explana o processo ou atividades que tomarão lugar no Caso de Uso. 10.3. Demais diagramas Além dos diagramas de classe e de caso de uso, existem os outros seguintes diagramas: • Diagrama de Sequência mostra objetos e uma sequência das chamadas do método feitas para outros objetos. http://solutioin.com Francisco Calaça, Otávio Calaça 113 Versão 1.2-beta uml: unified modeling language Figura 10.6: Representação visual de alguns casos de uso • Diagrama de Colaboração mostra objetos e seus relacionamentos, colocando ênfase nos objetos que participam na troca de mensagens • Diagrama de Estado mostra estados, mudanças de estado e eventos num objeto ou uma parte do sistema • Diagrama de Atividade mostra atividades e as mudanças de uma atividade para outra com os eventos ocorridos em alguma parte do sistema • Diagrama de Componente mostra os componentes de programação de alto nível (como KParts ou Java Beans). • Diagrama de Distribuição mostra as instâncias dos componentes e seus relacionamentos. Os Diagramas de Entidade-Associação mostram os dados e as relações e as restrições entre os dados. 114 http://solutioin.com Francisco Calaça, Otávio Calaça 11 THREADS Thread, ou linha de execução em português, é uma forma de um processo dividir a si mesmo em duas ou mais tarefas que podem ser executadas simultaneamente. Uma linha de execução permite que o usuário do seu programa, por exemplo, utilize uma funcionalidade do ambiente enquanto outras linhas de execução realizam outros cálculos e operações. Os sistemas que suportam apenas uma única linha de execução são chamados de monothread e aqueles sistemas que suportam múltiplas linhas de execução são chamados de multithread. 11.1. Processos e Threads Em programação concorrente, há duas unidades básicas: processos e threads. Em Java a programação concorrente é normalmente concebida com threads. Um sistema computacional normalmente possui muitos processos e threads ativos. Esteja ele sendo executado em uma máquina com um processador ou em uma máquina multiprocessada. 11.1.1 Processos Um processo geralmente tem um conjunto completo e restrito de recursos para sua execução, ou seja, cada processo tem seu próprio espaço de memória. Processos são sinonimos de programas e aplicações. Como o espaço de memória e restrito a cada processo, a comunicação entre processos é feita através do sistema operecional com pipes e sockets. Esta comunicação pode ser feita entre processos na mesma máquina ou em diferentes máquinas. 11.1.2 Threads Threads são, algumas vezes, chamadas de processos leves. Threads existem dentro dos processos, cada processo possui pelo menos uma thread. Threads podem compartilhar recursos do processos, como memória e arquivos abertos. Isto é muito eficiente para a comunição de recursos. Execução multithread é um caracteristica da plataforma Java. Cada aplicação Java é composta de várias thread. As threads tornam os programas mais eficientes pois, com elas, é possível realizar mais de uma atividade simultaneamente. Uma thread possui a habilidade de criar novas threads. 115 Versão 1.2-beta 11.2. threads Criação de Threads Cada thread está associada com uma instancia da classe Thread. Há duas formas de criar uma Thread: • Implementando a interface Runnable • Estendendo a classe Thread Independente da forma que se cria a thread o código a ser executado pela thread deve estar no método run: public void run() Para iniciar a thread é necessário executar o método start: suaThread.start() A listagem 11.1 apresenta um exemplo de Thread que é criada estendendo a classe Thread. O uso desta thread está na classe da listagem 11.2. Note o uso do método start para iniciar esta thread. A listagem 11.3 apresenta um exemplo de Thread que é criada implementado a interface Runnable. O uso desta thread está na classe da listagem 11.4. Também foi utilizado o método start para iniciar a thread. Listagem 11.1: Thread criada estendendo da classe Thread 1 package capitulo11; 2 3 public class PrimeiraThread extends Thread { 4 public PrimeiraThread(String nome) { super(nome); } 5 6 7 8 public void run() { for (int i = 0; i < 10000; i++) { System.out.printf("\n Thread: %s (executando) - %5d", getName(), i++); } } 9 10 11 12 13 14 } Listagem 11.2: Execução da Thread que estendeu a classe thread 1 package capitulo11; 2 3 4 5 6 7 8 9 10 public class ExemploThread { public static void main(String[] args) { PrimeiraThread thread1 = new PrimeiraThread(" **** "); PrimeiraThread thread2 = new PrimeiraThread("####"); thread1.start(); thread2.start(); } } 116 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta threads Listagem 11.3: Thread criada implementando Runnable 1 package capitulo11; 2 3 public class SegundaThread implements Runnable { 4 private String nome; 5 6 public SegundaThread(String nome) { this.nome = nome; } 7 8 9 10 public void run() { for (int i = 0; i < 10000; i++) { System.out.printf("\n Thread: %s (executando) - %5d", nome, i++); } } 11 12 13 14 15 16 } Listagem 11.4: Execução da Thread que implementou Runnable 1 package capitulo11; 2 3 4 5 6 public class ExemploThread2 { public static void main(String[] args) { SegundaThread st1 = new SegundaThread(" **** "); SegundaThread st2 = new SegundaThread("####"); 7 Thread thread1 = new Thread(st1); Thread thread2 = new Thread(st2); 8 9 10 thread1.start(); thread2.start(); 11 12 } 13 14 } 11.3. A classe Executors A nova API de threads permite um melhor gerenciamento das threads utilizando pool. Desta forma é possível criar um pool de Threads e especificar a quantidade máxima de threads estará em execução simultaneamente. A listagem 11.5 apresenta um exemplo de utilização do pool de threads. Neste exemplo o pool é criado com o método: ExecutorService threads = Executors.newFixedThreadPool(2) note que serão executadas apenas duas threads simultaneamente. threads.execute(t1); threads.execute(t2); threads.execute(t3); http://solutioin.com Francisco Calaça, Otávio Calaça 117 Versão 1.2-beta threads são colocadas três threads no pool. Como apenas duas threads serão executadas a terceira irá esperar uma das duas anteriores terminar para começar sua execução. Listagem 11.5: Exemplo de utilização do pool de threads 1 package capitulo11; 2 3 import java.util.concurrent.*; 4 5 6 7 8 9 public class ExemploThread3 { public static void main(String[] args) { SegundaThread t1 = new SegundaThread(" **** "); SegundaThread t2 = new SegundaThread("####"); SegundaThread t3 = new SegundaThread("$$$$"); 10 ExecutorService threads = Executors.newFixedThreadPool(2); threads.execute(t1); threads.execute(t2); threads.execute(t3); threads.shutdown(); 11 12 13 14 15 } 16 17 } 11.4. Métodos sleep e yield O método Thread.sleep faz com que a thread suspenda sua execução por um período específico. Após o término do periodo a thread volta ao estado de executável podendo entrar em execução ou não dependendo da sua prioridade. A figura 11.1 ilustra esse método. O método Thread.yield faz com que a thread desista de sua atual execução. Suponha que você executa muitas threads no computador e que estas threads estão sendo mal gerenciadas e que algumas não conseguem concluir algumas atividades. Ao ser executado o método yield provocará a desistência momentânea da thread em execução e possibilitará a entrada de outra thread para a execução. Essa thread aguardará até a CPU tornar-se disponível novamente. Note que ela poderá voltar a ser executada quando o gerenciador de threads do sistema solicitar. A figura 11.2 ilustra esse método. 11.5. Sincronização Quando duas threads compartilham dados é comum que haja problemas com sincronização. Para que você entenda melhor este problema observe o exemplo. A classe Troca está na listagem 11.6. Note que esta classe possui o método trocar que recebe um boolean. Se o boolean for true as variáveis a e b receberão 5 e 7, sendo false receberão 11 e 13. A thread está na listagem 11.7. A classe que instancia o objeto do tipo Troca e as threads está na listagem 11.8. Note que é criado apenas um objeto do tipo Troca e este objeto é compartilhado entre as threads es1 e es2. Uma dessas threads é instanciada com true a outra com 118 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta threads Figura 11.1: Método Thread.sleep Figura 11.2: Método Thread.yield http://solutioin.com Francisco Calaça, Otávio Calaça 119 Versão 1.2-beta threads false. isto fará com que o comportamento do metodo trocar da classe Troca seja diferente para cada thread. Ao executar este exemplo é apresentada a seguinte saída: 5 = 11 e 7 = 13 11 = 5 e 13 = 7 5 = 11 e 7 = 13 11 = 5 e 13 = 7 5 = 11 e 7 = 13 Isto acontece porque as threads não estão sincronizadas. Uma thread inicia o trabalho, a outra termina. Para resolver este problema é necessário sincronizar o método trocar: synchronized public void trocar(boolean bol). Ao acrescentar a palavra chave synchronized no método fará com que este não possa ser executado por duas threads simultaneamente. Listagem 11.6: Objeto Troca que está compartilhado entre a threads 1 package capitulo11; 2 3 4 public class Troca { private int a; 5 private int b; 6 7 public void trocar(boolean bol) throws InterruptedException { if (bol) { a = 5; b = 7; } else { a = 11; b = 13; } Thread.sleep(500); 8 9 10 11 12 13 14 15 16 17 if (bol) { System.out.printf("%d = 5 e %d = 7 \n", a, b); } else { System.out.printf("%d = 11 e %d = 13 \n", a, b); } 18 19 20 21 22 } 23 24 } Listagem 11.7: Thread que acessará o objeto Troca 1 package capitulo11; 2 3 4 5 public class Operador implements Runnable { private boolean bol; private Troca obj; 6 7 8 9 public Operador(Troca obj, boolean bol) { this.bol = bol; this.obj = obj; 120 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta threads } 10 11 public void run() { while (true) { try { obj.trocar(bol); } catch (InterruptedException e) { e.printStackTrace(); } } } 12 13 14 15 16 17 18 19 20 21 } Listagem 11.8: Exemplo de threads não sincronizadas 1 package capitulo11; 2 3 4 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; 5 6 7 public class ExemploSinc { 8 public static void main(String[] args) { Troca obj = new Troca(); Operador es1 = new Operador(obj, true); Operador es2 = new Operador(obj, false); 9 10 11 12 13 ExecutorService t1 = Executors.newFixedThreadPool(2); t1.execute(es1); t1.execute(es2); t1.shutdown(); 14 15 16 17 } 18 19 } 11.6. O verificador de primos Para exemplificar melhor o uso de threads as listagens 11.9 e 11.10 apresentam um Verificador de números primos. Este exemplo consegue verificar vários primos simultaneamente porque a classe VerificadorPrimo da listagem 11.9 é uma thread. A classe TestePrimo cria uma nova thread de verificação a cada número informado pelo usuário. Listagem 11.9: Thread que verifica se um número é primo (utiliza um algoritmo lento de verificação para demonstrar melhor o exemplo) 1 package capitulo11; 2 3 public class VerificadorPrimo extends Thread { 4 5 private long numero; http://solutioin.com Francisco Calaça, Otávio Calaça 121 Versão 1.2-beta threads 6 public VerificadorPrimo(long numero) { this.numero = numero; } 7 8 9 10 public void run() { boolean primo = true; for (int i = 2; i < numero; i++) { if ((numero % i) == 0) { primo = false; } } 11 12 13 14 15 16 17 18 if (primo) { System.out.printf("\nO número: %d é primo", numero); } else { System.out.printf("\nO número: %d não é primo", numero); } 19 20 21 22 23 } 24 25 } Listagem 11.10: Verificador de números primos 1 package capitulo11; 2 3 import javax.swing.JOptionPane; 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class TestePrimo { public static void main(String[] args) { String resposta; do { resposta = JOptionPane.showInputDialog("Digite um número"); try { long numero = new Long(resposta); VerificadorPrimo vf = new VerificadorPrimo(numero); vf.start(); } catch (NumberFormatException e) { JOptionPane.showMessageDialog(null, "número invalido" ); } 19 } while (!resposta.equals("sair")); 20 } 21 22 } 122 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta threads Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 11.7. Exercícios 1. O que são threads? 2. Qual a diferença entre processos e threads? 3. Descreva as duas formas de se criar uma thread. 4. O que são pool de threads? 5. Qual a diferença entre os métodos sleep e yield? 6. Qual o objetivo de utilização da palavra chave synchronized? http://solutioin.com Francisco Calaça, Otávio Calaça 123 12 S T R I N G S E D ATA S Converter Datas em Strings e Strings em Datas é um dos assuntos deste capítulo. Esta é uma tarefa comum em softwares uma vez que a maior forma de entrada de dados em um sistema é texto e este texto deve, algumas vezes, ser convertido em data para correta manipulação. Outra coisa,normalmente é necessária, é formatar uma data em textos para que seja melhor apresentada ao usuário. Na versão 5 do Java foi acrescentado a saída formatada assunto também abordado neste capítulo. Com a saída formatada é mais simples a formatação de números, datas e outros. 12.1. As classes Date e Calendar A classe Date é utilizada para representar momentos no tempo. A maior parte dos seus metodos estão deprecados, ou seja, não são mais utilizados. Para manipulação de datas e horas existe a classe Calendar. Por ser uma classe abstrata utiliza-se o método getInstance: Calendar.getInstance(); Para obter a data e hora atuais pode ser utilizado o construtor default da classe Date: Date hoje = new Date(); A listagem 12.1 apresenta um exemplo de uso da classe Calendar. Listagem 12.1: Exemplo de uso da classe Calendar 1 package capitulo12; 2 3 import java.util.Calendar; 4 5 public class ExemploCalendar { 6 public static void main(String[] args) { Calendar calendar = Calendar.getInstance(); int diaAno = calendar.get(Calendar.DAY_OF_YEAR); int ano = calendar.get(Calendar.YEAR); 7 8 9 10 11 System.out.printf("\nEstamos no %d dia do ano de %d", diaAno, ano); 12 } 13 14 15 } 125 Versão 1.2-beta 12.2. strings e datas Formatação de Datas É muito comum um sistema necessitar converter uma data em uma String ou uma String em uma data. Para estes casos é possível utilizar a classe SimpleDateFormat. Esta classe implementa a interface DateFormat e possui métodos que são capazes tanto em formatar uma data em um String ou em converter uma String em uma data. A listagem 12.2 apresenta um exemplo de conversão de String em data e formatação desta data em outra String. Para converter uma String em uma data utiliza-se o método parse. Este método lança uma exeção se a String não puder ser convertida. O método format formata uma data em uma String. Listagem 12.2: Exemplo de formatação de datas 1 package capitulo12; 2 3 4 5 6 import import import import java.text.DateFormat; java.text.ParseException; java.text.SimpleDateFormat; java.util.Date; 7 8 import javax.swing.JOptionPane; 9 10 public class ExemploFormatacaoData { 11 public static void main(String[] args) { DateFormat formatadorEntrada = new SimpleDateFormat( "dd/MM/yyyy" ); DateFormat formatadorSaida = new SimpleDateFormat( 12 13 14 15 "’Data Informada:’ dd ’de’ MMMM ’de’ yyyy - ’(’EEEE ’)’" ); 16 17 String dataTexto = JOptionPane .showInputDialog("Digite uma data:"); try { Date data = formatadorEntrada.parse(dataTexto); String dataFormatada = formatadorSaida.format(data); JOptionPane.showMessageDialog(null, "Data digitada: " + dataFormatada); } catch (ParseException e) { e.printStackTrace(); } 18 19 20 21 22 23 24 25 26 27 28 } 29 30 31 } 126 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 12.3. strings e datas A classe String Strings são objetos que contém uma cadeia de caracteres. Em Java são imutáveis, portanto uma vez criadas não podem ser alteradas. Para exemplificar, caso ocorra uma concatenação de Strings, um novo objeto é criado, e o antigo, será coletado pelo coletor de lixo. O método charAt é utilizado para consultar caracteres pelo índice. Para comparar Strings, assim como qualquer outro objeto Java, utiliza-se o método equals. Este método retorna true quando os valores entre as Strings são iguais e false caso sejam diferentes. 12.4. A classe StringBuffer As classes StringBuffer e StringBuilder possibilitam a alteração de uma cadeia de caracteres o que torna o processamento mais rápido uma vez que não é necessário criar Strings a cada concatenação. A listagem 12.3 apresenta uma comparação de concatenação de Strings entre String e StringBuffer. Listagem 12.3: Comparação da concatenação de Strings entre StringBuffer e a classe String 1 package capitulo12; 2 3 public class RankingString { 4 5 private static int quantidade = 10000; 6 7 8 public static long concatenarComString() { long t1 = System.currentTimeMillis(); 9 String texto = ""; for (int i = 0; i < quantidade; i++) { texto += "a"; } 10 11 12 13 14 long t2 = System.currentTimeMillis(); return t2 - t1; 15 16 17 } 18 19 20 public static long concatenarComStringBuffer() { long t1 = System.currentTimeMillis(); 21 StringBuffer texto = new StringBuffer(""); for (int i = 0; i < quantidade; i++) { texto.append("a"); } 22 23 24 25 26 long t2 = System.currentTimeMillis(); return t2 - t1; 27 28 29 } 30 http://solutioin.com Francisco Calaça, Otávio Calaça 127 Versão 1.2-beta strings e datas public static void main(String[] args) { long tempoStringBuffer = concatenarComStringBuffer(); System.out.printf("Tempo com StringBuffer: %d ms \n", tempoStringBuffer); 31 32 33 34 long tempoString = concatenarComString(); System.out.printf("Tempo com String: %d ms \n", tempoString); 35 36 } 37 38 } 12.5. Saída formatada A saída formatada está disponível a partir do Java 5.0. Igual à saída formatada das linguagens C e C++ permite a formação de Strings utilizando uma String formatadora: System.out.printf(‘‘\%s, \%s’’, texto1, texto2); Observe que a string formatadora “%s, %s” recebe os parâmetros texto1 e texto2 o os formata uma após o outro separados com uma vírgula. Observe que a passatem dos parâmetros texto1 e texto2 são impressos na mesma ordem que aparecem. É possível alterar esta ordem utilizando indices. O exemplo System.out.printf(‘‘\%2\$s, \%1\$s’’, texto1, texto2); irá imprimir os parâmetros texto1 e texto2 na ordem contraria em que aparecem. 12.5.1 Caracteres de conversão Para formatar Strings é possível utilizar uma vasta quantidade de caracteres de conversão, dependendo do tipo da informação a ser formatada. A tabela 12.1 apresenta uma uma lista dos caracteres de formatação utilizados com Java. É possível ajustar o tamanho da saída do parâmetro acrescentando um valor antes do caractere de conversão.: %5d imprimirá um número inteiro decimal e reservará um espaço de cinco caracteres para isto. Para números com ponto flutuante é ajustar a quantidade de casas decimais que devem ser apresentadas. Isto se faz acrescentando um ponto e um número com a quantidade de casas decimais a apresentar: \%.2 Este exemplo apresentará um número com ponto flutuante com duas casas decimais. A listagem 12.4 apresenta um exemplo com várias opções de formatação. 128 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta %s Utilizado com Strings %d Utilizado com números inteiros decimais %o Utilizado com números inteiros octais %x Utilizado com números inteiros hexadecimais (utilize “%X” para que as letras aparecam maiúsculas) %f Utilizado com números com ponto flutuante %t Utilizado com datas. Deve ser combinado com os formatadores da tabela ?? para produzir um resultado. strings e datas Tabela 12.1: Caracteres de conversão de String %F Formata uma data %H mostra a hora de uma data %M mostra o minuto de uma data %S mostra o segundo de uma data %m mostra o mês de uma data %d mostra o dia de uma data Tabela 12.2: tablecaption http://solutioin.com Francisco Calaça, Otávio Calaça 129 Versão 1.2-beta strings e datas Listagem 12.4: Exemplo de saída formatada 1 package capitulo12; 2 3 import java.util.Date; 4 5 public class ExemploSaidaFormatada { 6 public static void main(String[] args) { 7 8 /* * Exemplo de formatação de números inteiros */ System.out.println("Formatação de inteiros"); int inteiro = 123; System.out.printf("%10s %10s %10s", "DECIMAL", "OCTAL", "HEXADECIMAL"); System.out.printf("\n%1$10d %1$10o %1$10X", inteiro); 9 10 11 12 13 14 15 16 /* * Exemplo de formatação de ponto flutuante */ System.out.println("\n\nFormatação de ponto flutuantes"); double flutuante = 1.2345; System.out.printf("%.3f", flutuante); 17 18 19 20 21 22 23 /* * Formatação de Datas e Horas */ System.out.println("\n\nFormatação de datas e horas"); Date hoje = new Date(); System.out.printf("Hora atual: %1$tH:%1$tM:%1$tS", hoje); System.out.printf("\nData formatada: %1$tF", hoje); System.out.printf("\nData atual: %1$td/%1$tm/%1$tY", hoje); 24 25 26 27 28 29 30 31 32 } 33 34 } Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 12.6. Exercícios 1. Qual a diferença do uso das classes Date e Calendar? 2. Crie uma classe que receba a data no formato dd/MM/yyyy e converta para o formato yyyy-mm-dd utilizando a classe SimpleDateFormat. 130 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta strings e datas 3. Descreva a classe String. 4. Qual a diferença entre String e StringBuffer? http://solutioin.com Francisco Calaça, Otávio Calaça 131 13 JDBC Um Sistema Gerenciador de Banco de Dados (SGBD) é o conjunto de programas de computador responsáveis pelo gerenciamento de uma base de dados. O principal objetivo é retirar da aplicação o trabalho e a responsabilidade de gerenciar o acesso e a segurança de suas informações. Em bancos de dados relacionais é utilizada a linguagem SQL para manipulação dos registros. Normalmente as pessoas chamam os SGBDs de apenas Banco de Dados. No decorrer deste capítulo onde estiver o termo Banco de Dados entenda que são estas estruturas complexas de armazenamento de informações. JDBC (Java Database Connectivity) é a API do Java para trabalhar com Banco de Dados. Com ela é possível executar instruções ler registros executar funções no Banco de Dados. Trata-se de um conjunto de interfaces e classes que possuem os métodos necessários para as mais diversas atividades com um banco de dados. As interfaces são implementadas pelos drivers JDBC que são específicos para cada banco. 13.1. Conexão com banco de dados Para se conectar em um Banco de dados com o JDBC é necessários as seguintes informações: • O Driver do banco • A URL de conexão • O usuário • A senha • O caminho para o Driver (arquivo .jar) A classe apresentada na listagem 13.1 mostra um exemplo de conexão com o Banco de Dados. O Driver é passado com o seguinte método: Class.forName("org.postgresql.Driver"); A url, usuário e a senha com o seguinte método: DriverManager.getConnection( "jdbc:postgresql://localhost/treinamento", "postgres", "123456"); 133 Versão 1.2-beta jdbc A configuração do caminho para Driver é feita nas propriedades do projeto, na opção Java Build Path, conforme a figura 13.1. Listagem 13.1: Classe Conexao 1 package capitulo13; 2 3 import java.sql.*; 4 5 6 7 8 9 public class Conexao { private static String private static String private static String private static String driver = "org.postgresql.Driver"; url = "jdbc:postgresql :// localhost/treinamento"; usuario = "postgres"; senha = "123456"; 10 public static Connection getConexao() { try { Class.forName(driver); return DriverManager.getConnection(url, usuario, senha); } catch (ClassNotFoundException e) { e.printStackTrace(); return null; } catch (SQLException e) { e.printStackTrace(); return null; } } 11 12 13 14 15 16 17 18 19 20 21 22 23 } Figura 13.1: Configuração do CLASSPATH para o Driver JDBC 134 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 13.2. jdbc A linguagem SQL SQL é um linguagem de consulta a registros em um Banco de dados Relacional. As instruções SQL apresentadas a seguir utilizarão como referência a tabela CLIENTE 13.2.1 SELECT Instrução para consulta de registros. Sua sintaxe é: SELECT <LISTA DOS CAMPOS DA TABELA> FROM <TABELA> Um Exemplo: Para buscar todos os registros da tabela CLIENTE pode ser utilizado o seguinte SQL: SELECT CODIGO, NOME, TELEFONE, ENDERECO, NASCIMENTO FROM CLIENTE Um outra forma, não aconselhada, de busca de registros é a utilização do asterisco (*): SELECT * FROM CLIENTE 13.2.2 Cláusula WHERE Permite filtrar os registros em uma consulta, alteração ou exclusão. Sua sintaxe é: WHERE <NOME DO CAMPO> = <VALOR> Para buscar o registro da tabela CLIENTE onde o código vale 5: SELECT CODIGO, NOME, TELEFONE, ENDERECO, NASCIMENTO FROM CLIENTE WHERE CODIGO = 5 13.2.3 O Operador LIKE É possível realizar busca com aproximação de valores utilizando a expressão LIKE. Se o objetivo é buscar todos os nomes da tabela CLIENTE que comecem com “Ma” pode-se utilizar a seguinte instrução SQL: SELECT CODIGO, NOME, CPFCNPJ, ENDERECO, MUNICIPIO FROM CLIENTE WHERE NOME LIKE ’Ma%’ O caracter “%” substituirá com zero ou mais caracteres na busca. O caracter _ substituirá apenas com um caracter. http://solutioin.com Francisco Calaça, Otávio Calaça 135 Versão 1.2-beta 13.2.4 jdbc INSERT Permite incluir registros em uma tabela no banco de dados. Sua sintaxe é: INSERT INTO <NOME DA TABELA> (<NOME DOS CAMPOS>) VALUES (<VALOR DOS CAMPOS>). Para incluir um registro na tabela de CLIENTE pode ser utilizado o seguinte SQL: INSERT INTO CLIENTE (NOME, CPFCNPJ, ENDERECO, MUNICIPIO, UF) VALUES (’ANA MARIA’, ’321.321.321-01’, ’Rua 2 Centro’, ’GOIANIA’, ’GO’). 13.2.5 UPDATE Permite alterar registros em um tabela. Sua sintaxe é: UPDATE <NOME DA TABELA> SET <CAMPO> = <VALOR> WHERE <CAMPO> = <VALOR> Note a existência da cláusula WHERE. Se não for especificada todos os registros da tabela serão alterados para <VALOR>. Para alterar o nome do CLIENTE com código 5 para Joao Carlos pode ser utilizada a seguinte instrução: UPDATE CLIENTE SET NOME = ’Joao Carlos’ WHERE ID = 5 13.2.6 DELETE Permite excluir registros em uma tabela. Sua sintaxe é: DELETE FROM <NOME DA TABELA> WHERE <CAMPO> = <VALOR> Note o uso da cláusula WHERE. Sem especifica-la todos os registros da tabela serão excluídos. Para excluir o registro com código 5 da tabela é utilizada a seguinte instrução: DELETE FROM CLIENTE WHERE ID = 5 13.3. Como executar instruções SQL e obter registros Após realizada a conexão é possível executar instrções SQL. Para isto é necessário a criação de um Statement. Existem três tipos de Statements: • Statement - para execução de instruções estáticas, ou seja, sem parâmetros. 136 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta jdbc • PreparedStatement - para a execução de instruções com parâmetros • CallableStatement - para a execuções de funções do Banco de Dados. A classe da listagem 13.2 apresenta um exemplo de execução de instruções. Note que há dois tipos execuções: as que têm a função de buscar registros e as que tem a função de alterar registros. O comando SQL utilizado para buscar registros é o SELECT. Para a execução de um SELECT é necessário o método executeQuery. Este método retorna um ResultSet que possibilita a navegação no resultado. A interface ResultSet possui alguns métodos úteis e estes estão listados na tabela 13.1. next ir ao próximo registro, retorna true se existir um próximo registro e false se este não existir. getString(<NOME DO CAMPO>) retorna o valor (no formato String) contido no respectivo campo da tabela. Tabela 13.1: Leitura de um ResultSet Os comando SQL para alteração de registros são o INSERT, UPDATE e DELETE. Para a execução destes comandos podem ser utilizados os métodos execute ou executeUpdate Listagem 13.2: Primeiro Exemplo de acesso a banco de dados 1 package capitulo13; 2 3 import java.sql.*; 4 5 public class ExemploJDBC { 6 7 8 9 10 11 public static void main(String[] args) { Connection con = Conexao.getConexao(); try { Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("select * from cliente"); 12 13 14 15 16 17 18 19 while (rs.next()) { System.out.printf("%-30s%-30s%-30s%-30s%-30s\n", rs.getString("nome"), rs.getString("cpfCnpj"), rs.getString("endereco"), rs.getString("municipio"), rs.getString("uf")); } 20 21 22 23 con.close(); } catch (SQLException e) { e.printStackTrace(); http://solutioin.com Francisco Calaça, Otávio Calaça 137 Versão 1.2-beta } 24 } 25 26 jdbc } 13.3.1 PreparedStatement Com a interface PreparedStatement é possível passar parâmetros para as instruções SQL. No lugar dos parâmetros são utilizados pontos de interrogação (?): PreparedStatement pstmt = con.prepareStatement(‘‘SELECT * FROM CLIENTE WHERE ID = ?’’); pstmt.setInt(1, 5); Observe que após a criação da instrução é necessário passar os parâmetros com setInt. Exite também o setString, setDate, setLong, enfim, uma infinidade de possibilidades de passagem de valores para a instrução. 13.4. Execução em Lote É possível executar instruções SQL em lote. Esta técnica torna a execução muito mais rápida do que executar uma instrução de cada vez. A listagem 13.3 apresenta um teste de velocidade entre a utilização Listagem 13.3: Exemplo de execução em Batch 1 package capitulo13; 2 3 4 5 6 import import import import java.sql.Connection; java.sql.PreparedStatement; java.sql.SQLException; java.sql.Statement; 7 8 public class ExemploExecucaoBatch { 9 10 public static Connection con = Conexao.getConexao(); 11 12 13 14 15 16 17 18 19 static void limparTabela(){ try { Statement stmt = con.createStatement(); stmt.execute("delete from cliente"); } catch (SQLException e) { e.printStackTrace(); } } 20 21 22 23 24 public static long executarSemBatch(){ limparTabela(); long t1 = System.currentTimeMillis(); try { 138 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta jdbc PreparedStatement pstmt = con.prepareStatement("insert into cliente " + "(nome , cpfCnpj , endereco , municipio , uf) " + "values (?, ?, ?, ?, ?)"); for(int i = 0; i < 50000; i++){ pstmt.setString(1, "nome"); pstmt.setString(2, "cpfCnpj"); pstmt.setString(3, "endereco"); pstmt.setString(4, "municipio"); pstmt.setString(5, "uf"); pstmt.execute(); } } catch (SQLException e) { e.printStackTrace(); } long t2 = System.currentTimeMillis(); return t2 - t1; 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 } 41 42 public static long executarComBatch(){ limparTabela(); long t1 = System.currentTimeMillis(); try { PreparedStatement pstmt = con.prepareStatement("insert into cliente " + "(nome , cpfCnpj , endereco , municipio , uf) " + "values (?, ?, ?, ?, ?)"); for(int i = 0; i < 50000; i++){ pstmt.setString(1, "nome"); pstmt.setString(2, "cpfCnpj"); pstmt.setString(3, "endereco"); pstmt.setString(4, "municipio"); pstmt.setString(5, "uf"); pstmt.addBatch(); } pstmt.execute(); } catch (SQLException e) { e.printStackTrace(); } long t2 = System.currentTimeMillis(); return t2 - t1; } 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 public static void main(String[] args) { long t1 = executarComBatch(); System.out.printf("Com Batch: %d (ms)\n", t1); 67 68 69 70 long t2 = executarSemBatch(); System.out.printf("Sem Batch: %d (ms)\n", t2); 71 72 } 73 74 } http://solutioin.com Francisco Calaça, Otávio Calaça 139 Versão 1.2-beta 13.5. jdbc Tabela de Clientes Para exemplificar os conceitos de Banco de Dados veja agora uma agenda de clientes. A listagem 13.4 apresenta a classe Cliente. Listagem 13.4: Classe Cliente 1 package capitulo13; 2 3 public class Cliente { 4 5 private int id; 6 7 private String nome; 8 9 private String cpfCnpj; 10 11 private String endereco; 12 13 private String municipio; 14 15 private String uf; 16 17 18 19 public int getId() { return id; } 20 21 22 23 public void setId(int id) { this.id = id; } 24 25 26 27 public String getNome() { return nome; } 28 29 30 31 public void setNome(String nome) { this.nome = nome; } 32 33 34 35 public String getCpfCnpj() { return cpfCnpj; } 36 37 38 39 public void setCpfCnpj(String cpfCnpj) { this.cpfCnpj = cpfCnpj; } 40 41 42 43 public String getEndereco() { return endereco; } 44 45 public void setEndereco(String endereco) { 140 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta jdbc this.endereco = endereco; 46 } 47 48 public String getMunicipio() { return municipio; } 49 50 51 52 public void setMunicipio(String municipio) { this.municipio = municipio; } 53 54 55 56 public String getUf() { return uf; } 57 58 59 60 public void setUf(String uf) { this.uf = uf; } 61 62 63 64 } A listagem 13.5 apresenta a classe ClienteDao. Observe que foi colocada nesta classe os métodos de acesso ao Banco de Dados como incluir, excluir e listar. Colocar os métodos que acessam o Banco de Dados fora da entidade Cliente é uma boa prática de programação pois facilita a alteração da estrutura de dados. Listagem 13.5: Classe ClienteDao - acessa os recursos no Banco de Dados 1 package capitulo13; 2 3 4 5 6 7 8 9 import import import import import import import java.sql.Connection; java.sql.PreparedStatement; java.sql.ResultSet; java.sql.SQLException; java.sql.Statement; java.util.ArrayList; java.util.List; 10 11 public class ClienteDao { 12 13 14 15 16 17 18 19 20 21 22 private Cliente mapear(ResultSet rs) throws SQLException{ Cliente cliente = new Cliente(); cliente.setId(rs.getInt("id")); cliente.setNome(rs.getString("nome")); cliente.setCpfCnpj(rs.getString("cpfCnpj")); cliente.setEndereco(rs.getString("endereco")); cliente.setMunicipio(rs.getString("municipio")); cliente.setUf(rs.getString("uf")); return cliente; } 23 24 25 26 public void incluir(Cliente cliente) { Connection con = Conexao.getConexao(); try { http://solutioin.com Francisco Calaça, Otávio Calaça 141 Versão 1.2-beta try { PreparedStatement pstmt = con.prepareStatement("insert into cliente " + "(nome , cpfcnpj , endereco , municipio , uf) values (?, ?, ?, ?, ?)" ); pstmt.setString(1, cliente.getNome()); pstmt.setString(2, cliente.getCpfCnpj()); pstmt.setString(3, cliente.getEndereco()); pstmt.setString(4, cliente.getMunicipio()); pstmt.setString(5, cliente.getUf()); pstmt.execute(); } finally { con.close(); } } catch (SQLException e) { e.printStackTrace(); } 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 jdbc } 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 public List<Cliente> listar() { Connection con = Conexao.getConexao(); List<Cliente> resultado = new ArrayList<Cliente>(); try { try { Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("select * from cliente"); while (rs.next()) { Cliente cliente = mapear(rs); resultado.add(cliente); } } finally { con.close(); } } catch (SQLException e) { e.printStackTrace(); } return resultado; } 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 public void excluir(int id){ Connection con = Conexao.getConexao(); try { try { PreparedStatement pstmt = con.prepareStatement("delete from cliente where id = ?" ); pstmt.setInt(1, id); pstmt.execute(); } finally { con.close(); } } catch (SQLException e) { e.printStackTrace(); } } 142 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta jdbc 78 79 } A listagem 13.6 apresenta a classe Agenda. Esta classe obtém as informações com o usuário do sistema armazena no Banco de Dados e apresenta a lista de clientes cadastrados. Listagem 13.6: A Agenda 1 package capitulo13; 2 3 import java.util.List; 4 5 import javax.swing.JOptionPane; 6 7 public class ClienteInclusao { 8 public static void main(String[] args) { Cliente cliente = new Cliente(); cliente.setNome(JOptionPane.showInputDialog("Nome:")); cliente.setCpfCnpj(JOptionPane.showInputDialog("Cpf/Cnpj:")); cliente.setEndereco(JOptionPane.showInputDialog("Endereço:")); cliente.setMunicipio(JOptionPane.showInputDialog("Município:")); cliente.setUf(JOptionPane.showInputDialog("UF:")); 9 10 11 12 13 14 15 16 ClienteDao cdao = new ClienteDao(); cdao.incluir(cliente); 17 18 19 List<Cliente> clientes = cdao.listar(); for(Cliente c : clientes){ System.out.printf("%-30s%-30s%-30s%-30s%-30s\n", c.getNome(), c.getCpfCnpj(), c.getEndereco(), c.getMunicipio(), c.getUf()); } 20 21 22 23 24 25 26 27 28 } 29 30 } Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 13.6. Exercícios 1. O que é JDBC ? http://solutioin.com Francisco Calaça, Otávio Calaça 143 Versão 1.2-beta jdbc 2. Descreva os passos necessários para obter um conexao (Connection) Java com o Banco de dados. 3. No exemplo da agenda implemente a funcionalidade que exclui clientes. 4. O que é SQL? Quais os comandos básicos e sua sintaxe? 5. Qual a diferença entre o Statement e o PreparedStatement? 6. Pesquise o motivo da execução em lote ser mais rápida. 144 http://solutioin.com Francisco Calaça, Otávio Calaça 14 J AVA P E R S I S T E N C E A P I C O M H I B E R N AT E 14.1. Mapeamento objeto relacional Mapeamento objeto-relacional (ou ORM) é uma técnica de desenvolvimento utilizada para reduzir o trabalho de programar sistemas orientados aos objetos que utilizam bancos de dados relacionais. As tabelas do banco de dados são representadas através de classes e os registos de cada tabela são representados como instâncias das classes correspondentes. Com esta técnica, diminui-se consideravelmente a utilização de comandos em linguagem SQL. O desenvolvedor irá usar uma interface de programação simples que faz todo o trabalho de persistência. Não é necessária uma correspondência direta entre as tabelas de dados e as classes do programa. A relação entre as tabelas onde originam os dados e o objeto que os disponibiliza é configurada pelo programador, isolando o código do programa das alterações à organização dos dados nas tabelas do banco de dados. Em resumo, mapeamento objeto/relacional é a automatização das operações entre o mundo objeto e o mundo relacional. É utilizado na persistência de objetos em aplicações Java para tabelas em um banco de dados relacional. 14.2. Configurações iniciais Para que os exemplos deste capítulo funcionem, é necessário realizar algumas configurações prévias. Inicialmente, crie uma pasta, dentro do diretório src do seu projeto, chamada META-INF. Copie para esta pasta o arquivo persistence.xml. O conteúdo deste arquivo está na Listagem 18.12. Este arquivo também está disponibilizado na pasta AmbienteTrabalho/Material/materialJpa/config. A Figura 14.1 ilustra este passo. Figura 14.1: Configuração do arquivo persistence.xml 145 Versão 1.2-beta java persistence api com hibernate O próximo passo é a configuração das dependências da JPA. Para isto, clique com o botão direito do mouse sobre o projeto e vá em Properties. Clique em Java Build Path. Adicione os arquivos .jar que estão no diretório AmbienteTrabalho/Material/materialJpa/libJpa. A Figura 14.2 ilustra este passo. Figura 14.2: Configuração das dependências da JPA. 14.3. A criação do primeiro exemplo Agora será criado o modelo desenvolvido no capitulo de JDBC utilizando JPA. A classe Cliente deverá ser anotada com @Entity do pacote javax.persistence. A anotação @Entity instrui ao provedor de persistência de que a classe em questão deverá ser mapeada para um banco de dados e que também será gerenciada pelo EntityManager. A listagem 14.1 apresenta as anotações necessárias para utilização da classe Cliente como entidade da JPA. Listagem 14.1: Classe Cliente com as anotações da JPA 1 package capitulo14; 2 3 4 5 import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; 6 7 8 @Entity public class Cliente { 9 146 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 10 11 12 java persistence api com hibernate @Id @GeneratedValue private int id; 13 14 private String nome; 15 16 private String cpfCnpj; 17 18 private String endereco; 19 20 private String municipio; 21 22 private String uf; 23 24 25 26 public int getId() { return id; } 27 28 29 30 public void setId(int id) { this.id = id; } 31 32 33 34 public String getNome() { return nome; } 35 36 37 38 public void setNome(String nome) { this.nome = nome; } 39 40 41 42 public String getCpfCnpj() { return cpfCnpj; } 43 44 45 46 public void setCpfCnpj(String cpfCnpj) { this.cpfCnpj = cpfCnpj; } 47 48 49 50 public String getEndereco() { return endereco; } 51 52 53 54 public void setEndereco(String endereco) { this.endereco = endereco; } 55 56 57 58 public String getMunicipio() { return municipio; } 59 60 61 public void setMunicipio(String municipio) { this.municipio = municipio; http://solutioin.com Francisco Calaça, Otávio Calaça 147 Versão 1.2-beta java persistence api com hibernate } 62 63 public String getUf() { return uf; } 64 65 66 67 public void setUf(String uf) { this.uf = uf; } 68 69 70 71 } 14.4. O arquivo persistence.xml O arquivo persistence.xml é o “coração” da JPA. É nele que serão definidas as configurações das conexões, entidades que serão persistidas e o comportamento do engine da JPA. Este arquivo deve ficar dentro do diretório META-INF do classpath da aplicação. As configurações deste arquivo dependerão da implementação JPA utilizada: Hibernate, TopLink, KODO, etc. A listagem 18.12 apresenta o exemplo do arquivo persistence.xml com a implementação do Hibernate. As propriedades desse arquivo estão descritas na tabela 14.1. hibernate.hbm2ddl.auto update - cria as tabelas conforme as anotações das entidades hibernate.dialect Configura o dialeto a ser usado no banco. Mais dialetos podem ser vistos na Tabela 14.2 hibernate.connection.driver_class Configura o driver do banco de dados hibernate.connection.username Configura o usuário do banco de dados hibernate.connection.password Configura a senha do banco de dados hibernate.connection.url Configura a url de conexão com o banco de dados hibernate.show_sql se true mostra no log as expressões SQL utilazadas Tabela 14.1: Alguns dos parâmetros do hibernate Listagem 14.2: Arquivo persistence.xml do nosso projeto 1 2 3 4 5 6 7 8 9 <?xml version="1.0" encoding="UTF -8"?> <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org /2001/ XMLSchema -instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns /persistence/persistence _ 1 _ 0.xsd" > <persistence-unit name="aulajpa"> <properties> <property name="hibernate.hbm2ddl.auto" value="update"/> <property name="hibernate.show _ sql" value="true"/> 10 148 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 11 12 13 14 15 16 17 18 java persistence api com hibernate <property name="hibernate.dialect" value="org.hibernate.dialect. PostgreSQLDialect" /> <property name="hibernate.connection.driver _ class" value="org.postgresql. Driver" /> <property name="hibernate.connection.url" value="jdbc:postgresql: // localhost/treinamento" /> <property name="hibernate.connection.username" value="postgres"/> <property name="hibernate.connection.password" value="123456"/> </properties> </persistence-unit> </persistence> Banco de Dados Dialeto DB2 org.hibernate.dialect.DB2Dialect DB2 AS/400 org.hibernate.dialect.DB2400Dialect DB2 OS390 org.hibernate.dialect.DB2390Dialect PostgreSQL org.hibernate.dialect.PostgreSQLDialect MySQL org.hibernate.dialect.MySQLDialect MySQL com InnoDB org.hibernate.dialect.MySQLInnoDBDialect MySQL com MyISAM org.hibernate.dialect.MySQLMyISAMDialect Oracle (qualque versão) org.hibernate.dialect.OracleDialect Oracle 9i org.hibernate.dialect.Oracle9iDialect Oracle 10g org.hibernate.dialect.Oracle10gDialect Sybase org.hibernate.dialect.SybaseDialect Sybase Anywhere org.hibernate.dialect.SybaseAnywhereDialect Microsoft SQL Server org.hibernate.dialect.SQLServerDialect SAP DB org.hibernate.dialect.SAPDBDialect Informix org.hibernate.dialect.InformixDialect HypersonicSQL org.hibernate.dialect.HSQLDialect Ingres org.hibernate.dialect.IngresDialect Progress org.hibernate.dialect.ProgressDialect Mckoi SQL org.hibernate.dialect.MckoiDialect Interbase org.hibernate.dialect.InterbaseDialect Pointbase org.hibernate.dialect.PointbaseDialect FrontBase org.hibernate.dialect.FrontbaseDialect Firebird org.hibernate.dialect.FirebirdDialect Tabela 14.2: Alguns dos dialetos do hibernate http://solutioin.com Francisco Calaça, Otávio Calaça 149 Versão 1.2-beta 14.5. java persistence api com hibernate O EntityManager Inicialmente deve ser criada uma instância de EntityManagerFactory. Isto é realizado através do código: EntityManagerFactory emf = Persistence.createEntityManagerFactory("aulajpa"); neste momento, o engine da JPA irá validar as tabelas em relação às classes anotadas. Em alguns engines (como é o caso do Hibernate) é possível configurar para que, neste momento, também sejam criadas as tabelas no banco de dados. O EntityManager pode ser criado ou obtido de uma EntityManagerFactory. Você precisa utilizar um EntityManagerFactory para criar instâncias de EntityManager. O método createEntityManager() retorna uma instância de EntityManager. Esta instância irágerenciar o contexto de persistência. A classe da listagem 14.3 apresenta um exemplo de utilização do EntityManager. Listagem 14.3: Classe ContatoDao exemplificando a utilização do EntityManager 1 package capitulo14; 2 3 import java.util.List; 4 5 6 7 8 import import import import javax.persistence.EntityManager; javax.persistence.EntityManagerFactory; javax.persistence.Persistence; javax.persistence.Query; 9 10 public class ClienteDaoJpa { 11 12 private static EntityManagerFactory emf = Persistence.createEntityManagerFactory(" aulajpa" ); 13 14 private EntityManager em = emf.createEntityManager(); 15 16 17 18 19 20 public void incluir(Cliente cliente) { em.getTransaction().begin(); em.persist(cliente); em.getTransaction().commit(); } 21 22 23 24 25 public List<Cliente> listar() { Query query = em.createNativeQuery("select * from cliente", Cliente.class); return query.getResultList(); } 26 27 28 29 30 31 32 public void excluir(int id){ em.getTransaction().begin(); Cliente c = em.find(Cliente.class, id); em.remove(c); em.getTransaction().commit(); } 150 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta java persistence api com hibernate 33 34 } 14.6. A inclusão de clientes com JPA A classe da listagem 14.4 apresenta nossa agenda na versão JPA. Listagem 14.4: Classe Agenda 1 package capitulo14; 2 3 import java.util.List; 4 5 import javax.swing.JOptionPane; 6 7 public class ClienteInclusaoJpa { 8 public static void main(String[] args) { Cliente cliente = new Cliente(); cliente.setNome(JOptionPane.showInputDialog("Nome:")); cliente.setCpfCnpj(JOptionPane.showInputDialog("Cpf/Cnpj:")); cliente.setEndereco(JOptionPane.showInputDialog("Endereço:")); cliente.setMunicipio(JOptionPane.showInputDialog("Município:")); cliente.setUf(JOptionPane.showInputDialog("UF:")); 9 10 11 12 13 14 15 16 ClienteDaoJpa cdao = new ClienteDaoJpa(); cdao.incluir(cliente); 17 18 19 List<Cliente> clientes = cdao.listar(); for(Cliente c : clientes){ System.out.printf("%-30s%-30s%-30s%-30s%-30s\n", c.getNome(), c.getCpfCnpj(), c.getEndereco(), c.getMunicipio(), c.getUf()); } 20 21 22 23 24 25 26 27 28 } 29 30 } 14.6.1 Persistindo entidades Persistir uma entidade é o ato de inseri-la em um banco de dados. Você persiste entidades que ainda não foram criadas no banco de dados. Para isso utilize o método persiste(entidade) do EntityManager. http://solutioin.com Francisco Calaça, Otávio Calaça 151 Versão 1.2-beta 14.6.2 java persistence api com hibernate Localizando entidades O EntityManager possui o método find(classe, id) cujo objetivo é o de localizar entidades no banco de dados. Sua forma de utilização é: em.find(Cliente.class, 2) neste caso será retornado o registro com id = 2 da tabela que persiste os objetos do tipo Cliente. 14.6.3 Removendo entidades Para remover entidades de um banco de dados utilize o método remove(entidade). Somente podem ser removidas entidades que estão no estado de gerenciadas. Para isto é necessário localiza-las antes com find(). 14.6.4 Mesclando entidades Se a entidade não estiver no estado de gerenciada é possível mesclar as alterações com as informações do banco de dados. Isto é realizado com o método merge(entidade). Este método recebe uma entidade não gerenciada e retorna esta mesma entidade gerenciada. 14.7. Relacionamento entre classes Existem quatro tipos de relacionamentos: • Um para um - @OneToOne • Um para muitos - @OneToMany • Muitos para um - @ManyToOne • Muitos para muitos - @ManyToMany Para exemplificar o relacionamento @OneToMany foram criadas as classes das listagens 14.6 e 14.5. Observe a utilização da @OneToMany na propriedade disciplinas da classe Curso. Esta anotação descreve a existência de vários cursos para cada disciplina. A listagem 14.7 cria um objeto do tipo Disciplina e adiciona vários objetos do tipo Curso na disciplina. Após isto é utilizada a JPA-QL para consultar os cursos com suas respectivas disciplinas. Listagem 14.5: Classe Curso do exemplo de relacionamento @OneToMany 1 package capitulo14; 2 3 import static javax.persistence.CascadeType.ALL; 152 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 4 java persistence api com hibernate import static javax.persistence.FetchType.EAGER; 5 6 7 import java.util.ArrayList; import java.util.List; 8 9 10 11 12 13 import import import import import javax.persistence.Entity; javax.persistence.GeneratedValue; javax.persistence.Id; javax.persistence.JoinColumn; javax.persistence.OneToMany; 14 15 16 @Entity public class Curso { 17 @Id @GeneratedValue private int id; 18 19 20 21 private String nome; 22 23 @JoinColumn(name="curso _ id") @OneToMany(cascade=ALL, fetch = EAGER) private List<Disciplina> disciplinas = new ArrayList<Disciplina>(); 24 25 26 27 public String toString() { StringBuffer sb = new StringBuffer(nome); sb.append("\n"); for(Disciplina disciplina : disciplinas){ sb.append(" " ); sb.append(disciplina); sb.append("\n"); } return sb.toString(); } 28 29 30 31 32 33 34 35 36 37 38 public int getId() { return id; } 39 40 41 42 public String getNome() { return nome; } 43 44 45 46 public void setNome(String nome) { this.nome = nome; } 47 48 49 50 public List<Disciplina> getDisciplinas() { return disciplinas; } 51 52 53 54 } http://solutioin.com Francisco Calaça, Otávio Calaça 153 Versão 1.2-beta java persistence api com hibernate Listagem 14.6: Classe Disciplina do exemplo de relacionamento @OneToMany 1 package capitulo14; 2 3 4 5 import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; 6 7 8 @Entity public class Disciplina { 9 @Id @GeneratedValue private int id; 10 11 12 13 private String nome; 14 15 private int cargaHoraria; 16 17 public String toString() { return String.format("%s - %s", nome, cargaHoraria); } 18 19 20 21 public int getId() { return id; } 22 23 24 25 public String getNome() { return nome; } 26 27 28 29 public void setNome(String nome) { this.nome = nome; } 30 31 32 33 public int getCargaHoraria() { return cargaHoraria; } 34 35 36 37 public void setCargaHoraria(int cargaHoraria) { this.cargaHoraria = cargaHoraria; } 38 39 40 41 } Listagem 14.7: Classe Escola do exemplo de relacionamento @OneToMany 1 package capitulo14; 2 3 import java.util.List; 4 5 public class Escola { 6 7 public static void main(String[] args) { 154 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta java persistence api com hibernate Disciplina disciplina1 = new Disciplina(); disciplina1.setNome("Matematica"); 8 9 10 Disciplina disciplina2 = new Disciplina(); disciplina2.setNome("Portugues"); 11 12 13 Disciplina disciplina3 = new Disciplina(); disciplina3.setNome("Fisica"); 14 15 16 Curso curso = new Curso(); curso.setNome("Nucleo comum"); curso.getDisciplinas().add(disciplina1); curso.getDisciplinas().add(disciplina2); curso.getDisciplinas().add(disciplina3); 17 18 19 20 21 22 CursoDaoJpa cursoDaoJpa = new CursoDaoJpa(); cursoDaoJpa.incluir(curso); 23 24 25 List<Curso> cursos = cursoDaoJpa.listar(); for(Curso c : cursos){ System.out.println(c); } 26 27 28 29 30 } 31 32 33 } 14.8. Formas de obtenção de id’s Uma chave primária é a identidade de um determinado bean de entidade. Cada bean de entidade deve ter uma chave primaria e esta deve ser única. A chave primaria pode mapear para uma ou mais propriedades. A JPA permite quatro estratégias: • TABLE - designa uma tabela relacional definida pelo usuário a partir da qual as chaves numéricas serão geradas. • SEQUENCE - Interage com as sequences dos bancos de dados que suportam esta tecnologia como Oracle, PostGres, HSQLDB, etc. • IDENTITY - Utilizada em bancos de dados com suporte a esta forma de geração de ID’s como o SQL Server e o Derby. • AUTO - Utilizada em banco de dados que possuem a funcionalidade autoincrement. No exemplo foi utilizada a estratégia SEQUENCE por ser esta suportada pelo banco de dados Postgres, utilizado neste livro. A classe Cliente apresentada na listagem 14.1 contém este exemplo. Se desejar configurar o nome da sequence no banco de dados, utilize a seguinte sintaxe: http://solutioin.com Francisco Calaça, Otávio Calaça 155 Versão 1.2-beta java persistence api com hibernate @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="produto_seq") @SequenceGenerator(sequenceName="produto_seq", name="produto_seq", allocationSize=1, initialValue=1) 14.9. JPQL - A linguagem consulta da Jpa O Java Persistence Query Language (JPQL) é uma linguagem de consulta orientada a objetos definidos como parte da especificação da Java Persistence API (JPA). Para realizar consultas de objetos é utilizada a JPQL, uma linguagem de consulta de objetos que será traduzida, pela JPA, na linguagem de consulta estruturada: SQL. A classe da 14.5 apresenta um exemplo de JPQL. JPQL é usado para fazer consultas em entidades armazenadas em um banco de dados relacional. Ela é fortemente inspirada na linguagem SQL, e suas consultas assemelham à sintaxe das consultas SQL. A diferença é que operam com objetos de entidade JPA ao invés de diretamente operar com as tabelas de banco de dados. Além de recuperar objetos (consultas SELECT), JPQL é compatível com atualizações (UPDATE e DELETE). Por exemplo, para retornar os cursos (Listagem 14.5) ordenados pelo nome, bastaria utilizar: select c from Curso c order by c.nome Outro exemplo, para retornar apenas os cursos que contenham a disciplica com nome FÍSICA, basta utilizar: select c from Curso c left join fetch c.disciplinas d where d.nome = ’FÍSICA’ 14.9.1 Passagem de parâmetros Para passar parâmetros para as consultas você deve utilizar a seguinte estratégia: Query query = em.createQuery(select c from Curso c where c.nome = :nome); query.setParameter("nome", ’Java’); neste caso, serão retornados todos os registros que contém nome igual a Java. Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 156 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 14.10. java persistence api com hibernate Exercícios 1. O que é o mapeamento objeto-relacinal? 2. Quais os procedimentos necessários para tornar um bean apto a trabalhar com JPA? 3. Para que serve o EntityManager? 4. Quais os tipos de relacionamentos existem na JPA? 5. O que é o arquivo persistence.xml? 6. Quais as formas de obtenção de primary keys existem na JPA? 7. O que é JPA-QL ? http://solutioin.com Francisco Calaça, Otávio Calaça 157 15 A P L I C AT I V O S W E B Construir aplicativos WEB consiste em misturar muitas tecnologias como HTML, CSS e JavaScript em um aplicativo. A grande vantagem dos aplicativos WEB é o fato que a execução deles está no servidor e que a conectividade é máxima. É possível utilizar aplicativos WEB em qualquer região do mundo bastando apenas estar conectado com o sistema. É possível construir aplicativos WEB com Java. O que consistem em apenas utilizar a tecnologia Java para gerar CSS, HTML e JavaScript. Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 15.1. XML XML é a abreviação de EXtensible Markup Language (Linguagem extensível de marcação). Trata-se de uma linguagem que é considerada uma grande evolução na internet. O XML é uma especificação técnica desenvolvida pelo W3C (World Wide Web Consortium - entidade responsável pela definição da de padrões da internet), para ser um padrão de comunicação entre sistemas. Em Java além de troca de informações entre sistemas o XML também é muito utilizado para configurar recursos. O XML provê uma representação estruturada dos dados. Isto o torna amplamente utilizado e de fácil utilização. É possível representar vários tipos de estrutura de dados com XML. O XML provê um padrão que pode codificar o conteúdo, as semânticas e as esquematizações para uma grande variedade de aplicações desde simples até as mais complexas, dentre elas: • Um simples documento. • Um registro estruturado tal como uma ordem de compra de produtos. • Um objeto com métodos e dados como objetos Java ou controles ActiveX. • Um registro de dados. Um exemplo seria o resultado de uma consulta a bancos de dados. • Apresentação gráfica, como interface de aplicações de usuário. • Entidades e tipos de esquema padrões. 159 Versão 1.2-beta aplicativos web • Todos os links entre informações e pessoas na web. O XML é considerado de grande importância na Internet e em grandes intranets porque provê a capacidade de inter operação dos computadores por ter um padrão flexível e aberto e independente de dispositivo. As aplicações podem ser construídas e atualizadas mais rapidamente e também permitem múltiplas formas de visualização dos dados estruturados. Para ser considerado válido um arquivo xml deve, obrigatoriamente: • ter todas as suas tags fechadas; • ter apenas uma tag principal; • todos os valores dos atributos devem ser escritos entre aspas. Na listagem 15.1 é apresentado um exemplo de arquivo xml. Listagem 15.1: Exemplo de xml 1 2 3 4 5 6 <dados> <pessoa nome="Manoel"> <endereco rua="Rua 2" numero="30" /> <endereco rua="Av Goias" numero="2" /> </pessoa> </dados> 15.2. HTML HTML (acrônimo para a expressão inglesa HyperText Markup Language, que significa Linguagem de Marcação de Hipertexto) é uma linguagem de marcação utilizada para produzir páginas na Web. Documentos HTML podem ser interpretados por navegadores. 15.2.1 A estrutura básica de um documento HTML A estrutura de um documento HTML apresenta os seguintes componentes: <html> <head> <title>Título do Documento</title> </head> <body> texto, imagem, links, ... </body> </html> 160 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta <table> aplicativos web Gera uma tabela <tr> Uma linha em uma tabela <td> Uma célula em uma tabela <link> liga recursos na página <form> Cria um formulário <input> Cria um campo de entrada de dados Tabela 15.1: Algumas tags HTML As tags básicas de HTML são: • < html >: define o início de um documento HTML e indica ao navegador que todo conteúdo posterior deve ser tratado como uma série de códigos HTML. • < head >: define o cabeçalho de um documento HTML, que traz informações sobre o documento que está sendo aberto. • < body >: define o conteúdo principal, o corpo do documento. Esta é a parte do documento HTML que é exibida no navegador. No corpo podem-se definir propriedades comuns a toda a página, como cor de fundo, margens, e outras formatações. 15.2.1.1 Cabeçalho Dentro do cabeçalho existem os seguintes comandos: • < title >: define o título da página, que é exibido na barra de título dos navegadores. • < style >: define formatação em CSS. • < script >: define programação de certas funções em página com scripts, podendo adicionar funções de JavaScript. • < link >: define ligações da página com outros arquivos como feeds, CSS, scripts, etc. • < meta >: define propriedades da página, como codificação de caracteres, descrição da página, autor, etc. São meta informações sobre documento. Tais campos são muitos usados por motores de busca para obterem mais informações sobre o documento, afim de classificá-lo melhor. Por exemplo, pode-se adicionar o código < meta name="description" content="descrição da sua página" / > no documento HTML para indicar ao motor de busca que texto de descrição apresentar junto com a ligação para o documento. 15.2.2 Outras tags HTML Algumas das tags HTML podem ser vistas na tabela 15.1. http://solutioin.com Francisco Calaça, Otávio Calaça 161 Versão 1.2-beta 15.3. aplicativos web JavaScript JavaScript é uma linguagem de programação criada pela Netscape em 1995, que a princípio se chamava LiveScript, para atender, principalmente, as seguintes necessidades: • Validação de formulários no lado cliente (programa navegador); • Interação com a página. Assim, foi feita como uma linguagem de script. Javascript tem sintaxe semelhante à do Java, mas é totalmente diferente no conceito e no uso. Possui as seguintes características • Oferece tipagem dinâmica - tipos de variáveis não são definidos; • É interpretada, ao invés de compilada; • Oferece bom suporte a expressões regulares (característica também comum a linguagens de script). Sua união com o CSS é conhecida como DHTML. Usando o Javascript, é possível modificar dinamicamente os estilos dos elementos da página em HTML. Dada sua enorme versatilidade e utilidade ao lidar com ambientes em árvore (como um documento HTML), foi criado a partir desta linguagem um padrão ECMA, o ECMA262, também conhecido como ECMAScript. Este padrão é seguido, por exemplo, pela linguagem ActionScript da Adobe. O uso de JavaScript em páginas HTML deve ser informado ao navegador da seguinte forma: <script type="text/javascript"> /* aqui fica o script */ </script> Caso contrário, o navegador irá interpretar o script como sendo código HTML, escrevendoo na página. Na listagem 15.2 é apresentado um exemplo de JavaScript. Neste exemplo existem duas funções: clicar e formatarData. A função clicar incrementa o valor o botão a cada vez que é clicado no botão. A função formatarData formata uma data com as barras quando o campo de data perde o foco. Listagem 15.2: Exemplo de JavaScript 1 2 3 4 <html> <head> <title>Exemplo de JavaScript</title> </head> 5 6 7 <script type="text/javascript"> var qtdVezes = 0; 162 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 8 9 10 11 12 aplicativos web function clicar(comp){ qtdVezes++; complemento = qtdVezes > 1 ? "es" : ""; comp.value = qtdVezes + " vez" + complemento; } 13 14 15 16 17 18 19 20 function formatarData(comp){ data = comp.value; data = data.substring(0,2) + "/" + data.substring(2,4) + "/" + data.substring(4,8); comp.value = data; } </script> 21 22 23 24 25 26 27 28 <body> Clique no botão: <input type="button" value="Clique" onclick="javascript:clicar(this)"/> <br/> Data:<input type="text" onblur="javascript:formatarData(this)"/> </body> </html> 15.4. CSS Cascading Style Sheets, ou simplesmente CSS, é uma linguagem de estilo utilizada para definir a apresentação de documentos escritos em uma linguagem de marcação, como HTML ou XML. Seu principal benefício é prover a separação entre o formato e o conteúdo de um documento. Ao invés de colocar a formatação dentro do documento, o desenvolvedor cria um link (ligação) para uma página que contém os estilos, procedendo de forma idêntica para todas as páginas de um site. Quando quiser alterar a aparência do site basta portanto modificar apenas um arquivo, o arquivo de estilo. As especificações do CSS podem ser obtidas no site da W3C "Word Wide Web Consortium", um consórcio de diversas empresas que buscam estabelecer padrões para a internet. É importante notar que nenhum browser suporta igualmente as definições do CSS. Desta forma, o webdesigner deve sempre testar suas folhas de estilo em browsers de vários fabricantes, e preferencialmente em mais de uma versão, para se certificar de que o que foi codificado realmente seja apresentado da forma desejada. Com a variação de atualizações dos navegadores (browsers) como Internet Explorer que ficou sem nova versão de 2001 a 2006, o suporte ao CSS pode variar. O Internet Explorer 6, por exemplo, tem suporte total a CSS1 e praticamente nulo a CSS2. Navegadores mais modernos como Opera, Internet Explorer 7 e Mozilla Firefox tem suporte maior, inclusive até a CSS 3, ainda em desenvolvimento. O código: /* comentário em css */ body http://solutioin.com Francisco Calaça, Otávio Calaça 163 Versão 1.2-beta aplicativos web { font-family: Arial, Verdana, sans-serif; background-color: #FFFFFF; margin: 5px 10px; } define fonte padrão Arial, caso não exista substitui por Verdana, caso não exista define qualquer fonte sem serifa. Define também a cor de fundo do corpo da página. Na listagem 15.3 é apresentado um exemplo de uma página HTML. Note a tag link: <link href="estilo.css" type="text/css" rel="stylesheet"/> Esta tag faz ligação com o arquivo da listagem 15.4 que é o arquivo CSS. Observe que no estilo.css existem definições de formatação das tags da página da listagem 15.3. Listagem 15.3: Exemplo de página HTML 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <html> <head> <link href="estilo.css" type="text/css" rel="stylesheet"/> <title>Primeira página HTML</title> </head> <body> <h1>Tabela de Cursos</h1> <table> <tr> <th>Curso</th> <th>Carga Horária</th> <th>Instrutor</th> </tr> <tr> <td>Java</td> <td>80 Horas</td> <td>Francisco</td> </tr> <tr> <td>Delphi</td> <td>160 Horas</td> <td>Danilo</td> </tr> <tr> <td>Linux</td> <td>160 Horas</td> <td>Diogo</td> </tr> </table> </body> </html> Listagem 15.4: estilo.css - exemplo de css 1 h1{ 164 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta font-family: verdana; font-size: 25pt; color: #00aa22; font-weight: bold; 2 3 4 5 6 aplicativos web } 7 8 th{ font-family: verdana; font-size: 15pt; color: #0022aa; 9 10 11 12 13 } td{ font-family: verdana; font-size: 12pt; color: #00aa22; background-color: #ccccff; 14 15 16 17 18 } 15.5. Aplicativos Web com Java Para a construção de aplicativos WEB utilizando o Java será necessário todas as tecnologias apresentadas: • Html, para construção do conteúdo • CSS, para construção da apresentação • JavaScript, para construção do dinamismo como as máscaras A linguagem Java deverá ser executada em um servidor e está auxiliará a criação de conteúdo html, css e javascript. Existem vários servidores WEB. Comumente é chamado de contêiner o servidor que executa o código java. Neste livro será utilizado o contêiner WEB chamado tomcat na sua versão 5.5. 15.5.1 Instalação do Tomcat Para instalar o tomcat siga as seguintes instruções: Faça o download do tomcat através do site tomcat.apache.org Descompacte o arquivo. (Preferencialmente dentro do diretório AreaDeTabalho/MeusAplicativos). Configure a variável de ambiente JAVA_HOME para o diretório raiz onde está instalado o JDK. Vá ao diretorio bin do tomcat e execute o comando startup.bat Abra o browser e acesse o endereço http://localhost:8080. Se aparecer uma página ilustrada na figura 15.1 o tomcat está devidamente instalado. http://solutioin.com Francisco Calaça, Otávio Calaça 165 Versão 1.2-beta aplicativos web Figura 15.1: Tela inicial do tomcat Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 15.6. Exercícios 1. O que são arquivos xml? 2. O que são arquivos html? 3. O que é JavaScript? 4. Crie um script JavaScript para colocar a máscara de data em um campo. 5. O que é css? 6. Pesquise sobre o padrão w3c tableless. 7. Quais os procedimentos necessários para instalação do tomcat? 166 http://solutioin.com Francisco Calaça, Otávio Calaça 16 S E RV L E T S Servlet é uma tecnologia que insere novos recursos a um servidor, a definição mais usada é que são consideradas extensões de servidores, essa tecnologia disponibiliza ao desenvolvedor do sistema uma interface para o servidor de aplicação, através de uma API. As aplicações baseadas em Servlet geram conteúdo dinâmico e interagem com os clientes, utilizando o modelo request/response (requisição e resposta) do protocolo HTTP. Apesar de normalmente utilizam o protocolo HTTP, os Servlets não são restritos a ele. Um Servlet necessita de um contêiner Web para ser executado. Este contêiner Web pode ser um servidor de aplicações como o JBoss, GlassFish, Apache Gerônimo, etc ou apenas um contêiner como o Tomcat. A estrutura de um Servlet é simples, basicamente são classes Java que implementam a interface Servlet. Os servlets que responderão ao protocolo HTTP (a maioria) deveom estender a classe HttpServlet, que implementa a interface Servlet. Além disto é necessário configurar o Servlet no descritor de implantação da aplicação. Este descritor de implantação é o arquivo web.xml. 16.1. Estrutura de uma aplicação web Java As aplicações Java WEB seguem a estrutura apresentada na figura 16.1. Nesta figura é possível observar os seguintes elementos: • app1 - É o contexto. É o diretório onde fica armazenada a aplicação • WEB-INF - É o diretório onde ficam as classes java, as bibliotecas e os arquivos de configuração. • classes - É o diretório onde ficam as classes Java. Este diretório é opcional, precisa existir apenas se existirem classes Java na aplicação. • lib - É o diretório onde ficam os arquivos .jar. Este diretório é opcional, precisa existir apenas se existirem arquivos .jar. • web.xml - É o descritor de implantação. Este arquivo possui as configurações gerais da aplicação. Este arquivo é obrigatório. 16.2. Construindo o primeiro Servlet Para exemplificar a estrutura de um aplicativo WEB Java observe o exemplo. Na listagem 16.1 é apresentada a classe do servlet. Observe que esta classe estende HttpServlet. O 167 Versão 1.2-beta servlets Figura 16.1: Exemplo de estrutura de uma aplicação WEB método doGet é o método executado quando ocorre uma requisição a esse servlet. Note que nesse método é gerada uma resposta html que será apresentada no browser. Para que tudo funcione corretamente é necessário montar a estrutura de um aplicativo web apresentado na figura 16.1. Primeiramente crie o diretório app1. Dentro do diretório app1 crie o diretório WEB-INF. dentro do diretório WEB-INF crie o diretório classes. Compile a classe PrimeiroServlet e após isto coloque o pacote capitulo16 gerado dentro do diretório classes. Note que para compilar essa classe é necessário ter o arquivo servlet.jar configurado no classpath de compilação. Este arquivo pode ser encontrado dentro de common/lib do tomcat instalado. Crie o descritor de implantação apresentado na listagem 18.10 e coloque-o dentro do diretório WEB-INF. Certifique-se de ter ficado como a figura 16.1. Após ter montado esta estrutura coloque-a dentro do diretório webapps do tomcat instalado no capítulo anterior. Certifique-se de que o tomcat esteje sendo executado. Acesse o endereço: http://localhost:8080/app1/prim. Se aparecer a figura 16.2 tudo funcionou corretamente. Listagem 16.1: Classe PrimeiroServlet. Um exemplo de servlet 1 package capitulo16; 2 3 4 import java.io.IOException; import java.io.PrintWriter; 5 6 7 8 9 10 import import import import import javax.servlet.ServletException; javax.servlet.annotation.WebServlet; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; 11 12 13 @WebServlet("/PrimeiroServlet") public class PrimeiroServlet extends HttpServlet { 14 15 16 17 18 19 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<HTML >"); out.println("<HEAD ><TITLE >Primeiro Servlet </TITLE ></HEAD >"); 168 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta servlets out.println("<BODY >"); out.println("<H1>PRIMEIRO SERVLET FUNCIONANDO ...</H1>"); out.println("</BODY >"); out.println("</HTML >"); out.close(); 20 21 22 23 24 } 25 26 27 } Listagem 16.2: O descritor de implantação web.xml 1 2 <web-app> <display-name>Exemplo de servlet</display-name> 3 4 5 6 7 <servlet> <servlet-name>primeiro</servlet-name> <servlet-class>capitulo16.PrimeiroServlet</servlet-class> </servlet> 8 9 10 11 12 13 <servlet-mapping> <servlet-name>primeiro</servlet-name> <url-pattern>/prim</url-pattern> </servlet-mapping> </web-app> Figura 16.2: O primeiro servlet funcionando 16.3. Como fazer no eclipse O eclipse nos ajuda a construir um projeto WEB de forma mais fácil. Isto não o isenta de entender bem toda a estrutura de um aplicativo WEB. http://solutioin.com Francisco Calaça, Otávio Calaça 169 Versão 1.2-beta servlets Vá em File - New - Project. Escolha Dynamic Web Project, conforme ilustrado na figura 16.7. Na tela seguinte é possível configurar o nome da aplicação e em qual servidor será executada. Escolha Apache Tomcat v5.5 conforme a figura 16.8. Se não aparecer esta opção clique no botão New e configure. Na tela seguinte é possível configurar os FrameWorks utilizados neste projeto. Deixe como está. Esta tela está ilustrada na figura 16.9. Por último é possível configurar o nome do contexto. O diretório onde ficará os arquivos WEB e o diretório onde ficarão os arquivos .java conforme mostra a figura 16.10. Figura 16.3: Novo projeto Web no eclipse 16.4. Atendendo requisições com o método get A listagem 16.3 apresenta a classe do servlet que receberá as informações através do método get. Note que todo o código que atenderá a requisição fica dentro do método doGet. Este método recebe dois parâmetros um do tipo HttpServletRequest que possui as informações da requisição e um do tipo HttpServletResponse que possibilita a construção da resposta. É utilizado o método getParameter: String nascimento = request.getParameter("nascimento"); para buscar as informações que vêm da requisição. A listagem 16.4 apresenta a página html que invocará o servlet e enviará as informações através do método get. Note o uso da tag <form action="ExemploGet" method="GET"> 170 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta servlets Figura 16.4: Novo projeto Web no eclipse http://solutioin.com Francisco Calaça, Otávio Calaça 171 Versão 1.2-beta servlets Figura 16.5: Novo projeto Web no eclipse Figura 16.6: Novo projeto Web no eclipse 172 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta servlets Figura 16.7: Novo projeto Web no eclipse Figura 16.8: Configuração do nome do projeto http://solutioin.com Francisco Calaça, Otávio Calaça 173 Versão 1.2-beta servlets Figura 16.9: Configuração dos frameworks web Figura 16.10: Configuração do diretório dos fontes e dos arquivos web 174 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta servlets o atributo action descreve qual recurso será invocado quando for clicado no botao submit e o atributo method descreve qual método será utilizado, no caso GET. Observe que os parâmetros que você digitou no formulário aparecem na url enviada pelo browser. Esta é a característica do método get: envia os parâmetros através da URL. Listagem 16.3: Servlet do exemplo de passagem de parâmetros com o método get 1 package capitulo16; 2 3 4 import java.io.IOException; import java.io.PrintWriter; 5 6 7 8 9 10 11 import import import import import import javax.servlet.RequestDispatcher; javax.servlet.ServletException; javax.servlet.annotation.WebServlet; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; 12 13 14 @WebServlet("/ExemploGet") public class ExemploGet extends HttpServlet { 15 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); String nome = request.getParameter("nome"); String nascimento = request.getParameter("nascimento"); 16 17 18 19 20 21 out.println("<html >"); out.println("<body >"); out.printf("%s nasceu em %s", nome, nascimento); out.println("</body >"); out.println("</html >"); out.close(); 22 23 24 25 26 27 } 28 29 } Listagem 16.4: Página Html que enviará as informações através do método get 1 2 3 4 5 6 7 8 9 10 11 12 <html> <head> <title>Exemplo Get</title> </head> <body> <form action="ExemploGet" method="get"> Nome: <input type="text" name="nome" /><br/> Data de nascimento: <input type="text" name="nascimento" /><br/> <input type="submit" value="Enviar"/> </form> </body> </html> http://solutioin.com Francisco Calaça, Otávio Calaça 175 Versão 1.2-beta 16.5. servlets Atendendo requisições com o método post Diferente do método get o método post envia as informações para o servidor no corpo da solicitação. As informações não aparecerão na URL como no método GET. A listagem 16.5 apresenta o servlet que atenderá às requisições post. Note que agora foi implementado o método doPost. A listagem 16.6 apresenta a página que enviará as informações através do método post. Note que a unica diferença com o envio com método GET é o atributo method da tag form que agora é POST. Listagem 16.5: Servlet do exemplo de passagem de parâmetros com o método post 1 package capitulo16; 2 3 4 import java.io.IOException; import java.io.PrintWriter; 5 6 7 8 9 10 11 import import import import import import javax.servlet.RequestDispatcher; javax.servlet.ServletException; javax.servlet.annotation.WebServlet; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; 12 13 14 @WebServlet("/ExemploPost") public class ExemploPost extends HttpServlet { 15 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); 16 17 18 19 String nome = request.getParameter("nome"); String endereco = request.getParameter("endereco"); String salario = request.getParameter("salario"); 20 21 22 23 out.println("<html >"); out.println("<body"); out.printf("Nome: %s <br/>", nome); out.printf("Endereco: %s <br/>", endereco); out.printf("Salario: %s <br/>", salario); out.println("</body >"); out.println("</html >"); out.close(); 24 25 26 27 28 29 30 31 } 32 33 } Listagem 16.6: Página Html que enviará as informações através do método post 1 2 3 <html> <head> <title>Exemplo método post</title> 176 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 4 5 6 7 8 9 10 11 12 13 14 15 servlets </head> <body> <form action="ExemploPost" method="POST"> <pre> Nome: <input type="text" name="nome" /> Endereco: <input type="text" name="endereco" /> Salario: <input type="text" name="salario" /> <input type="submit" /> </pre> </form> </body> </html> 16.6. Redirect Para exemplificar o redirect pense em um Call Center. Imagine você ligando para um Call Center para fazer uma reclamação de sua conta telefônica. Após ser atendido pelo primeiro atendente você conta toda a história que originou a ligação. O atentende espera até você terminar e diz: Não é comigo. Vou transfefir o senhor para o departamento responsável. Você se irrita um pouco e diz: Tudo bem. Um novo antendente atente e solicita a você que conte o problema a ele. Você conta o problema e ele o ouve até terminar. Quando você termina o novo atendente diz: Também não é comigo. Vou transferir o senhor para o departamento responsável. Aí você um pouco mais irritado espera. Na terceira vez conta, novamente toda a história e assim vai. Neste caso ocorre um redirect. Quando é feito um redirect entre recursos WEB com o protocolo HTTP é como se fosse necessário contar novamente toda a história ao novo recurso e fica claro, para o solicitante, que houve mudança de “servlet atendente”. As páginas das Listagens 16.9 e 16.10 apresentam o resultado. Note o uso do método sendRedirect: response.sendRedirect(pagina); para realizar o redirecionamento para a página de resultado. Com o redirect será feita uma nova requisição para as páginas e você observará que, ao clicar no botão, automaticamente será redirecionado para aprovado.html ou reprovado.html. Ficou claro que quem originou a resposta foram as próprias páginas. Listagem 16.7: Página inicial do exemplo com redirect 1 2 3 4 5 6 7 8 9 <html> <head> <title>Exemplo Redirect</title> </head> <body> <form action="ExemploRedirect" method="post"> Salário: <input type="text" name="salario"/> <input type="submit" value="Enviar"/> </form> http://solutioin.com Francisco Calaça, Otávio Calaça 177 Versão 1.2-beta 10 11 servlets </body> </html> Listagem 16.8: Servlet do exemplo de Redirect 1 package capitulo16; 2 3 import java.io.IOException; 4 5 6 7 8 9 10 import import import import import import javax.servlet.RequestDispatcher; javax.servlet.ServletException; javax.servlet.annotation.WebServlet; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; 11 12 13 @WebServlet("/ExemploRedirect") public class ExemploRedirect extends HttpServlet { 14 protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { double salario = Double.parseDouble(request.getParameter("salario")); String pagina; if(salario >= 5000){ pagina = "aprovado.html"; }else{ pagina = "reprovado.html"; } 15 16 17 18 19 20 21 22 23 response.sendRedirect(pagina); 24 } 25 26 } Listagem 16.9: Tela que apresenta o resultado: aprovado 1 2 3 4 5 6 7 8 <html> <head> <title>Aprovado</title> </head> <body> <h1 style="color: green;">LIMITE APROVADO</h1> </body> </html> Listagem 16.10: Tela que apresenta o resultado: reprovado 1 2 3 4 5 6 7 <html> <head> <title>Rerovado</title> </head> <body> <h1 style="color: red;">LIMITE REPROVADO</h1> </body> 178 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 8 servlets </html> 16.7. Forward Diferente do redirect o forward esconde quem realizou a resposta. Seria como se você tivesse ligado para o Call Center e contado o seu problema. O atendente falasse: -Espera um pouco. Neste momento ele pergunta para um colega que é o especialista naquele problema o que fazer. Após ter a resposta ele volta ao telefone e te conta a resposta. Você não teve que contar novamente sua história. Você também não conheceu quem realmente solucionou seu problema pois a única pessoa que você teve contato foi o atendente inicial. Isto é forward. O servlet da listagem 16.12 apresenta um exemplo de forward. Para a realização do forward foram utilizadas as seguintes instruções: RequestDispatcher rd = request.getRequestDispatcher(pagina); rd.forward(request, response); Note que após clicar no botão você vê a resposta mas não percebe que foi gerada pelas páginas aprovado.html ou reprovado.html. Listagem 16.11: Página inicial do exemplo com forward 1 2 3 4 5 6 7 8 9 10 11 <html> <head> <title>Exemplo Forward</title> </head> <body> <form action="ExemploForward" method="post"> Salário: <input type="text" name="salario"/> <input type="submit" value="Enviar"/> </form> </body> </html> Listagem 16.12: Servlet do exemplo de Forward 1 package capitulo16; 2 3 import java.io.IOException; 4 5 6 7 8 9 10 import import import import import import javax.servlet.RequestDispatcher; javax.servlet.ServletException; javax.servlet.annotation.WebServlet; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; 11 12 13 @WebServlet("/ExemploForward") public class ExemploForward extends HttpServlet{ 14 http://solutioin.com Francisco Calaça, Otávio Calaça 179 Versão 1.2-beta servlets protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { double salario = Double.parseDouble(request.getParameter("salario")); String pagina; if(salario >= 5000){ pagina = "aprovado.html"; }else{ pagina = "reprovado.html"; } 15 16 17 18 19 20 21 22 23 RequestDispatcher rd = request.getRequestDispatcher(pagina); rd.forward(request, response); 24 25 } 26 27 28 } 16.8. Escopo de objetos web Enquanto o usuário estiver em uma página, os valores do componente serão lembrados mesmo quando a página for reexibida, como quando o usuário clica em um botão que retorna nulo. No entanto, quando o usuário sai da página, os valores do componente desaparecem. Para tornar os valores disponíveis para outras páginas, ou para a mesma página, caso o usuário retorne à página, você precisa armazenar os valores. Quando você cria um projeto a partir do IDE, ele cria três Beans gerenciados para armazenar os valores: • Request - requisição • Session - sessão • Application - aplicação A figura 16.11 ilustra esses escopos. 16.8.1 Request Tudo que é armazenado no escopo de request é válido apenas enquanto durar uma requisição. Se o usuário clicar em algum link ou algum servlet realizar um redirec as informações armazenadas neste escopo se perdem. Para acessar este escopo utilize os método: request.getAttribute(‘‘bean’’); // para buscar informações do escopo request.setAttribute(‘‘bean’’, bean); // para colocar informações no escopo. 180 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta servlets Figura 16.11: Ilustração dos escopos WEB 16.8.2 Session Tudo que é armazenado no escopo de session é válido enquanto durar a sessao com o usuário. Uma sessão normalmente é representada com uma janela do browser aberta. É neste escopo que são armazenadas as informações de login do usuário ou o carrinho de compras em uma loja virtual. Para acessar este escopo utilize o método: request.getSession().getAttribute(‘‘bean’’); //para buscar informações do escopo request.getSession().setAttribute(‘‘bean’’, bean); // para colocar informações no escopo. 16.8.3 Application Tudo que é armazenado no escopo de application é valido para todos os usuários mesmo estando em browsers diferentes, mesmo estando em lugares diferentes. Em um chat seria um bom local para armazenar as mensagens que devem ser vistas por todos. Para acessar este escopo utilize o método: getServletContext().getAttribute(‘‘bean’’); //para buscar informações do escopo getServletContext().setAttribute(‘‘bean’’, bean); // para colocar informações no escopo. 16.9. Como distribuir uma aplicação web No início deste capítulo foi apresentada a estrutura de um aplicativo web Java. Existem uma série de detalhes a serem seguidos e que dificultam a distribuição de aplicações Java uma vez que cada aplicativo consiste de vários arquivos. Para solucionar este problema é possível comprimir todos estes arquivos que estão no contexto utilizando o formato zip em um arquivo com extensão .war. http://solutioin.com Francisco Calaça, Otávio Calaça 181 Versão 1.2-beta servlets Assim ao compactar o conteúdo da aplicação em um arquivo com extensão war tornará mais fácil a distribuição dos aplicativos. Atenção é compactado o conteúdo da pasta app1, não a pasta app1. O eclipse possui uma ferramenta que faz isto de forma automática. Para isto, basta clicar com o botão direito do mouse sobre o projeto e exportar o arquivo war. Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 16.10. Exercícios 1. O que é um servlet? 2. Explique a estrutura de um aplicação Java. 3. Quais são os passos para implementação de um servlet ? 4. Qual o diretório do tomcat onde ficam armazenados as aplicações? 5. Diferencie os métodos get e post. 6. Qual a diferenca entre redirect e forward? 7. Quais os escopos de um aplicativo web? 8. O que são arquivos .war ? 182 http://solutioin.com Francisco Calaça, Otávio Calaça 17 J AVA S E RV E R PA G E S JavaServer Pages - JSP - é uma tecnologia que simplifica o processo de desenvolvimento de aplicações web. Com JSP, os desenvolvedores podem rapidamente incorporar elementos dinâmicos em páginas da web, utilizando Java embutido e algumas tags. Estas tags fornecem ao desenvolvedor um meio de acessar dados e lógica de negócio armazenados em objetos Java sem ter que dominar as complexidades do desenvolvimento de aplicações. O JSP também oferece a vantagem de ser facilmente codificado, facilitando assim a elaboração e manutenção de uma aplicação. Além disso, essa tecnologia permite separar a programação lógica (parte dinâmica) da programação visual (parte estática), facilitando o desenvolvimento de aplicações mais robustas, onde programador e designer podem trabalhar no mesmo projeto, mas de forma independente. Os arquivos jsp’s são convertido em servlet’s (arquivos .java) e compilados para arquivos .class. Normalmente a primeira execução do jsp é mais lenta que as demais pois o contêiner está realizando essa operação. 17.1. Elementos do Jsp É possível inserir código Java dentro do servlet a ser gerado a partir do JSP. Isto pode ser feito de três formas: • Scriptlets: que insere dentro do servlet código Java • Expressões: que tem seu valor escrito na página; • Declarações: utilizadas para criarem métodos e classes dentro do JSP. Cada um destes elementos será descrito a seguir. 17.1.1 Scriptlet Scriptlets são trechos de código Java dentro de págianas HTML. Um Scriptlet fica entre as tags <% -- código java -- %> O Trecho de código abaixo é um exemplo de página HTML, com scriptlets JSP que escrevem na tela: “Olá Mundo” <% 183 Versão 1.2-beta java server pages String msg = "Olá Mundo"; out.println("Mensagem: "+msg+"!!"); %> Scriptlets tem acesso à algumas variáveis definidas como request, session, etc.: <% String dados = request.getQueryString(); out.println("Dados anexados: " + dados); %> <% if (Math.random() < 0.5) { %> Você está com <B>Sorte</B>! <% } else { %> Você não está com tanta <B>Sorte</B> assim! <% } %> 17.1.2 Expressões Uma expressão JSP é usada para escrever variáveis Java direntamente na página. Veja o exemplo a seguir: <%= Expressão Java %> A expressão Java será convertida em uma String e escrita na página. Por exemplo, o código seguinte: Data atual: <%= new java.util.Date() %> escreve a data utilizando o toString() da classe Date A listagem 17.1 apresenta um exemplo de scriptlets e expressões. Após implementado, para visualizar este exemplo, acesso a seguinte url no browser: http://localhost:8080/capitulo17/exemploJsp.j Listagem 17.1: Arquivo exemploJsp.jsp. Apresenta um exemplo de scriptlets e expressões 1 2 3 4 5 6 <html> <head> <title>Exemplo de JSP</title> </head> <body> <%for(int i = 0; i < 15; i++){ %> 7 8 Linha: <%=i %> <br/> 9 10 <%} %> 11 12 13 </body> </html> 184 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta java server pages 17.1.3 Declarações Uma declaração JSP define métodos, campos ou classes que serão inseridos no corpo do Servlet gerado pela página. Portanto, o código abaixo: <%! void somar(int a, int b){ . . .} $ %> $ é capaz de declarar um método na página. 17.2. Diretivas Uma diretiva JSP afeta toda a estrutura da página. Este é um exemplo de diretiva: <%@ diretiva atributo=‘‘valor" %> As diretivas existentes são: • include - inclusão de um arquivo na posição da diretiva • page - informações e metadados da página • taglib - inclusão de taglibs 17.2.1 Diretiva include A Listagem 17.2 apresenta o código do menu, que será inserido dentro das demais páginas. Observe na Listagem 17.3 a utilização da diretiva include com o objetivo de incluir o código do menu dentro da página index.jsp. Listagem 17.2: Arquivo menu.jsp 1 2 3 4 <a <a <a <a href="index.jsp">Início</a> href="exemploJsp.jsp">Primeiro Exemplo</a> href="clientes.jsp">Lista de Clientes</a> href="clientes -jstl.jsp">Lista de Clientes com JSTL</a> Listagem 17.3: Arquivo index.jsp 1 <html> <head> 2 <title>Página inicial</title> 3 </head> <body> 4 5 <%@include file="menu.jsp" %> 6 7 <h1>Página inicial</h1> 8 </body> 9 10 </html> http://solutioin.com Francisco Calaça, Otávio Calaça 185 Versão 1.2-beta java server pages Depois de implementar os exemplos das Listagens 17.2 e 17.3 adicione o código: <%@include file="menu.html" %> no arquivo exemploJsp.jsp 17.2.2 Diretiva Page Esta diretiva possui onze atributos diferentes. Observe primeiro como é a sua sintaxe: <%@ page atributo1="valor1" atributo2="valor2" atributo3="valor3" ... %> Por possuir múltiplos atributos a linguagem JSP permite que se declare várias diretivas numa mesma página, porém a único atributo que pode ser repetido é o import. Nas subseções à seguir serão descritos os atributos desta diretiva. 17.2.2.1 ContentType Este atributo indica qual o tipo MIME (Multipurpose Internet Mail Extensions) da resposta está sendo gerada pela JSP. Os tipos mais comuns são: “text/plain”, “text/html”, “text/xml”. Logo abaixo segue o exemplo usado como padrão para as JSPs. <%@ page contentType="text/html" %> 17.2.2.2 pageEncoding Define o caracter enconding da página. <%@ page pageEncoding="UTF-8" %> 17.2.2.3 Extends Serve para indicar a super classe que será usada pelo container JSP no momento de tradução da página em um Servlet Java. Exemplo: <%@ page extends="com.solutioin.taglib.jsp.primeirapagina" %> 17.2.2.4 Import Com o atribuo import, diferente do extends, é capaz de estender um conjunto de classes Java que poderão ser usadas nas páginas JSPs. Exemplo: <%@ page import="java.util.List" %> 17.2.2.5 Language Usado, em geral, para especificar Java como a linguagem de criação de script para a página. Exemplo: <%@ page language="java" %> 186 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta java server pages 17.2.2.6 Info Usado para inserir informações sumarizadas da página, não havendo restrições ao seu tamanho. Exemplo: <%@ page info="Java Para Web" %> 17.2.2.7 Session Session é do tipo boolean, indica se a página está participando do gerenciamento de sessão. Por exemplo, se quisermos dizer que uma página é parte de uma sessão, utiliza-se a seguinte sintaxe: <%@ page session="true" %> 17.2.2.8 Buffer Responsável por controlar a saída bufferizada para uma página JSP. Se for ajustado para “none” o conteúdo de uma JSP é passado instantaneamente à resposta HTTP. O tamanho do buffer é descrito em kilobytes. Exemplo: <%@ page buffer="20kb" %> ou <%@ page buffer="none" %> 17.2.2.9 AutoFlush Semelhante ao Buffer, também é responsável por controlar a saída buferizada, mais exatamente o comportamento do container JSP quando já esteja cheio o Buffer de saída. Neste caso é esvaziado automaticamente o Buffer de saída e o conteúd0o enviado para o servidor HTTP que transmite para o Browser responsável pela solicitação. Sendo do tipo boolean, sua sintaxe é dada abaixo: <%@ page autoFlush="true" %> 17.2.2.10 isThreadSafe Quando uma página JSP é compilada em um Servlet, ela deve ser capaz de atender a múltiplas solicitações. Para isso devemos utilizar o atributo isThreadSafe, caso contrário é necessário defini-lo como “false”. Exemplo: <%@ page isThreadSafe="false" %> 17.2.2.11 errorPage ErrorPage indica uma página alternativa que será exibida caso aconteça um erro não previsto durante o processamento de uma página JSP no container. Exemplo: <%@ page errorPage="/apostila/exemplos/erro.jsp" %> http://solutioin.com Francisco Calaça, Otávio Calaça 187 Versão 1.2-beta java server pages jsp:include Inclui um arquivo que foi gerado em tempo de execução na página jsp:useBean Busca um Bean instanciado. jsp:setProperty Seta a propriedade de um JavaBean. jsp:getProperty Insere a propriedade do JavaBean na página. jsp:forward Realiza um forward para outra página. jsp:plugin Gera um código para embutir plugins Java. Tabela 17.1: tablecaption 17.2.2.12 isErrorPage Responsável por define uma página JSP que servirá como a página de erro padrão para um grupo de páginas JSP. Sendo do tipo boolean, sua sintaxe é descrita abaixo: <%@ page isErrorPage="true"%> 17.3. Ações do JSP Comandos que executam ações durante o processamento do JSP São comandos na sintaxe XML que controlam o comportamento da execução do JSP. Com ações JSP é possível inserir um arquivo dinamicamente, reutilizar um Java Bean, fazer um forward para outra página ou gerar código HTML para um plugin Java. Algumas açoes disponíveis são: 17.4. Biblioteca de tags JSTL A JSTL (Standard Tag Library for JavaServer Pages) foi criada para organizar melhor o código de um JSP evitando a inserção de código Java dentro das mesmas. Normalmente quem edita as páginas JSP são web designers que não sabem programar em Java. JSTL consiste em uma coleção de bibliotecas, tendo cada uma um propósito bem definido, que permitem escrever páginas JSPs sem código Java, aumentando assim a legibilidade do código e a interação entre desenvolvedores e web designers. Cada tag realiza um determinado tipo de processamento (equivalente a código Java dentro de JSP). Exemplo de uma página JSTL <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <html> <body bgcolor="#FFFFFF"> <jsp:useBean id="agora" class="java.util.Date"/> 188 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta java server pages <br> Hoje: <fmt:formatDate value="${agora}" /> <br> Agora: <fmt:formatDate value="${agora}" pattern="dd/MM/yyyy"/> </body> </html> Versão Curta: 25/07/2005 Versão Longa: Segunda-feira, 25 de Julho de 2005 A taglib mais utilizada é a central. Normalmente é prefixada com “c”. Possui tags para trabalhar com condicionais, loops, condicionais, dentre outras. Sua declaração é: <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> Uma tag muito utilizada é a <c:forEach>. Esta tag permite percorrer uma lista de objetos e apresenta-los na página. 17.4.1 EL - Expressão de Linguagem As expressões EL estão sempre dentro de chaves, precedidas pelo símbolo cifrão: ${ . . . } Exemplo: ${cliente.nome} São utilizadas para referenciar objetos no código JSP: Telefone: ${cliente.endereco} ou ainda <c:forEach items="${lista}" var="cliente"> O trecho de código abaixo apresenta todos os contatos de uma lista: <table border="1"> <c:forEach items="${lista}" var="cliente"> <tr> <td>${cliente.id}</td> <td>${cliente.nome}</td> <td>${cliente.endereco}</td> <td>${cliente.municipio}</td> <td>${cliente.uf}</td> <td><a href="ClienteControl?acao=excluir&id=${cliente.id}">excluir</a></td> </tr> </c:forEach> </table> http://solutioin.com Francisco Calaça, Otávio Calaça 189 Versão 1.2-beta 17.5. java server pages MVC - Model View Control Model-view-controller (MVC) é um padrão de arquitetura de software. Com o aumento da complexidade das aplicações desenvolvidas torna-se fundamental a separação entre os dados (Model) e o layout (View). Desta forma, alterações feitas no layout não afetam os dados, e estes poderão ser reorganizados sem alterar o layout. O MVC resolve o problema do reaproveitamento do modelo através da separação das tarefas de acesso aos dados e lógica de negócio da lógica de apresentação e de interacção com o usuário. Para isto é introduzido um componente entre a visão e o modelo: o Controller. Neste sentido, as camadas do MVC representam: Model: A representação "domínio" específica da informação em que a aplicação opera. Por exemplo, aluno, professor e turma fazem parte do domínio de um sistema acadêmico. É comum haver confusão pensando que Model é um outro nome para a camada de domínio. Lógica de domínio adiciona sentido à dados crus (por exemplo, calcular se hoje é aniversário do usuário, ou calcular o total de impostos e fretes sobre um determinado carrinho de compras). Muitas aplicações usam um mecanismo de armazenamento persistente (como banco de dados) para armazenar dados. MVC não cita especificamente a camada para acesso aos dados, porque subentende-se que estes métodos estariam encapsulados pelo Model. View: "Renderiza" o model em uma forma específica para a interação, geralmente uma interface de usuário. Controller: Processa e responde a eventos, geralmente ações do usuário, e pode invocar alterações no Model. 17.5.1 O cadastro de clientes Agora será apresentado uma versão WEB para o cadastro de clientes apresentado no Capítulo 13. Para que este cadastro funcione é necessário criar o servlet ClienteControl. Este servlet representa a camada de Controle do nosso exemplo. Seu código está na Listagem 18.4. Na listagem 17.5 é apresentado o código da tela. Listagem 17.4: Servlet que representa o Controle 1 package capitulo17; 2 3 import java.io.IOException; 4 5 6 7 8 9 10 import import import import import import javax.servlet.RequestDispatcher; javax.servlet.ServletException; javax.servlet.annotation.WebServlet; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; 11 12 13 import capitulo13.Cliente; import capitulo13.ClienteDao; 190 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta java server pages 14 15 16 @WebServlet("/ClienteControl") public class ClienteControl extends HttpServlet { 17 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String acao = request.getParameter("acao"); ClienteDao clienteDao = new ClienteDao(); if(acao == null){ request.setAttribute("lista", clienteDao.listar()); RequestDispatcher rd = request .getRequestDispatcher("cliente.jsp"); rd.forward(request, response); }else if(acao.equals("excluir")){ int id = Integer.parseInt(request.getParameter("id")); clienteDao.excluir(id); response.sendRedirect("ClienteControl"); }else if(acao.equals("confirmar")){ Cliente cliente = new Cliente(); cliente.setNome(request.getParameter("nome")); cliente.setCpfCnpj(request.getParameter("cpfCnpj")); cliente.setEndereco(request.getParameter("endereco")); cliente.setMunicipio(request.getParameter("municipio")); cliente.setUf(request.getParameter("uf")); clienteDao.incluir(cliente); response.sendRedirect("ClienteControl"); } } 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } 41 42 43 44 45 } Listagem 17.5: Página de cadastro de clientes 1 <%@ taglib prefix="c" uri="http ://java.sun.com/jsp/jstl/core"%> 2 3 4 5 6 7 <html> <head> <title>Cadastro de Clientes</title> </head> <body> 8 9 <%@ include file="menu.jsp" %> 10 11 12 13 14 15 16 <form action="ClienteControl"> <pre> <input type="hidden" Nome: <input type="text" CPF/CNPJ: <input type="text" Endereço: <input type="text" http://solutioin.com Francisco Calaça, Otávio Calaça name="acao" value="confirmar"/> name="nome"/> name="cpfCnpj"/> name="endereco"/> 191 Versão 1.2-beta 17 18 19 20 21 java server pages Município: <input type="text" name="municipio"/> UF: <input type="text" name="uf"/> <input type="submit" value="Confirmar"/> </pre> </form> 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <table border="1" rules="all"> <c:forEach items="${lista}" var="cliente"> <tr> <td>${cliente.id}</td> <td>${cliente.nome}</td> <td>${cliente.cpfCnpj}</td> <td>${cliente.endereco}</td> <td>${cliente.municipio}</td> <td>${cliente.uf}</td> <td><a href="ClienteControl?acao=excluir&id=${cliente.id}">excluir</a> </td> </tr> </c:forEach> </table> 37 38 39 40 </body> </html> Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 17.6. Exercícios 1. O é o JSP? 2. Quais são os elementos de um JSP? Para que serve cada um deles? 3. Para que servem as diretivas ? 4. O que é a Expressão de Linguagem? 5. Explique o MVC. 6. No exemplo da Agenda WEB crie a funcionalidade alterar contatos. 192 http://solutioin.com Francisco Calaça, Otávio Calaça 18 I N T R O D U Ç Ã O A O J AVA S E RV E R F A C E S JavaServer Faces é um poderoso framework para desenvolvimento Java EE. Seus princípios se baseiam no processamento de eventos gerados pelo usuário na página web como: um clique no botão, alteração do conteúdo de um campo de texto. O JSF usa o padrão MVC como base de funcionamento. Para ser processada uma página JSF ela deve passar por um controlador representado pelo Servlet FacesServlet. A execução de uma chamada JSF é dada pela seguinte seqüência: o FacesServlet recebe a chamada, cria o FacesContext, logo é atribuído o controle ao ciclo de vida (LifeCycle) que processa o contexto em 6 fases: reconstituição da view, aplicação dos valores da requisição, validação dos dados, atualização do modelo de dados, chamada ao aplicativo e geração da resposta. Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 18.1. Fazendo JavaServer Faces funcionar Para criar o primeiro projeto JavaServer Faces é necessário criar um projeto do tipo Dynamic Web Project. Na tela onde você coloca o nome do projeto, configure o framework JavaServer Faces v2.0 Project conforme ilustrado na Figura 18.1. Clique em next. . . next. . . até encontrar a tela apresentada na Figura 18.3. Nesta tela, escolha: Disable Library Configuration conforme apresentado na figura. Por último copie os arquivos .jar, disponibilizados na pasta Material para o diretório lib do projeto, conforme ilustrado na Figura 18.3. 18.2. Managed bean O Managed Bean é uma classe onde são colocados os códigos Java que são executados à partir dos componentes da tela. Nele é possível escrever código Java para atenter a eventos da tela, recebe dados, e executa tarefas. Trata-se e um classe que deve ter um construtor default, getters e setters. Um Managed Bean não necessita herdar de nenhuma classe. Um exemplo de Managed Bean pode ser visto na listagem 18.1. O Managed Bean deve ser declarado no arquivo faces-config.xml da seguinte forma: 193 Versão 1.2-beta introdução ao javaserver faces Figura 18.1: Escolha JavaServer Faces v2.0 Project 194 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta introdução ao javaserver faces Figura 18.2: Escolha Disable Library Configuration http://solutioin.com Francisco Calaça, Otávio Calaça 195 Versão 1.2-beta introdução ao javaserver faces Figura 18.3: Copie estes jar’s para o diretório lib <managed-bean> <managed-bean-name>exemploControl</managed-bean-name> <managed-bean-class>aulajsf.ExemploControl</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> Listagem 18.1: Exemplo do primeiro ManagedBean 1 package aulajsf; 2 3 import javax.faces.event.ActionEvent; 4 5 public class ExemploControl { 6 private String entrada; 7 8 private String saida; 9 10 public void executar(ActionEvent evt){ saida = String.format(" * %s - %s * ", entrada, entrada.toUpperCase()); } 11 12 13 14 public String getEntrada() { return entrada; } 15 16 17 18 196 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta introdução ao javaserver faces public void setEntrada(String entrada) { this.entrada = entrada; } 19 20 21 22 public String getSaida() { return saida; } 23 24 25 26 public void setSaida(String saida) { this.saida = saida; } 27 28 29 30 31 } 18.3. Tags básicas O JavaServer Faces possui dois conjuntos de tags: • tags para renderização de componentes HTML • tags Core 18.3.1 Tags JSF para renderização de HTML As tags JSF HTML básicas podem ser vistas na tabela 18.1. Observe que elas estão relacionadas com a taglib declarada com: "http://java.sun.com/jsf/html" As tags JSF HTML são utilizadas para construir componentes html na página como tabelas, campos de entrada, etc. Existem projetos JSF como o Primefaces, Richfaces, Icefaces, Myfaces que possuem mais componentes como calendário, tabela ordenável, menus, etc. 18.3.2 Tags Core do JSF As tags core do JSF permitem passar informações de configurações para os componentes, validações, conversões e metadados. Algumas estão listadas na tabela 18.2. Estão na biblioteca de tags declarada : "http://java.sun.com/jsf/core" 18.3.3 Exemplo de uso das Tags Um exemplo de utilização das tags JSF pode ser visto na listagem 18.2. Observe que todo o conteúdo JSF foi colocado dentro das tags: http://solutioin.com Francisco Calaça, Otávio Calaça 197 Versão 1.2-beta introdução ao javaserver faces <h:head> HTML head <h:body> HTML body <h:form> HTML form <h:inputText> Campo de entrada de texto (uma linha) <h:inputTextarea> Campo de entrada de texto (multilinhas) <h:inputSecret> Campo de entrada de senhas <h:inputHidden> Campo escondido <h:outputLabel> Rótulo para outros componentes <h:outputLink> link HTML <h:outputFormat> Igual a outputText, mas formata as mensagens <h:outputText> Saída de texto <h:commandButton> Botão: submit, reset ou pushbutton <h:commandLink> Link que atua como um botão <h:message> Apresenta a mensagem mais recente do componente <h:messages> Apresenta todas as mensagens <h:graphicImage> Apresenta uma imagem <h:selectOneListbox> Listbox com seleção de um elemento <h:selectOneMenu> ComboBox <h:selectOneRadio> Conjunto de botões radio <h:selectBooleanCheckbox> Checkbox <h:selectManyCheckbox> Conjunto de checkboxes <h:selectManyListbox> Listbox com seleção de vários elementos <h:selectManyMenu> Menu multiselecionavel <h:panelGrid> tabela HTML <h:panelGroup> Agrupa dois ou mais componentes <h:dataTable> Uma tabela utilizada para grid de dados <h:column> Coluna em um dataTable Tabela 18.1: Tags JSF para renderização de componentes HTML <f:view> . . . </f:view> A tag: <h:inputText /> é utilizada para entrada de texto. A tag: <h:commandButton /> cria um botão que executa ações no Managed Bean. 198 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta introdução ao javaserver faces <f:view> Cria uma visão <f:facet> Possibilita configurar parâmetros de componentes <f:convertDateTime> converte datas e horas Tabela 18.2: Tags Core do JSF Listagem 18.2: Exemplo da primerita tela JSF 1 2 3 <html xmlns="http://www.w3.org /1999/ xhtml" xmlns:h="http :// java.sun.com/jsf/html" xmlns:f="http ://java.sun.com/jsf/core"> 4 5 <h:head> 6 7 </h:head> 8 9 10 11 12 13 14 15 16 17 <h:body> <h:form> <h:inputText value="#{ exemploControl.entrada}" /> <h:commandButton ajax="false" actionListener="#{ exemploControl.executar}" value="Executar" /> <h:outputText value="#{ exemploControl.saida}" /> </h:form> </h:body> </html> Dica: Para acessar a tela da listagem 18.2 no browser, digite a url: http://localhost:8080/aulajsf/faces/exemplo.xhtml Após iniciar o servidor. 18.4. Expressões de Ligação - EL Na listagem 18.2 forão utilizadas as expressões de ligações: #{ . . . } para ligar os componentes da página com o managed bean. Por exemplo, a expressão #{exemploControl.entrada} liga o campo de entrada de texto com o atributo nome da classe ExemploControl (ManagedBean). A expressão #{exemploControl.executar} http://solutioin.com Francisco Calaça, Otávio Calaça 199 Versão 1.2-beta introdução ao javaserver faces liga o método executar com o botão. Não confunda as expressões de ligação do JSF com as expressões de linguagem vistas no Capítulo 17. As expressões de ligação: #{ . . . } São capazes de setar e buscar os valores do bean. Enquanto que as expressões de linguagem: ${ . . . } São apenas capazes de buscar os valores do bean. 18.4.1 Ligações com atributos Ao utilizar EL com atributos é necessário liga-las através do atributo value do componente a ser ligado. Na listagem 18.2 os atributos: entrada e saida da classe ExemploControl foram ligados com o atributo value dos componentes. É obrigatória a existência do método get para o atributo a ser ligado. A necessidade do método set é apenas para os componentes que alteram valores como os campos de entrada. 18.4.2 Ligações com métodos Ao utilizar EL com métodos é necessário liga-las através dos atributos listados na tabela 18.3: action para acões actionListener para eventos de ação (clique do mouse no botão) valueChangeListener para eventos de mudança de valor Tabela 18.3: Tabela de tipos de ligações com métodos Observe que existem dois tipos de ligações: • com ações • com listeners de eventos As ligações com ações são utilizadas com as navegações entre páginas (assunto discutido logo após). A assinatura do método de ação deve ser: public String nomeMetodo() Observe que este deve retornar uma String que será utilizada para a navegação. As ligações com eventos são utilizadas com eventos de cliques e mudança de valores. As assinaturas dos métodos devem ser: 200 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta introdução ao javaserver faces public void nomeMetodo(ActionEvent evento) para listeners de eventos de ação e public void nomeMetodo(ValueChangeEvent evento) para listeners de eventos de mudança de valor. 18.5. Configurar o Primefaces Para o Primefaces funcionar corretamente, adicione o código da Listagem 18.3 no arquivo web.xml. Listagem 18.3: Configuração do Primefaces 1 2 3 4 <context-param> <param-name>primefaces.THEME</param-name> <param-value>blitzer</param-value> </context-param> 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <context-param> <param-name>javax.faces.DEFAULT_SUFFIX</param-name> <param-value>.xhtml</param-value> </context-param> <context-param> <param-name>javax.faces.FACELETS_VIEW_MAPPINGS</param-name> <param-value>*.xhtml</param-value> </context-param> <filter> <filter-name>PrimeFaces FileUpload Filter</filter-name> <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class> </filter> <filter-mapping> <filter-name>PrimeFaces FileUpload Filter</filter-name> <servlet-name>Faces Servlet</servlet-name> </filter-mapping> 22 23 24 25 26 27 28 29 30 <servlet> <servlet-name>Resource Servlet</servlet-name> <servlet-class>org.primefaces.resource.ResourceServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Resource Servlet</servlet-name> <url-pattern>/primefaces_resource/*</url-pattern> </servlet-mapping> http://solutioin.com Francisco Calaça, Otávio Calaça 201 Versão 1.2-beta 18.6. introdução ao javaserver faces Cadastro de Clientes Nesta seção implementaremos a tela para cadastrar clientes. Serão utilizadas as classes implementadas no Capítulo 13. Portanto, é necessário configurar o projeto aulajsf para se referenciar ao projeto criado naquele capítulo. A Listagem 18.4 apresenta o ManagedBean, que neste caso age como Controlador, do cadastro de clientes. Após a implementação desta classe é necessário adicionar a seguinte configuração no arquivo faces-config.xml: <managed-bean> <managed-bean-name>clienteControl</managed-bean-name> <managed-bean-class>aulajsf.ClienteControl</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> Esta configuração fará o ManagedBean ClienteControl acessível à partir do arquivo JSF. A Listagem 18.5 apresenta o código para criação da tela para manter clientes. Listagem 18.4: Controlador do cadastro de Clientes 1 package aulajsf; 2 3 4 import java.util.ArrayList; import java.util.List; 5 6 7 8 import javax.faces.component.UIParameter; import javax.faces.event.ActionEvent; import javax.faces.model.SelectItem; 9 10 import org.primefaces.event.RowEditEvent; 11 12 13 import capitulo13.Cliente; import capitulo13.ClienteDao; 14 15 public class ClienteControl { 16 17 private Cliente cliente = new Cliente(); 18 19 private ClienteDao clienteDao = new ClienteDao(); 20 21 private List<Cliente> clientes = new ArrayList<Cliente>(); 22 23 24 25 26 27 28 29 30 31 public void confirmar(ActionEvent evt){ if(cliente.getId() == 0){ clienteDao.incluir(cliente); }else{ clienteDao.alterar(cliente); } cliente = new Cliente(); listar(evt); } 202 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta introdução ao javaserver faces 32 public void gravar(RowEditEvent event){ Cliente c = (Cliente) event.getObject(); clienteDao.alterar(c); } 33 34 35 36 37 public List<SelectItem> getUfs(){ List<SelectItem> result = new ArrayList<SelectItem>(); for(EnumUf uf : EnumUf.values()){ result.add(new SelectItem(uf.toString(), uf.getDescricao())); } return result; } 38 39 40 41 42 43 44 45 public void excluirCliente(ActionEvent evt){ UIParameter param = (UIParameter) evt.getComponent().findComponent("cliExcluir"); Cliente c = (Cliente) param.getValue(); clienteDao.excluir(c.getId()); listar(evt); } 46 47 48 49 50 51 52 public void listar(ActionEvent evt){ clientes = clienteDao.listar(); } 53 54 55 56 public Cliente getCliente() { return cliente; } 57 58 59 60 public void setCliente(Cliente cliente) { this.cliente = cliente; } 61 62 63 64 public List<Cliente> getClientes() { return clientes; } 65 66 67 68 69 70 71 } Listagem 18.5: Arquivo cliente.xhtml 1 2 3 4 <html xmlns="http://www.w3.org /1999/ xhtml" xmlns:h="http :// java.sun.com/jsf/html" xmlns:f="http ://java.sun.com/jsf/core" xmlns:p="http :// primefaces.org/ui"> 5 6 <h:head> 7 8 </h:head> 9 10 <h:body> http://solutioin.com Francisco Calaça, Otávio Calaça 203 Versão 1.2-beta 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 introdução ao javaserver faces <h:form> <p:panel header="Manter Clientes"> <h:panelGrid columns="2"> <h:outputText value="Nome:" /> <p:inputText value="#{ clienteControl.cliente.nome}"></p:inputText> <h:outputText value="CPF/CNPJ:" /> <p:inputText value="#{ clienteControl.cliente.cpfcnpj}"></p:inputText> <h:outputText value="Endereço:" /> <p:inputText value="#{ clienteControl.cliente.endereco}"></p:inputText> <h:outputText value=" M u n i c à p i o :" /> <p:inputText value="#{ clienteControl.cliente.municipio}"></p:inputText> <h:outputText value="UF:" /> <p:inputText value="#{ clienteControl.cliente.uf}"></p:inputText> <p:commandButton ajax="false" actionListener="#{ clienteControl.confirmar}" value="Confirmar"></p:commandButton> <p:commandButton ajax="false" actionListener="#{ clienteControl.listar}" value="Listar"></p:commandButton> </h:panelGrid> 29 30 31 32 33 34 35 <p:dataTable value="#{ clienteControl.clientes}" var="cli" editable="true"> <f:facet name="header"> <h:outputText value="Clientes" /> </f:facet> <p:ajax event="rowEdit" listener="#{ clienteControl.gravar}"></p:ajax> 36 <p:column headerText="Nome" sortBy="#{cli.nome}" filterBy="#{cli.nome}"> <p:cellEditor> <f:facet name="output"> <h:outputText value="#{cli.nome}" /> </f:facet> <f:facet name="input"> <p:inputText value="#{cli.nome}" /> </f:facet> </p:cellEditor> </p:column> <p:column headerText="Cpf/Cnpj" sortBy="#{cli.cpfcnpj}"> <h:outputText value="#{cli.cpfcnpj}" /> </p:column> <p:column> <p:tooltip for="editar" hideEffect="explode" value="Clique aqui para editar #{cli.nome}" /> <p:rowEditor id="editar" /> </p:column> 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 <p:column headerText="UF" sortBy="#{cli.uf}" filterBy="#{cli.uf}"> <p:cellEditor> <f:facet name="output"> <h:outputText value="#{cli.uf}" /> </f:facet> <f:facet name="input"> 57 58 59 60 61 62 204 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 63 64 65 66 67 68 69 introdução ao javaserver faces <p:selectOneMenu value="#{cli.uf}"> <f:selectItem itemLabel="Selecione" /> <f:selectItems value="#{ clienteControl.ufs}"></f:selectItems> </p:selectOneMenu> </f:facet> </p:cellEditor> </p:column> 70 71 72 73 74 75 76 77 78 79 <p:column> <p:commandButton actionListener="#{ clienteControl.excluirCliente}" icon="ui-icon -trash"> <f:param id="cliExcluir" value="#{cli}"></f:param> </p:commandButton> </p:column> </p:dataTable> </p:panel> </h:form> 80 81 82 </h:body> </html> 18.7. Cadastro de Produtos (com JPA) Listagem 18.6: Classe Produto 1 package aulajsf; 2 3 4 5 import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; 6 7 8 @Entity public class Produto { 9 10 11 12 @Id @GeneratedValue private int id; 13 14 private String descricao; 15 16 private double valor; 17 18 private int quantidade; 19 20 21 22 public int getId() { return id; } 23 24 25 public void setId(int id) { this.id = id; http://solutioin.com Francisco Calaça, Otávio Calaça 205 Versão 1.2-beta introdução ao javaserver faces } 26 27 public String getDescricao() { return descricao; } 28 29 30 31 public void setDescricao(String descricao) { this.descricao = descricao; } 32 33 34 35 public double getValor() { return valor; } 36 37 38 39 public void setValor(double valor) { this.valor = valor; } 40 41 42 43 public int getQuantidade() { return quantidade; } 44 45 46 47 public void setQuantidade(int quantidade) { this.quantidade = quantidade; } 48 49 50 51 52 } Listagem 18.7: Classe ProdutoDao 1 package aulajsf; 2 3 import java.util.List; 4 5 6 7 8 import import import import javax.persistence.EntityManager; javax.persistence.EntityManagerFactory; javax.persistence.Persistence; javax.persistence.Query; 9 10 public class ProdutoDao { 11 12 13 private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("aulajpa"); 14 15 private EntityManager em = emf.createEntityManager(); 16 17 18 19 20 21 public void incluir(Produto p){ em.getTransaction().begin(); em.persist(p); em.getTransaction().commit(); } 22 23 public void alterar(Produto p){ 206 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta introdução ao javaserver faces em.getTransaction().begin(); em.merge(p); em.getTransaction().commit(); 24 25 26 } 27 28 public Produto consultar(int id){ return em.find(Produto.class, id); } 29 30 31 32 public void excluir(int id){ em.getTransaction().begin(); Produto p = consultar(id); em.remove(p); em.getTransaction().commit(); } 33 34 35 36 37 38 39 public List<Produto> listar(){ Query query = em.createQuery("select p from Produto p"); List<Produto> prods = query.getResultList(); return prods; } 40 41 42 43 44 45 public List<Produto> listar(String descricao){ Query query = em.createQuery("select p from Produto p where upper(p.descricao) like upper(: descricao)" ); query.setParameter("descricao", "%"+descricao+"%"); List<Produto> prods = query.getResultList(); return prods; } 46 47 48 49 50 51 52 53 } Listagem 18.8: Classe ProdutoControl 1 package aulajsf; 2 3 4 import java.util.ArrayList; import java.util.List; 5 6 import javax.faces.event.ActionEvent; 7 8 import org.primefaces.event.RowEditEvent; 9 10 public class ProdutoControl { 11 12 private Produto produto = new Produto(); 13 14 private List<Produto> produtos = new ArrayList<Produto>(); 15 16 private ProdutoDao produtoDao = new ProdutoDao(); 17 18 19 public void confirmar(ActionEvent evt){ produtoDao.alterar(produto); http://solutioin.com Francisco Calaça, Otávio Calaça 207 Versão 1.2-beta introdução ao javaserver faces listar(evt); produto = new Produto(); 20 21 } 22 23 public void listar(ActionEvent evt){ produtos = produtoDao.listar(); } 24 25 26 27 public void gravar(RowEditEvent e){ Produto p = (Produto) e.getObject(); produtoDao.alterar(p); 28 29 30 31 } 32 33 public Produto getProduto() { return produto; } 34 35 36 37 public void setProduto(Produto produto) { this.produto = produto; } 38 39 40 41 public List<Produto> getProdutos() { return produtos; } 42 43 44 45 46 } Listagem 18.9: Tela produto.xhtml 1 2 3 4 <html xmlns="http ://www.w3.org /1999/ xhtml" xmlns:h="http ://java.sun.com/jsf/html" xmlns:f="http ://java.sun.com/jsf/core" xmlns:p="http :// primefaces.org/ui"> 5 6 <h:head> 7 8 </h:head> 9 10 11 12 13 14 15 16 17 18 19 <h:body> <h:form> <p:panel header="Manter Produtos"> <h:panelGrid columns="2"> <h:outputText value="Descrição:" /> <p:inputText value="#{ produtoControl.produto.descricao}"></p:inputText> <h:outputText value="Quantidade:" /> <p:inputText value="#{ produtoControl.produto.quantidade}"></p:inputText> <h:outputText value="Valor:" /> <p:inputText value="#{ produtoControl.produto.valor}"></p:inputText> 20 <p:commandButton ajax="false" actionListener="#{ produtoControl.confirmar}" value="Confirmar"></p:commandButton> 21 22 23 208 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 24 25 introdução ao javaserver faces <p:commandButton ajax="false" actionListener="#{ produtoControl.listar}" value="Listar"></p:commandButton> 26 27 </h:panelGrid> 28 29 30 <p:dataTable value="#{ produtoControl.produtos}" var="prod" editable="true"> 31 32 33 34 35 <f:facet name="header"> <h:outputText value="Produtos" /> </f:facet> <p:ajax event="rowEdit" listener="#{ produtoControl.gravar}"></p:ajax> 36 37 38 39 40 41 42 43 44 45 46 47 <p:column headerText="Nome" sortBy="#{prod.descricao}" filterBy="#{prod.descricao}"> <p:cellEditor> <f:facet name="output"> <h:outputText value="#{prod.descricao}" /> </f:facet> <f:facet name="input"> <p:inputText value="#{prod.descricao}" /> </f:facet> </p:cellEditor> </p:column> 48 49 50 51 52 53 54 <p:column> <p:commandButton ajax="false" value="Selecionar"> <f:setPropertyActionListener target="#{ produtoControl.produto}" value="#{prod}"></f:setPropertyActionListener> </p:commandButton> </p:column> 55 56 57 58 <p:column> <p:rowEditor></p:rowEditor> </p:column> 59 60 61 62 </p:dataTable> </p:panel> </h:form> 63 64 65 </h:body> </html> Finalmente, os arquivos de configuração do projeto estão nas Listagens 18.10 e 18.11. Listagem 18.10: web.xml 1 2 3 <?xml version="1.0" encoding="UTF -8"?> <web-app xmlns:xsi="http://www.w3.org /2001/ XMLSchema -instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/ javaee/web -app _ 2 _ 5.xsd" 4 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/ javaee/web -app _ 3 _ 0.xsd" http://solutioin.com Francisco Calaça, Otávio Calaça 209 Versão 1.2-beta 5 6 introdução ao javaserver faces version="3.0"> <display-name>capitulo18</display-name> 7 8 9 10 11 <context-param> <param-name>primefaces.THEME</param-name> <param-value>blitzer</param-value> </context-param> 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <context-param> <param-name>javax.faces.DEFAULT_SUFFIX</param-name> <param-value>.xhtml</param-value> </context-param> <context-param> <param-name>javax.faces.FACELETS_VIEW_MAPPINGS</param-name> <param-value>*.xhtml</param-value> </context-param> <filter> <filter-name>PrimeFaces FileUpload Filter</filter-name> <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class> </filter> <filter-mapping> <filter-name>PrimeFaces FileUpload Filter</filter-name> <servlet-name>Faces Servlet</servlet-name> </filter-mapping> 29 30 31 32 33 34 35 36 37 <servlet> <servlet-name>Resource Servlet</servlet-name> <servlet-class>org.primefaces.resource.ResourceServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Resource Servlet</servlet-name> <url-pattern>/primefaces_resource/*</url-pattern> </servlet-mapping> 38 39 40 41 42 43 44 45 46 47 48 <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> </web-app> Listagem 18.11: faces-config.xml 1 2 3 4 <?xml version="1.0" encoding="UTF -8"?> <faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xi="http://www.w3.org /2001/ XInclude" xmlns:xsi="http://www.w3.org /2001/ XMLSchema -instance" xsi:schemaLocation="http://java .sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web -facesconfig _ 2 _ 0.xsd" > 210 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 introdução ao javaserver faces <managed-bean> <managed-bean-name>exemploControl</managed-bean-name> <managed-bean-class>aulajsf.ExemploControl</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <managed-bean> <managed-bean-name>clienteControl</managed-bean-name> <managed-bean-class>aulajsf.ClienteControl</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <managed-bean> <managed-bean-name>produtoControl</managed-bean-name> <managed-bean-class>aulajsf.ProdutoControl</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <managed-bean> <managed-bean-name>produtoListControl</managed-bean-name> <managed-bean-class>aulajsf.ProdutoListControl</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> </faces-config> Na Listagem 18.12 é apresentado o código do arquivo persistence.xml, necessário para o funcionamento da JPA. Listagem 18.12: persistence.xml 1 2 3 <?xml version="1.0" encoding="UTF -8"?> <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org /2001/ XMLSchema -instance" 4 5 6 7 8 9 10 11 12 13 14 15 16 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns /persistence/persistence _ 1 _ 0.xsd" > <persistence-unit name="aulajpa"> <properties> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.show _ sql" value="true" /> <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" /> <property name="hibernate.connection.url" value="jdbc:postgresql: // localhost/ treinamento" /> <property name="hibernate.connection.driver _ class" value="org.postgresql.Driver" /> <property name="hibernate.connection.username" value="postgres" /> <property name="hibernate.connection.password" value="123456" /> </properties> </persistence-unit> </persistence> Dica: Não esqueça de adicionar as dependências da JPA nas libs do projeto de JSF. http://solutioin.com Francisco Calaça, Otávio Calaça 211 Versão 1.2-beta 18.8. introdução ao javaserver faces Conversores Inicialmente vamos verificar a necessidade de utilizar conversores JSF. Imagine uma tela de uma aplicação web onde o usuário entra com uma informação no formato String. Suponha que esta informação deva ser convertida em um valor numérico como uma idade ou um salário. Esta conversão deve ser feita de forma automática para que, no Managed Bean a variável já possa ser declarada como inteira ou ponto flutuante. Um outro exemplo pode acontecer com datas. Nestes casos utilizamos conversores. Por exemplo, para converter números, utize: <h:inputText id="salary" value="#{PessoaControl.salario}"> <f:convertNumber pattern="###,##0.00"/> </h:inputText> Para converter datas, utilize: <h:inputText id="date" value="#{PessoaControl.dataNascimento}"> <f:convertDateTime pattern="dd/MM/yyyy"/> </h:inputText> 18.8.1 Conversores personalizados Em muitas situações é necessário converter objetos de classes do modelo da aplicação para serem utilizados em telas JSF. Por exemplo: Uma classe Produto deve ser convertida para poder ser utilizada em algum componente JSF. Neste caso, utiliza-se os conversores personalizados. Listagem 18.13: Classe ProdutoControl 1 package aulajsf; 2 3 4 import java.util.ArrayList; import java.util.List; 5 6 import javax.faces.event.ActionEvent; 7 8 9 public class ProdutoListControl { 10 11 private ProdutoDao produtoDao = new ProdutoDao(); 12 13 private List<Produto> produtos = new ArrayList<Produto>(); 14 15 private Produto produto; 16 17 18 19 public List<Produto> listarPorDescricao(String descricao){ return produtoDao.listar(descricao); } 20 212 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta introdução ao javaserver faces public void adicionar(ActionEvent evt){ produtos.add(produto); } 21 22 23 24 public List<Produto> getProdutos() { return produtos; } 25 26 27 28 public Produto getProduto() { return produto; } 29 30 31 32 public void setProduto(Produto produto) { this.produto = produto; } 33 34 35 36 37 } Listagem 18.14: Classe ProdutoControl 1 package aulajsf; 2 3 4 import java.util.HashMap; import java.util.Map; 5 6 7 8 9 import import import import javax.faces.component.UIComponent; javax.faces.context.FacesContext; javax.faces.convert.Converter; javax.faces.convert.FacesConverter; 10 11 12 13 @FacesConverter("produtoConverter") public class ProdutoConverter implements Converter{ 14 private static Map<String, Produto> mapa = new HashMap<String, Produto>(); 15 16 @Override public Object getAsObject(FacesContext ctx, UIComponent comp, String value) { return mapa.get(value); } 17 18 19 20 21 @Override public String getAsString(FacesContext ctx, UIComponent comp, Object value) { if(value instanceof Produto){ Produto p = (Produto) value; mapa.put(String.valueOf(p.getId()), p); return String.valueOf(p.getId()); }else{ return ""; } } 22 23 24 25 26 27 28 29 30 31 32 33 } http://solutioin.com Francisco Calaça, Otávio Calaça 213 Versão 1.2-beta introdução ao javaserver faces Listagem 18.15: Tela produto.xhtml 1 2 3 4 <html xmlns="http ://www.w3.org /1999/ xhtml" xmlns:h="http ://java.sun.com/jsf/html" xmlns:f="http ://java.sun.com/jsf/core" xmlns:p="http :// primefaces.org/ui"> 5 6 <h:head> 7 8 </h:head> 9 10 11 12 13 <h:body> <h:form enctype="multipart/form -data"> <p:panel header="Manter Produtos"> <p:autoComplete value="#{ produtoListControl.produto}" id="produto" completeMethod=" #{ produtoListControl.listarPorDescricao}" 14 15 var="p" itemLabel="#{p.descricao}" itemValue="#{p}" converter ="produtoConverter" forceSelection="true"/> <p:commandButton value="Adicionar" actionListener="#{ produtoListControl.adicionar}" update="produtos"></p:commandButton> 16 17 18 19 20 <p:dataTable value="#{ produtoListControl.produtos}" var="prod" id="produtos"> <f:facet name="header"> <h:outputText value="Produtos" /> </f:facet> 21 <p:column> <h:outputText value="#{prod.descricao}"></h:outputText> </p:column> 22 23 24 25 <p:column> <h:outputText value="#{prod.valor}"></h:outputText> </p:column> 26 27 28 29 30 31 32 </p:dataTable> </p:panel> </h:form> 33 34 35 </h:body> </html> Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 214 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta 18.9. introdução ao javaserver faces Exercícios 1. Descreva o framework JavaServer Faces 2. Quais os procedimentos para adicionar o JavaServer Faces em um aplicativo 3. O que é um Managed Bean 4. Quais são as tags básicas do JSF 5. O que é uma expressão de ligação? http://solutioin.com Francisco Calaça, Otávio Calaça 215 19 PA D R Õ E S D E P R O J E T O Um Padrão de Projeto de Software, também muito conhecido pelo seu termo original em inglês, Design Pattern, descreve uma solução geral reutilizável para um problema recorrente no desenvolvimento de sistemas de software orientados a objetos. Não é um código final, é uma descrição ou modelo de como resolver o problema do qual trata, que pode ser usada em muitas situações diferentes. Os Padrões de Projeto normalmente definem as relações e interações entre as classes ou objetos, sem especificar os detalhes das classes ou objetos envolvidos, ou seja, estão num nível de generalidade mais alto. Um padrão de projeto define : • seu nome, • o problema, • a solução, • quando aplicar esta solução e • suas consequências. Os padrões de projeto visam facilitar a reutilização de soluções de projeto e estabelecem um vocabulário comum para ser utilizado no projeto, facilitando comunicação, documentação e aprendizado dos sistemas de software. Alguns dos códigos aqui descritos e mais informações sobre este assunto pode ser obtido em: http://solutioin.com/java Acesse e verifique! 19.1. Padrões GoF Gof vem do inglês Os padrões "GoF" são organizados em 3 grupos: • Padrões de criação : relacionados à criação de objetos • Padrões estruturais : tratam das associações entre classes e objetos. • Padrões comportamentais : tratam das interações e divisões de responsabilidades entre as classes ou objetos. 217 Versão 1.2-beta padrões de projeto Padrões de criação: • Abstract Factory • Builder • Factory Method • Prototype • Singleton Padrões estruturais • Adapter • Bridge • Composite • Decorator • Facade • Flyweight • Proxy Padrões comportamentais • Chain of Responsibility • Command • Interpreter • Iterator • Mediator • Memento • Observer • State • Strategy • Template Method • Visitor 19.2. Abstract Factory Abstract Factory é um padrão de projeto de software (também conhecido como design pattern em inglês). Este padrão permite a criação de famílias de objetos relacionados ou dependentes, através de uma única interface e sem que a classe concreta seja especificada. 218 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta padrões de projeto 19.2.1 Utilização O padrão Abstract Factory pode ser utilizado na implementação de um toolkit que disponibilize controles que funcionem em diferentes interfaces gráficas, tal como Motif, GTK+ (GNOME) ou Qt (KDE). Estas GUIs possuem diferentes padrões de controles visuais e, para facilitar a construção de aplicativos que interajam facilmente com diferentes interfaces gráficas, é interessante que se defina interfaces comuns para acesso aos controles, independentemente da GUI utilizada. Este problema pode ser resolvido através de uma classe abstrata que declara uma interface genérica para criação dos controles visuais e de uma classe abstrata para criação de cada tipo de controle. O comportamento específico, de cada um dos padrões tecnológicos contemplados, é implementado através de uma classe concreta. O aplicativo, ou "cliente", interage com o toolkit através das classes abstratas sem ter conhecimento da implementação das classes concretas. Um exemplo bem simplista seria um projeto com interface para Mobile e para Desktop, uma boa opção para reaproveitar os mesmos controles de interface seria criar pacotes com classes abstratas e os pacotes com as classes concretas implementando apenas as diferenças. Esse padrão também se aplica na padronização de ambientes, por exemplo, tamanhos de botões, fontes, cores de fundo, largura de bordas. Com isso e havendo uma política que exija que os desenvolvedores usem essas classes em vez das nativas da linguagem, ajudará a padronizar a aparência e comportamento das aplicações. 19.3. Factory Method Factory Method, na ciência da computação, é um padrão de projeto de software (design pattern, em inglês) que define uma classe para criação de um objeto, mas permite que as subclasses escolham qual classes instanciar. O factory method permite delegar a instanciação para as subclasses. 19.3.1 Utilização Este padrão é muito utilizado em frameworks para definir e manter relacionamentos entre objetos. O framework Spring, dependendo da configuração, pode utilizar um Factory Method para criar os seus beans. Este padrão pode ser utilizado na construção de um framework que suporta aplicações que apresentam múltiplos documentos ao usuário. Normalmente este tipo de aplicação manipula um número variável de formatos de documento e, por isso, este framework deve ser flexível o bastante para suportar qualquer formato. Uma solução para este problema poderia disponibilizar, no framework, o código para alguns dos formatos mais utilizados. Mas, na prática, esta solução seria uma implementação pouco flexível, e até mesmo incompleta, já que é custoso implementar os mais variados formatos. O padrão Factory Method propõe uma solução que deixa para o cliente (a implementação da aplicação) a tarefa de suportar os formatos necessários e para o framework o papel de definição de uma abstração que oferece uma interface única para criação de documentos. Este framework seria baseado em duas classes abstratas, que representam http://solutioin.com Francisco Calaça, Otávio Calaça 219 Versão 1.2-beta padrões de projeto a Aplicação e o Documento. O cliente do framework fornece um par de classes concretas, uma aplicação e o respectivo documento, para cada um dos formatos de Documento suportados pela Aplicação. Se for necessário apresentar um documento que suporte desenho, por exemplo, o cliente deve disponibilizar as classes AplicacaoDesenho e DocumentoDesenho (supondo que o sufixo "Desenho" indique classes que suportam esta funcionalidade). O objetivo do Factory Method está em diversas classes que implementam a mesma operação, retornarem o mesmo tipo abstrato, mas internamente instanciam diferentes classes que o implementam. Com o Factory Method o criador do objeto faz uma escolha de qual classe instanciar para o cliente. Para ser um Factory Method o método precisa retornar uma interface ou uma classe abstrata e, dependendo das necessidades do cliente, criar um objeto determinado como retorno. Um exemplo clássico do Factory Method são os iteradores em Java. 19.3.2 Command Encapsular uma solicitação como um objeto, desta forma permitindo que clientes parametrizem diferentes solicitações, enfileirem ou façam o registro (log) de solicitações e suportem operações que podem ser desfeitas. 19.3.3 Problema Algumas vezes é necessário emitir solicitações para objetos nada sabendo sobre a operação que está sendo solicitada ou sobre o receptor da mesma. Utilizar quando: • Parametrizar objetos por uma ação a ser executada. Você pode expressar tal parametrização numa linguagem procedural através de uma função callback, ou seja, uma função que é registrada em algum lugar para ser chamada em um momento mais adiante. Os Commands são uma substituição orientada a objetos para callbacks; • Especificar, enfileirar e executar solicitações em tempos diferentes. Um objeto Command pode ter um tempo de vida independente da solicitação original. Se o receptor de uma solicitação pode ser representado de uma maneira independente do espaço de endereçamento, então você pode transferir um objeto Command para a solicitação para um processo diferente e lá atender a solicitação; • Suportar desfazer operações. A operação Execute, de Command, pode armazenar estados para reverter seus efeitos no próprio comando. A interface do Command deve ter acrescentada uma operação Unexecute, que o reverte.efeitos de uma chamada anterior de Execute. Os comandos executados são armazenados em uma lista histórica. O nível ilimitado de desfazer e refazer operações é obtido percorrendo esta lista para trás e para frente, chamando operações Unexecute e Execute, respectivamente. 220 http://solutioin.com Francisco Calaça, Otávio Calaça Versão 1.2-beta padrões de projeto 19.3.4 Aplicação A chave deste padrão è uma classe abstrata Command, a qual declara uma interface para execução de operações. Na sua forma mais simples, esta interface inclui uma operação abstrata Execute. As subclasses concretas de Command especificam um par receptor-ação através do armazenamento do receptor como uma variável de instância e pela implementação de Execute para invocar a solicitação. O receptor tem o conhecimento necessário para poder executar a solicitação. 19.4. Data Access Object (DAO) Este não é um padrão de projeto GoF. Objeto de acesso a dados (ou simplesmente DAO, acrônimo de Data Access Object), é um padrão para persistência de dados que permite separar regras de negócio das regras de acesso a banco de dados. Numa aplicação que utilize a arquitetura MVC, todas as funcionalidades de bancos de dados, tais como obter as conexões, mapear objetos Java para tipos de dados SQL ou executar comandos SQL, devem ser feitas por classes de DAO. 19.4.1 Vantagens A vantagem de usar objetos de acesso a dados é a separação simples e rigorosa entre duas partes importantes de uma aplicação que não devem e não podem conhecer quase que nada uma da outra, e que podem evoluir frequentemente e independentemente. Alterar a lógica de negócio podem esperar apenas a implementação de uma interface, enquanto que modificações na lógica de persistência não alteram a lógica de negocio, desde que a interface entre elas não seja modificada. • Pode ser usada em uma vasta porcentagem de aplicações; • Esconde todos os detalhes relativos a armazenamento de dados do resto da aplicação; • Atua como um intermediário entre a aplicação e o banco de dados; • Mitiga ou resolve problemas de comunicação entre a base de dados e a aplicação, evitando estados inconsistentes de dados. No contexto específico da linguagem de programação Java, um objeto de acesso a dados como padrão de projeto de software pode ser implementado de várias maneiras. Pode variar desde uma simples interface que separa partes de acesso a dados da lógica de negócio de uma aplicação até frameworks e produtos comerciais específicos. Os paradigmas para programação usando DAOs demandam alguma proficiência. O uso de tecnologias como Java persistence technologies e JDO garantem a implementação do padrão de projeto até certo ponto. Tecnologias como Enterprise JavaBeans trazem para a aplicação servidores montados e que podem ser usados em aplicações que usem um servidor de aplicação JEE. http://solutioin.com Francisco Calaça, Otávio Calaça 221 Versão 1.2-beta padrões de projeto Produtos comerciais como o TopLink estão disponíveis, baseados em mapeamento objetorelacional (ORM). Produtos ORM populares em código aberto incluem Doctrine, Hibernate, iBATIS e Apache OpenJPA. 19.5. MVC Model-view-controller (MVC) é um modelo de desenvolvimento de Software, atualmente considerado uma "arquitetura padrão" utilizada na Engenharia de Software. O modelo isola a "lógica" (A lógica da aplicação) da interface do usuário (Inserir e exibir dados), permitindo desenvolver, editar e testar separadamente cada parte. 19.5.1 Componentes O modelo (model) é usado para definir e gerenciar o domínio da informação e notificar observadores sobre mudanças nos dados. Ele é uma representação detalhada da informação que a aplicação opera. A lógica de negócio adiciona valor semântico aos dados, e quando há mudança de estado o modelo notifica seus observadores. Por exemplo, aluno, professor e turma fazem parte do domínio de um sistema acadêmico. Operações como calcular a média final do aluno ou o índice de faltas da turma fazem parte da lógica de domínio. A forma como o dado é armazenado ou acessado não é de interesse do MVC, assume-se que é de responsabilidade do modelo. A visão (view) apresenta o modelo num formato adequado ao utilizador, na saída de dados, e diferentes visões podem existir para um mesmo modelo, para diferentes propósitos. O controlador (controller) recebe a entrada de dados e inicia a resposta ao utilizador ao invocar objetos do modelo, e por fim uma visão baseada na entrada. Ele também é responsável pela validação e filtragem da entrada de dados. Um caso prático é uma aplicação web em que a visão é um documento HTML (ou derivado) gerado pela aplicação. O controlador recebe uma entrada GET ou POST após um estímulo do utilizador e decide como processá-la, invocando objetos do domínio para tratar a lógica de negócio, e por fim invocando uma visão para apresentar a saída. 19.5.2 Justificativa Com o aumento da complexidade das aplicações desenvolvidas,sempre visando a programação orientada a objeto nao devemos esquecer que torna-se relevante a separação entre os dados e a apresentação das aplicações. Desta forma, alterações feitas no layout não afetam a manipulação de dados, e estes poderão ser reorganizados sem alterar o layout. Esse padrão resolve este problema através da separação das tarefas de acesso aos dados e lógica de negócio, lógica de apresentação e de interação com o utilizador, introduzindo um componente entre os dois, o controlador. 222 http://solutioin.com Francisco Calaça, Otávio Calaça A M O N TA G E M D O A M B I E N T E D E TRABALHO A.1. Obtenção e instalação do JDK O JDK deve ser obtido do site da Oracle1 . Quando você acessar este site, notará a primeira grande confusão enfrentada pelos iniciantes. O que baixar JDK ou JRE ? No nosso caso, devemos baixar o Java SE 7 JDK, ou seja, clique no download do JDK. Para instalar o JDK basta executar o instalador adequado obtido no site. Note que existem opções de instalador para linux, windows e solaris para as arquiteturas 32 e 64 bits. A diferença entre JDK e JRE é que o JDK contém, além da máquina virtual Java, várias ferramentas para o desenvolvimento de um software Java. Já o JRE contém apenas a máquina virtual. A.2. O que é a Máquina virtual Java Todo software Java necessita de uma máquina virtual para executá-lo. É ela quem acessa o hardware da máquina. Em java, todo o código escrito deve ser compilado. Este arquivo compilado é chamado de bytecode e é executado pela máquina virtual. Hoje existem máquinas virtuais JIT que recompilam o bytecode para código nativo (que pode ser executado diretamente no computador) tornando a execução do software mais rápida. Este trabalho feito pela JVM é transparente, ou seja, não há a necessidade de se preocupar como e quando será feito isto. A.3. Obtenção e instalação do eclipse O Eclipse pode ser obtido no seu site: http://www.eclipse.org/downloads/. Neste livro será utilizado o “Eclipse IDE for Java EE Developers”. Após o término do download, basta descompactar o arquivo. Para iniciar o Eclipse basta executar o aplicativo eclipse(Linux) ou eclipse.exe(Windows) situado dentro do diretório eclipse descompactado. 1 http://www.oracle.com/technetwork/java/javase/downloads/index.html 223 B E R R O S C O M U N S E N F R E N TA D O S P O R INICIANTES B.1. Exceções que costumam serem vistas B.1.1 ClassNotFoundException B.1.2 NoSuchMethodError B.1.3 LazyInitializationException B.1.4 NoClassDefFoundError B.1.5 NullPointerException B.1.6 ClassCastException B.2. Erros comuns do HTTP 225