Este documento apresenta os fundamentos da linguagem de programação Java, incluindo sua história, características como orientação a objetos, portabilidade e segurança, e o passo a passo para instalação do ambiente de desenvolvimento Java.
Sobre nossa empresaA Jet Software é uma empresa jovem, dinâmica, que atua no mercado de TI, em consultoria e treinamento. Nossa empresa é especializada em Java, .NET, SOA, EAI e metodologias ágeis. Nossos profissionais são experientes, certificados e possuem vários anos de experiência de mercado, agregando assim alto valor nas soluções apresentadas a nossos clientes, quer sejam elas sobre consultoria ou treinamentos.
3.
Sobre esta apostilaEsta apostila tem a finalidade de levar ao aluno os fundamentos da linguagem Java. Ou seja, nosso objetivo é mostrar os conceitos que regem a linguagem, seu funcionamento, comportamento, configuração, setup de ambiente e toda informação básica que darão ao aluno o conhecimento técnico suficiente para a preparação para a certificação e cobrir os pré-requisitos para os próximos módulos de desenvolvimento Java para web, componentes distribuídos ( EJB ) e demais módulos.
4.
Sobre este cursoNosso foco é trazer a nossos alunos um curso dinâmico, abordando o conteúdo da linguagem e da plataforma, e também as melhores práticas e bibliotecas Utilizadas pelo mercado. E foi pensando nisso que a Jet Software elaborou sua grade de cursos, afim de que ao término de cada módulo o aluno esteja dominando a tecnologia / plataforma, e também conhecendo tudo aquilo que o mercado utiliza, estando assim melhor preparado para as futuras oportunidades.
5.
O que oaluno deve aprender sobre Java ? Esta é uma pergunta que muitas pessoas fazem e provavelmente continuarão a fazer. Existe um certo mito de que para ser um bom programador Java o indivíduo deve saber somente “tudo” sobre a linguagem. Fique calmo, pois isto não é verdade! A linguagem e a plataforma Java possui inúmeras features e APIs, e seria impossível descarregar todo este conteúdo sobre o aluno em um só curso ou em um só livro, o que existe sim é um conjunto de regras e conceitos básicos que o aluno necessita saber para iniciar sua vida como programador Java, e após a absorção destes conceitos é muito fácil adicionar mais conhecimento a sua base.
6.
O que oaluno deve aprender sobre Java ? Todos os próximos módulos usarão os conceitos, APIs e demais conhecimentos adquiridos neste curso de fundamentos. Recomendamos aqueles alunos que desejam tirar a certificação que ao término de nosso curso invistam entre 2 ou 4 semanas se preparando para a prova, pois não basta somente absorver o conteúdo em sala de aula como será passado, mas também treinar o que foi aprendido, e ainda preparar-se para as famosas “pegadinhas” da prova. Recomendamos o seguinte livro para a preparação, que contém uma gama imensa de exercícios e dicas :
7.
Preparação para acertificação SCJP Sun Certified Programmer for Java 6 Exam 310-065 [ILLUSTRATED] (Hardcover) by Katherine Sierra (Author), Bert Bates (Author)
8.
Agenda do CursoIntrodução ao Java Conceitos Básicos Introdução a Orientação a Objetos Declaração de variáveis Construção de classes Tipos Herança e Polimorfismo Interfaces Enumerações ( Enum ) Controle de Fluxo Tratamento de Exceções O Framework de coleções ( Collection framework ) Generics Threads JDBC
Simples, orientada aobjetos e familiar A linguagem de programação Java foi pensada para “atacar” as dificuldades do desenvolvimento de aplicações, no contexto de heterogeneidade, ambientes de rede distribuídos. E além de todos estes desafios, a execução segura de aplicações que consomem o mínimo de recursos de um sistema, pode ser executada em qualquer hardware e plataforma de software, e além de tudo pode ser estendida dinamicamente.
11.
Simples, orientada aobjetos e familiar A linguagem de programação Java foi originada como parte de um projeto de pesquisa para desenvolver uma espécie de software avançado para uma grande variedade de dispositivos de rede ( móveis ). O objetivo era desenvolver uma plataforma operacional que fosse pequena, confiável, portável distribuída, tempo-real.
12.
Simples, orientada aobjetos e familiar Quando o projeto iniciou-se o C++ foi a linguagem escolhida. Mas conforme o tempo foi passando as dificuldades encontradas com o C++ cresceram ao ponto de que os problemas poderiam ser melhor resolvidos criando-se uma nova plataforma de linguagem. Decisões de design e arquitetura vieram de uma grande variedade de linguagens, tais como Eiffel, SmallTalk, Objective C e Cedar/Mesa. O resultado foi uma nova linguagem/plataforma que provou ser ideal para o desenvolvimento de aplicações seguras, distribuídas, network-based, aplicações de usuário final em diversos ambientes que vão desde sistemas embarcados ( embedded ) até a Web e desktops.
13.
Robusta e seguraA linguagem de programação Java foi arquitetada para ser um software altamente confiável. Ela provê uma extensiva checagem em tempo de compilação, seguida por um segundo nível de checagem em tempo de execução. As features da linguagem guiam os programadores no caminho dos hábitos confiáveis de programação.
14.
Robusta e seguraO modelo de gerenciamento de memória é extremamente simples, pois os objetos são criados com o operador new . Não existe nenhum tipo de ponteiro definido pelo programador, não existe aritimética de ponteiros , e temos ainda um garbage collector automático. Este modelo simples de gerenciamento elimina uma gama incrível de erros de programação que programadores C e C++ tem que lidar no seu dia-a-dia. Podemos desenvolver código Java com a confiança que o sistema/plataforma irá encontrar muitos erros rapidamente e que os maiores problemas não ficarão escondidos até nosso software estar em produção.
15.
Robusta e seguraA tecnologia Java foi desenvolvida para operar em ambientes distribuídos, o que significa que a segurança é um item de extrema importância. Com as propriedades de segurança que foram desenvolvidas dentro da linguagem e no sistema de run-time, a tecnologia Java nos permite construir aplicações que não podem ser invadidas por meios externos. Em um ambiente de rede, as aplicações escritas na linguagem Java estão seguras de qualquer intrusão por código não autorizado, ou ainda por vírus ou arquivos inválidos.
16.
Arquitetura neutra eportável A tecnologia Java é também responsável por suportar aplicações que serão instaladas ( deployed ) em ambientes de redes heterogêneos. Nestes ambientes as aplicações precisam ser capazes de executar em uma grande variedade de arquitetura de hardware. Dentro desta variedade de plataformas de hardware, as aplicações devem executar em cima de uma variedade de sistemas operacionais, e inter-operar com Múltiplas interfaces de linguagem de programação. Para acomodar esta diversidade de sistemas operacionais, o compilador Java produz o bytecode , que é um formato arquitetural intermediário e neutro, que é designado a trasportar o código eficientemente para múltiplas plataformas de hardware e software. A natureza interpretada da tecnologia Java resolve ambos problemas de distribuição binária e versionamento; pois o mesmo byte code será executado em qualquer plataforma.
17.
Arquitetura neutra eportável A arquitetura neutra e portável da plataforma da linguagem Java é conhecida como Java Virtual Machine . Ela é uma especificação de uma abstração de uma máquina, na qual os compiladores da linguagem Java podem gerar código. Implementações específicas Da Java Virtual Machine para plataformas específicas de hardware e software criam a concreta materialização da virtual machine. A Java Virtual Machine é baseada primeiramente na especificação de interface POSIX, um padrão da industria para a definição de interfaces de sistemas portáveis. Implementar a Java Virtual Machine em novas arquitetura é uma tarefa relativamente simples, necessitando apenas que a plataforma de destino cumpra com os requisitos básicos, tal como o suporte a multi-threading.
18.
Alta Performance Performanceé sempre alvo de grandes considerações. A plataforma Java possui uma performance superior adotando um esquema onde o interpretador pode ser executado em velocidade máxima sem a necessidade do ambiente de checagem de run-time. O garbage collector automático é executado como uma thread de baixa prioridade em background, proporcionando assim uma alta probabilidade que a memória estará disponível quando requisitada, causando assim uma melhor performance.
19.
Alta Performance Aplicaçõesque necessitam de uma grande quantidade de poder de processamento podem ser designadas tal como seções de computação intensivas podem ser re-escritas em código nativo de máquina como necessitar e interfacear com a plataforma Java. Em geral, usuários percebem que aplicações interativas respondem rápido, mesmo que elas sejam interpretadas.
20.
Interpretada, threaded, dinâmicaO interpretador Java pode executar bytecodes Java diretamente em qualquer máquina na qual o sistema de interpretador e run-time tenha sido portada. Em uma plataforma interpretada como o Java, a fase de link de um programa é simples, incremental e leve. Os benefícios são grandes, tais como ciclos de desenvolvimentos mais rápidos, prototipação, experimentação, e o desenvolvimento rápido de casos normais, ao contrário do tradicional compilador “peso-pesado” : compilar, linkar e ciclos de testes.
21.
Interpretada, threaded, dinâmicaAplicações modernas baseadas em rede, tal como o HotJava Browser para a web, tipicamente necessida de muitas coisas ao mesmo tempo. Um usuário trabalhando com o HotJava browser pode executar muitas animações concorrentemente enquanto faz o download de uma imagem e usa o scroll de uma página. A capacidade de multi-thread da tecnologia Java provê os meios para a construção de aplicações com atividades concorrentes de threads. Multithreading resulta em um alto nível de interatividade para o usuário final.
22.
Interpretada, threaded, dinâmicaA plataforma Java suporta multi-threading no nível de linguagem com a sofisticação adicional de sincronização de primitivos: a biblioteca de linguagem provê a classe Thread , e o sistema de run-time provê o monitor e as condições de lock primitivas. No nível de biblioteca, novamente, as bibliotecas de sistema de alto nível, tem sido escritas para serem thread safe : a funcionalidade provida pelas bibliotecas está disponível sem o conflito para a execução de múltiplas threads.
23.
Interpretada, threaded, dinâmicaEnquanto o compilador Java é restrito no seu “compile-time static checking”, o sistema de run-time da linguagem é dinâmico nos seus estágios de linking. As classes são “linkadas” somente quando necessário. Novos módulos de código podem ser linkados sob demanda de uma grande variedade de fontes, mesmo de fontes através da rede. No caso do HotJava Browser e aplicações similares, código executável interativo pode ser carregado de qualquer lugar, o que possibilita o update transparente de aplicações. O resultado é um serviço constante on-line que sempre é incrementado; ele pode permaneter inovador e recente, ser oferecido para mais clientes, e suportar o crescimento do comércio eletrônico na internet.
A plataforma Java,um novo jeito de fazer computação distribuída Se pegarmos individualmente, estas características discutidas acima podem ser encontradas em uma grande variedade de plataformas de software. Mas o que é completamente novo é a maneira que a tecnologia Java e o seu ambiente de runtime tem combinado eles para produzir um poderoso e flexível sistema de programação.
26.
A plataforma Java,um novo jeito de fazer computação distribuída Desenvolver nossas aplicações usando a linguagem de programação Java resulta em um software que é portável através de múltiplas arquiteturas de máquinas, sistemas operacionais, e interfaces de usuário gráficas, seguro e de alta performance. Com a tecnologia Java, nosso trabalho como desenvolvedores é muito fácil, pois o foco de nossa atenção é somente no objetivo final de entregarmos um produto inovador no prazo, baseado nos sólidos fundamentos da plataforma Java. A melhor forma de desenvolver software é aqui, agora, trazido pela plataforma Java.
O ambiente dedesenvolvimento Para podermos desenvolver programas em Java precisaremos : Java Development Kit ( JDK ), que por sua vez é um conjunto de programas e APIs que nos possibilita escrevermos e compilar programas em Java. Notepad ++ Netbeans, que é uma das mais famosas IDEs para desenvolvimento Java.
31.
Passos para ainstalação do ambiente Download the Notepad++ http://notepad-plus.sourceforge.net/uk/site.htm Execute o instalador do Notepad++ Download the JDK : http://java.sun.com/javase/downloads Ou vá para a página principal : www.java.sun.com e navegue no link JavaSE, afim de baixar a versão correta ( 6.x ) Execute o instalador do JDK Crie a variável JAVA_HOME no seu painel de controle, apontando para o diretório de instalação de seu JDK, ex : C:\Arquivos de programas\Java\jdk1.6.0_05 Configure o seu path no painel de controle para conter o caminho do JDK, exemplo : %JAVA_HOME%;%JAVA_HOME\bin%;%JAVA_HOME\lib%;
Verificando a instalação Abra uma janela de comandos do windows e digite o seguinte comando : java –version Você deverá ver o seguinte resultado ( ou a versão que você instalou ): java version 1.6.0_05 Java(TM) SE Runtime Environment (build 1.6.0_05-b13) Java HotSpot(TM) Client VM (build 10.0-b19, mixed mode, sharing)
Estrutura de diretórioBin Compilador e command line tools Db Banco de dados Demo Demos Include Arquivos para métodos native Jre Arquivos Java Runtime Env. Lib Arquivos de bibliotecas Src Código fonte das bibliotecas
Tópicos Compilando umprograma em Java • String • Blocos e expressões • Operadores • Controle de execução • Arrays
38.
Compilando um programaJava Crie um diretório chamado c:\projetos\Welcome Abra o Notepad++ e digite o seguinte código : public class Welcome { public static void main(String[] args) { System.out.println(“Bem vindo ao mundo do Java”); } }
39.
Compilando um programaJava Salve este arquivo como Welcome.java dentro do diretório Welcome. Abra uma janela do DOS e vamos compilar e rodar nosso novo programa : javac Welcome.java java Welcome Resultado : Bem vindo ao mundo do Java
40.
Programando em Java Neste momento já possuímos um bom conhecimento sobre a linguagem e a plataforma Java, e já temos o JDK instalado, compilando e executando programas Java. Nesta parte veremos mais a fundo os conceitos básicos de programação, tal como tipos de dados, fluxo e loops.
41.
Programando em JavaUm programa Java simples. É o que exibimos no trecho código abaixo, e podemos até dizer que este programa tem o mínimo de código necessário para que o mesmo seja executado como um “executável”, como veremos mais a frente na anatomia de um programa Java : public class PrimeiroExemplo { public static void main(String[] args) { System.out.println("Nosso primeiro exemplo !!!"); } }
42.
Anatomia de umprograma Java Traçaremos a antomia deste programa Java para tornarmos mais confortáveis com o framework provido pelo JDK. A primeira propriedade que devemos notar é que o Java é “case sensitive”, ou seja, o Java pode interpretar maiúsculo/minúsculo como erro se digitarmos MAIN ao invés de main, e o programa não poderá ser executado gerando um erro : C:\projetos\Welcome>javac PrimeiroExemplo.java C:\projetos\Welcome>java PrimeiroExemplo Exception in thread "main" java.lang.NoSuchMethodError: main
43.
Anatomia de umprograma Java Este erro é ocasionado por que a JVM espera que a classe possua um método chamado main com a seguinte assinatura : public static void main (String[] args) { … } Ao invés de : public static void MAIN (String[] args) { … }
44.
Anatomia de umprograma Java public é um modificador de acesso, que rege como a classe pode ser acessada. Veremos modificadores a fundo mais a frente. class é um identificador, um marcador que diz que o bloco inteiro é uma classe, e vale a pena apontar mais uma vez que tudo no Java é um tipo de classe específica. Em linhas muito gerais uma classe é um container de código que define o comportamento de uma aplicação, um bloco de código no qual todo programa é montado sobre, e tudo em um programa Java deve estar dentro de uma class.
45.
Anatomia de umprograma Java O padrão de nomeclatura de classes Java é o famoso “camel case”, onde usamos uma letra maiúscula sempre que passamos para uma nova parte de identificação da classe, para ficar mais claro podemos dar como exemplo duas classes, uma para registrar pagamentos e outra para listar balanço : public class RegistrarPagamento { .. } Public class ListarBalanco { .. }
46.
Anatomia de umprograma Java Outra coisa a ser notada são os colchetes { }, que delimitam o início e fim de um determinado bloco, e se abrimos um novo bloco, o mesmo deve ser fechado em algum momento abaixo. Caso não façamos isso receberemos um erro do compilador. public class NomeDaClasse { public static void main(String[] args) { //invocação de métodos, apis, e etc… } }
47.
Anatomia de umprograma Java Não precisamos nos preocupar com a palavra chave “static” neste momento, pois veremos estes e outros conceitos mais de perto nos próximos capítulos. O ponto a ser lembrado é que toda classe Java que desejamos que seja “executável” por meio de linha de comando deve ter a sintaxe acima declarada.
String • O tipo String é um dos mais utilizados em qualquer linguagem de programação • Em Java, o tipo String é uma classe e não um tipo primitivo • No entanto, assim como os tipos primitivos, as strings podem ser criadas a partir de constantes, que, no caso, são seqüências de caracteres delimitados por aspas duplas. Ex: String s = “abc”; • Embora seja um objeto, não há a necessidade de utilização do operador new , como acontece com TODAS as outras classes.
52.
String • As instâncias de String são objetos imutáveis, ou seja, uma vez criada o seu valor não pode ser nunca alterado. • Isto acontece porque cada instância de String é criada apenas uma vez, e essa lista de strings é mantida pelo sistema. Se uma nova String for criada e o seu valor já estiver nesta lista, não há a necessidade de criar uma nova instância. Ex.: String s1, s2, s3; abc s1 = “abc”; s2 = “abc”; s3 = s1.toUpperCase();
53.
Variáveis Em Javatoda variável necessita ter um tipo, isto porque o Java é uma linguagem fortemente tipada, como vimos anteriormente : double salary; int vacationDays; long earthPopulation; boolean done; int i, j; // ambas inteiras Lembrando sempre que devemos inicializar uma variável antes de podermos utilizar a mesma para qualquer função : int vacationDays; // ERRO !--variable not initialized System.out.println(vacationDays);
54.
Variáveis Constantes sãovariáveis “imutáveis”, pois uma vez atribuido um valor a mesma, nunca mais poderemos mudá-lo : public class Constants { public static void main(String[] args) { final double CM_PER_INCH = 2.54; double paperWidth = 8.5; double paperHeight = 11; System.out.println("Paper size in centimeters: " + paperWidth * CM_PER_INCH + " by " + paperHeight * CM_PER_INCH); } } A palavra chave final é quem torna a variável imutável ( constante ) !
Operadores e atribuiçãoOperadores são utilizados para operações aritiméticas, ou seja, adição, subtração, multiplicação e divisão. Atribuição é a ação de determinar um valor a uma variável. O trabalho de atribuir um valor a uma variável parece ser algo muito simples, pois a única coisa que devemos fazer é colocar um valor no lado direito do sinal de igual “=” e a variável a esquerda do mesmo. Veremos capítulo de Orientação a Objetos que isto não é tão fácil quanto parece, mas neste momentos nos ateremos aos exemplos mais simples :
57.
Atribuição int x= 4; int a = 12; long l = 44444444444444; double d = 355.44;
58.
Operadores Como exmeplode operações podemos utilizar : x += 4; Que é o equivalente a : x = x + 4; Geralmente quando queremos fazer este tipo de operação direta utilizamos o símbolo antes do sinal de =, como *= ou %=). Exemplos de Incrementanto e decremento : int myVar = 15 ; myVar++ ; O valor de myVar será de 16, pois adicionamos mais um número ao mesmo. Outros exemplos : int m = 7; int n = 7; int a = 2 * ++m; // vale 16, e “m” vale 8 int b = 2 * n++; // vale 14, e “n” vale 8
59.
Operadores relacionais Operadoresrelacionais são aqueles que estão ligados a comparações, e o seu resultado é sempre true ou false, a caracterização dos mesmos é pelo sinal “==”, um duplo sinal de igual, como veremos a seguir : 3 == 7 ( false ) 3 != 7 ( true ) Nota : == ( igual ) != ou <> ( diferente ) Temos também os outros operadores, < menor que, > maior que, <= menor ou igual que, e >= maior ou igual que. O Java segue o C++ e usa os operadores && e || que são avaliados em “short circuit” . Ou seja, o segundo argumento não é avaliado se o primeiro já determinar o valor. A sintaxe é muito simples :
60.
Operadores relacionais expressão1&& expressão2 int x = 5; x != 0 && 1 / x > x + y; A segunda parte de nossa expressão nunca será avaliada, pois a primeira parte dela já satisfaz a condição que queremos. E da mesma forma poderemos utilizar o ou lógico ||. expressão1 || expressão2 Outro operador lógico utilizado pelo Java é o operador ternário, que tem sua sintaxe : condição1 ? expressão1 : expressão2
61.
Operadores relacionais Esteoperador avalia a condição1, e se a mesma for verdadeira (true), então o Java atribui a primeira expressão como resultado, senão a segunda : int x = 7; int y = 9; String resultado = x > y ? “X é Maior que Y” : “Não, X não é maior que Y” System.out.println(resultado); Operadores de bitwise Este tipo de operador funciona com qualquer tipo inteiro, e eles operam diretamente com os bits que compõem os inteiros. Isto significa que podemos utilizar um tipo de máscara para pegar os bits individuais de um número. Estes operadores são : & (“and”) | (“or”) ^ (“xor”) ~ (“not”)
62.
Operadores relacionais Comoexemplo temos : int fourthBitFromRight = (n & 8) / 8; Estes operadores tem uma particularidade, pois eles não são executados em short circuit, ou seja, a segunda expressão será avaliada de qualquer forma após a primeira. Por último temos os operadores de shift, que servem para mover os bits para a esquerda ou direita, eles são >> , << e >>> . int n = 6; int quartoBitDaDireita = (n & (1 << 3)) >> 3;
Conversão entre tiposnuméricos Quando convertemos nossos valores para uma variável de capacidade superior, não temos problema algum com o conteúdo, mas quando tentamos fazer o inverso, devemos utilizar um cast , e lidar com a perda de dados : int n = 123456789; float f = n; System.out.println("n == " + n); System.out.println("f == " + f); n == 123456789 f == 1.23456792E8
65.
Conversão entre tiposnuméricos O exemplo acima nos mostra um cast automático entre um int e um float, nesse caso, a magnitude do número será mantida, mas haverá uma conversão automática para o tipo float e perderemos alguma precisão. Podemos ver na figura anterior que as setas cheias indicam uma conversão sem perda de precisão, e as setas pontilhadas conversão com possível perda de precisão. Quando dois valores usam um operador binário ( por exemplo n + f onde um operando é um integer e o outro um float), ambos operandos são convertidos para um tipo comum antes da operação ser executada.
66.
Conversão entre tiposnuméricos Se um dos operandos é do tipo double , o outro será convertido pra double . Se um dos operandos é do tipo float , o outro será convertido para float . Se um dos operandos é long , então o outro será convertido pra long . Em qualquer outro caso serão convertidos para int
67.
Conversão entre tiposnuméricos ( cast ) Nos exemplos anteriores vimos que as conversões são automáticas, pois estamos tentando colocar ó conteúdo de uma variável de menor grandeza em uma outra de maior grandeza. Esta conversão automática não acontece quando tentamos fazer o contrário, colocarmos o conteúdo de uma variável double dentro de um int , por exemplo : double x = 9.997; int nx = (int) x;
68.
Operadores e hierarquiade parênteses Devemos prestar atenção na precedência de operadores no momento em que montamos uma expressão, pois dependendo da disposição das expressões ou dos operadores podemos ter uma precedência diferente da esperada. Se nenhum parêntese for usado, então a precedência natural será. Como exemplo, o operador && tem uma precedência mais altar q || :
69.
Operadores e hierarquiade parênteses a && b || c é o mesmo que : (a && b) || c Por que o sinal += associa da direita para a esquerda, a expressão a += b += c significa a += (b += c) Ou seja, o valor de b += c (que é o valor de b depois da adição) é adicionado a.
70.
Operadores e hierarquiade parênteses Operadores Associatividade [] . () (invocação de método) Esquerda para a direita ! ~ ++ -- + (unary) – (unary) () (cast) new Direita para a esquerda * / % Esquerda para a direita + - Esquerda para a direita << >> >>> Esquerda para a direita < <= > >= instanceof Esquerda para a direita == != Esquerda para a direita & Esquerda para a direita ^ Esquerda para a direita | Esquerda para a direita && Esquerda para a direita || Esquerda para a direita ?: Esquerda para a direita = += -= *= /= %= &= |= ^= <<= >>= >>>= Esquerda para a direita
71.
Enumerations As vezesprecisamos representar um conjunto distintos de valores para um cálculo, ou precisamos de um conjunto restritivo. O Java, apartir de sua versão 5 disponibiliza um valioso recurso chamado enumeration ( enum ), que é um tipo especial para armazenar um conjunto de dados : enum Size { SMALL, MEDIUM, LARGE, EXTRA_LARGE }; Size s = Size.MEDIUM;
72.
Strings O tipoString é um dos mais utilizados em qualquer linguagem de programação. Em Java, o tipo String é uma classe e não um tipo primitivo, no entanto, assim como os tipos primitivos, as strings podem ser criadas a partir de constantes, que, no caso, são seqüências de caracteres delimitados por aspas duplas : String s = “abc”;
73.
Strings Embora sejaum objeto, não há a necessidade de utilização do operador new, como acontece com TODAS as outras classes. As instâncias de String são objetos imutáveis, ou seja, uma vez criada o seu valor não pode ser nunca alterado. Isto acontece porque cada instância de String é criada apenas uma vez, e essa lista de strings é mantida pelo sistema. Se uma nova String for criada e o seu valor já estiver nesta lista, não há a necessidade de criar uma nova instância.
String ( algunsmétodos ) Assinatura Descrição Exemplo char charAt(int posicao) Retorna o caractere em determinada posição na String String s = “Teste”; char c = s.charAt( //Resultado: ‘s’ int indexOf(String s2) Retorna a posição da primeira ocorrência de s2 na String String s = “Teste”; int pos = s.indexOf(“st”); //Resultado: 2 int lastIndexOf(String s2) Retorna a posição da última ocorrência de s2 na String String s = “Teste”; int pos = s.lastIndexOf(“e”); //Resultado: 4 int length() Retorna o tamanho da String String s = “Teste”; int tam = s.length(); //Resultado: 5 String substring(int pos1, int pos2) Retorna um pedaço da string que vai de pos1 a pos2 String s = “Teste”; String s2 = s.substring(1, 4); //Resultado: “est” String toUpperCase() Converte para maiúsculo String s = “Teste”; String s2 = s.toUpperCase(); //Resultado: ‘TESTE’ String toLowerCase() Converte para minúsculo String s = “Teste”; String s2 = s.toLowerCase(); //Resultado: ‘teste’ String trim() Limpa os espaços no início e no final da String String s = “ Teste da a ”; String s2 = s.trim(); //Resultado: “Teste da a”
76.
String ( comparações) Comparação de Strings : Ao comparar duas Strings utilize sempre o método equals() em vez do operador ==. Isto é necessário porque o == compara as referências, enquanto que o equals() compara os valores das referências: String s1 = “a”; String s2 = “a”; if(s1 == s2){ //De vez em quando funciona } if(s1.equals(s2)){ //Forma correta de comparar } “ Hello".equalsIgnoreCase("hello")
77.
String ( Métodos) String greeting = "Hello"; int n = greeting.length(); // 5. char first = greeting.charAt(0); // first is 'H' char last = greeting.charAt(4); // last is 'o' int cp = greeting.codePointAt(index); Documentação completa on-line de String : http://java.sun.com/javase/6/docs/api/java/lang/String.html
Orientação a ObjetosO paradigma de orientação a objetos ( OO ) é o assunto mais quente na forma de desenvolver software na “ atualidade”. O mesmo substituiu a famosa forma estruturada de desenvolver sistemas, e podemos citar por exemplo a linguagem C ou Clipper. Java é uma linguagem totalmente orientada a objetos. Um programa orientado a objetos é composto de objetos, e cada objeto tem uma funcionalidade específica que é exposta para os usuários, ou ainda temos outras funcionalidades que são comportamentos escondidos.
80.
Classes Uma classeé um template, ou ainda podemos considerá-la uma forma na qual objetos são “cozinhados como bolos”, ou seja todo objeto terá o formato da forma que foi produzido. Como vimos anteriormente, qualquer código escrito em Java é SEMPRE escrito dentro de uma classe. As bibliotecas standard do Java possuem uma gama imensa de classes para tratamento de interface de usuário, datas, programação em rede e muito mais.
Classes Quando construímosum objeto apartir de uma classe, podemos dizer que o objeto é uma instância daquela classe. import java.util.Date; public class Contrato { Date dataRegistro; Date dataVencimento; double valor; void adicionarVencimento (int valor) { //implementação aqui } double calcularValor (int valor) { //implementação aqui return 0; } }
83.
Classes ( propriedades) Uma classe possui algumas propriedades básicas, que podemos classificar da seguinte forma : Encapsulamento – Também conhecido como “esconder a informação”, que nada mais é do que a combinação de estado e comportamento, empacotados para esconder os detalhes da implementação do usuário. Campos de instância – Os dados vivem aqui dentro, que são variáveis declaradas dentro das classes. Métodos – São os procedimentos de acesso aos dados contidos nos campos de instância. Para termos estas propriedades acima NUNCA devemos invocar um campo de instância diretamente, pelo contrário, devemos sempre invocar um método que realizará o trabalho necessário para retornar-nos o valor desejado.
84.
Objetos Objetos sãoa materialização de uma classe, ou seja, como dissemos anteriormente uma classe é como uma forma para criarmos novos objetos que farão parte do nosso programa. Objetos possuem as seguintes propriedades: Comportamento – Simplesmente aquilo que o objeto é capaz de realizar. O estado do objeto – Como o objeto reage quando invocamos seus métodos. Identidade do objeto – Como o objeto de distingue dos outros objetos que podem ter o mesmo estado e comportamento;
85.
Identificando classes Emprogramas procedurais nós iniciamos o programa com algum processo no topo, tipo “principal”, mas em programação OO não existe este tipo de mecanismo. Na programação OO precisamos criar classes e colocar métodos neles. Uma regra para encontrarmos classes é olhando para os substantivos de nossos use-cases ou estórias, e os métodos serão os verbos.
Criando e usandoobjetos Para podermos usar objetos precisamos antes criá-los apartir de sua classe : java.util.Date data = new java.util.Date(); System.out.println(data); String s1 = new java.util.Date().toString(); System.out.println(s1);
90.
Atributos Atributos sãoas variáveis de instância que existem dentro das classes para compor seu estado, ou seja, são as propriedades que uma classe carrega para compor sua informação.
Métodos Como vimosrapidamente anteriormente, os métodos são funções utilizadas para acessar um determinado comportamento da classe.
93.
Métodos import java.util.Date;/** * @author Marcio */ public class Pessoa { private long id; private String nome; private Date dataNascimento; public long getId() { return id; } public void setId(long id) { this.id = id; }
94.
Métodos public StringgetNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public Date getDataNascimento() { return dataNascimento; } public void setDataNascimento(Date dataNascimento) { this.dataNascimento = dataNascimento; } }
95.
Construtores Construtores sãométodos especiais para criar novas instâncias de objetos. Estes métodos possuem o mesmo nome da classe, mas sem retorno. Podemos ainda usar os construtores para atribuirmos um estado inicial ao objeto, se assim o desejarmos.
96.
Construtores import java.util.Date;public class Pessoa { private long id; private String nome; private Date dataNascimento; //Construtor defaul para a classe pessoa public Pessoa() { } public Pessoa(long id, String nome, Date dataNascimento) { this.id = id; this.nome = nome; this.dataNascimento = dataNascimento; }
Pacotes Pacotes sãouma forma de organizar nosso código, no fundo pacotes nada mais são do que uma estrutura hierárquica de diretórios que o Java usa para uma melhor organização do código fonte. Podemos então organizar nosso código por camadas, nível de importância, ou qualquer outra forma que for mais conveniente.
Pacotes Um pacotegenérico seguindo a convenção proposta pela Sun, diz que o prefixo de um pacote único deve estar escrito em minúsculo, primeiramente com o domínio, e os componentes subsequentes sendo o nome da organização, divisão, departamento, projeto, máquina ou login name. com.sun.eng com.apple.quicktime.v2 edu.cmu.cs.bovik.cheese br.com.jetsoftware.domain
102.
Especificando e ImportandoPacotes O Comando Package serve para especificar a que pacote uma determinada classe ou inteface pertence. O Comando Import torna disponível para o pacote corrente, as classes dos pacotes mencionados após a cláusula import.
103.
Resolvendo Nomes eColisões Quando dois ou mais pacotes são importados para um determinado programa e eles contém classes de mesmo nome isso não representa problemas de colisão caso tais classes não sejam utilizadas No caso de ser necessário fazer referência a uma das classes citadas acima, isso deve ser feito de modo explícito para que não haja problemas de colisão. Caso isso não seja feito, o compilador enviará uma mensagem de erro, forçando que essa chamada seja explicitada. java.util.Date / java.sql.Date
104.
Modificadores de acessoclass MinhaClass { } Apesar desta declaração funcionar a mesma não é ideal, pois como já vimos necessitamos organizar o nosso código na forma de pacotes, e precisamos ainda organizar o acesso as nossas classes. Ou seja, precisamos definir quem poderá acessar nossas classes e de onde.
105.
Modificadores De acesso: public, protected, private. Não relacionados a acesso : strictfp, final, e abstract.
106.
Modificadores ( emmiúdos ) Podemos exemplificar o acesso a classes, se dissermos por exemplo que a class A tem acesso a outra classe B, e isto significa que a classe A pode fazer uma destas 3 coisas : Criar uma instância de B Extender B ( ser uma sub-classe de B ) Acessar certos métodos e variáveis dentro de B, dependendo do controle de acesso destes métodos e variáveis.
107.
Modificadores ( emmiúdos ) Na verdade acesso significa visibilidade . Se a classe A não puder ver a classe B, então o nível de acesso dos métodos e variáveis dentro de B não farão a menor diferença, pois a classe A não terá como acessá-los de forma alguma.
108.
Acesso Default Default– Uma classe com acesso default não possui declaração de modificadores, e este é o acesso default quando não especificamos nenhum. Default também é conhecido como “package level access”, por que as classes com acesso default podem somente ser vista por classes dentro do mesmo pacote.
109.
Default, exemplo ArquivoBeverage.java package cert; class Beverage { } Arquivo Tea.java package exam.stuff; import cert.Beverage; class Tea extends Beverage { } Se tentarmos compilar.... Can't access class cert.Beverage. Class or interface must be public, in same package, or an accessible member class. import cert.Beverage;
110.
Acesso Public Public– Uma classe que é declarada com a palavra chave public dá acesso a todas classes de todos pacotes. Todas as classes do universo ( e outros universos paralelos) tem acesso a classes “public” .
Private Como opróprio nome já diz, “private” é um modificador para acesso privado, ou seja, ninguém externamente a classe tem acesso ao que for definido com esse modificador de acesso.
113.
Final Classes definidascomo “final” não podem ter sub-classes ! Em outras palavras, outras classes não poderão extendê-las, e qualquer tentativa receberemos um erro do compilador.
114.
Final, exemplo packagecert; public final class Beverage { public void importantMethod() { } } package exam.stuff; import cert.Beverage; class Tea extends Beverage { } Se tentarmos compilar de novo... Can't subclass final classes: class cert.Beverage class Tea extends Beverage{ 1 error
115.
Abstract Classes declaradascomo “abstract” não podem ser instanciadas, isto acontece porque as mesmas são usadas como template para outras classes, ou seja, elas já nasceram para conterem algum comportamento base e serem extendidas e terem um refinamento nas sub-classes.
116.
Abstract, exemplo abstractclass Carro { private double price; private String model; private String year; public abstract void goFast(); public abstract void goUpHill(); public abstract void impressNeighbors(); // Mais métodos... } Se tentarmos a façanha de instanciá-la : Carro.java:7: class Car is an abstract class. It can't be instantiated. Car x = new Car(); 1 error
117.
Abstract, exemplo packagecomida; public abstract class Fruta{ /* any code you want */ } import comida; class Banana extends Fruta{ /* any code you want */ }
118.
Herança Extends éa palavra chave usada para podermos definir herança entre classes no Java. Toda sub-classe possui todas as características da classe base que foi herdada, isso funciona quase que exatamente como se fosse herança genética, onde o herdeiro tem as características de seus pais, cor dos olhos, cabelo, feições e etc. Simplesmente usamos a seguinte notação : ClasseB extends ClasseA
119.
Herança Com herançapodemos modificar todo o comportamento de uma cadeia de classes alterando somente o código da classe base. Por isso devemos ter muito cuidado quando fazemos o design da mesma, pois um bug ou código mal-feito se extenderá por toda hierarquia de classes.
120.
Interfaces Interfaces sãouma alternativa a herança, qualquer classe pode “assinar” ou seja, implementar os métodos definidos na mesma, sem dizer como o farão. Elas são também vistas como contratos, pois qualquer classe que implementar a interface serão obrigadas a implementar seus métodos. Interfaces podem ser implementadas por qualquer classe, de qualquer lugar ou hierarquia. Isso nos permite mudar radicalmente a característica de diferentes classes dando a elas a mesma característica.
Interfaces, exemplo packagebr.com.jetsoftware.domain; import java.util.Date; public interface IContratoFinanceiro { double calcularBalanco(); double calcularHistorico(Date dataInicial, Date dataFinal); double saldoMensal(int mes, int ano); }
123.
Interfaces, exemplo packagebr.com.jetsoftware.domain; import java.util.Date; public class Caixa implements IContratoFinanceiro { public double calcularBalanco() { //seus cálculos return 2; } public double calcularHistorico(Date dataInicial, Date dataFinal) { //seus cálculos if (dataFinal.getTime() < dataInicial.getTime()) { return 0; } return 55.3; } public double saldoMensal(int mes, int ano) { //seus cálculos return 30; } }
124.
Interfaces, exemplo packagebr.com.jetsoftware.domain; import java.util.Date; public class ContratoFinanceiro implements IContratoFinanceiro { public double calcularBalanco() { //seus cálculos return 7; } public double calcularHistorico(Date dataInicial, Date dataFinal) { //seus cálculos return 99.4; } public double saldoMensal(int mes, int ano) { //seus cálculos return 652.478; } }
125.
Interfaces Interfaces podemser vistas como classes 100% abstratas. Nós dissemos 100% abstratas pois enquanto classes abstratas podem definir métodos abstratos e não abstratos, interfaces por sua vez podem somente definir métodos abstratos. Outra diferença que existe entre interfaces e classes é que interfaces possuem pouca flexibilidade no tocante como métodos e variáveis são definidas. Todos os métodos de uma interface são implicitamente públicos e abstratos. Ou seja, não precisamos digitar as palavras chave public ou abstract, pois os mesmos serão sempre public e abstract. Todas as variáveis dentro de uma interface devem ser public, static, e final, ou seja, interfaces podem declarar somente constantes.
126.
Interfaces Métodos deInterfaces não podem ser static. Já que métodos de interfaces são abstratos, eles não podem ser marcados como final, strictfp, or native. Uma interface pode estender ( extends ) uma ou mais interfaces. Uma interface não pode extender nada além de outra interface. Uma interface não pode implementar outra interface ou classe. Uma interface deve ser declarada com a palavra chave interface. Interfaces podem ser usadas de forma polimórfica.
127.
Modificadores de acessopara atributos Métodos e variáveis permitem o acesso quase que da mesma forma. Existem 4 tipos de acesso distintos para atributos : Public Protected Default private
128.
Modificadores de acessopara atributos Como vimos anteriormente, a proteção default é aquela que recebemos quando não digitamos nenhum modificador de acesso na declaração do membro. Os modificadores default e protected tem quase que o mesmo comportamento, exceto por uma diferença que será mencionada mais a frente.
129.
Modificadores de acessopara atributos Public – Todos podem acessar. Private – Só pode ser acessado pela mesma classe na qual o o atributo foi definido. Default – Pode ser acessado se a classe que está tentando acessá-lo estiver dentro do mesmo pacote. Protected – Pode ser acessado por qualquer sub-classe mesmo que estejam em pacotes diferentes. Variáveis locais a um método não podem ter modificadores de acesso. Isto por que elas já são privadas ao método.
130.
Encapsulamento Muito importante: conseguimos usar objetos da classe ContaCorrente sem saber nada sobre como a mesma foi implementada! • Isso se chama Ocultação de Informação e é muito importante na programação • É a forma básica de lidar com a complexidade dos programas • É comum usarmos "private" como especificador de controle de acesso para atributos de uma classe
131.
Encapsulamento Também podemosdizer que a classe ContaCorrente encapsula dados e comportamento em cima desses dados Os dados são os atributos escondidos de nós (saldo, histórico de transações, dados do titular, etc) • O comportamento são os métodos que podemos chamar para manipular o objeto • Só podemos “alterar" o estado do objeto através de seus métodos.
132.
Overloading e RedefiniçãoEm Java, o que identifica unicamente o método é o nome e a lista de argumentos. A técnica de definir métodos de mesmo nome, com listas de argumentos diferentes é chamado de " method overloading " . Quando uma classe B define um método usando o mesmo nome, tipo de retorno e argumentos de um método de uma classe ancestral A , este método redefine o método da classe ancestral.
133.
Overloading e Redefiniçãopublic class ContaCorrente { public ContaCorrente ( String t, String c, int n ) { numero = n; titular = new Titular ( t, c ); } public ContaCorrente ( Titular t, int n ) { numero = n; titular = t; } }
134.
Overloading e Redefiniçãopublic class Animal { public void comer() { System.out.println("Eu como de forma genérica !"); } public void respirar() { System.out.println("Eu respiro de forma genérica !"); } }
135.
Overloading e Redefiniçãoclass Cao extends Animal { public void comer() { System.out.println("Eu com o foçinho enfiado na minha tijela."); } public void respirar() { System.out.println("Eu respiro pelos pulmoões e somente fora da agua."); } }
136.
Overloading e Redefiniçãoclass SerHumano extends Animal { public void comer() { System.out.println("Eu como sentado na mesa, com garfo e faca."); } public void respirar() { System.out.println("Eu respiro pelos pulmoões e somente fora da agua."); } }
137.
Visibilidade de membrosVisibilidade Public Protected Default Private De dentro da mesma classe Sim Sim Sim Sim De qualquer classe dentro do mesmo pacote Sim Sim Sim Não De uma sub-classe dentro do mesmo pacote Sim Sim Sim Não De uma sub-classe fora do pacote Sim Sim, por herança Não Não De qualquer não sub-classe fora do pacote Sim Não Não Não
138.
Polimorfismo A palavra"polimorfismo" significa "Que apresenta várias formas“ Numa linguagem de programação, o polimorfismo permite tratar objetos de classes diferentes do mesmo jeito (com as mesmas chamadas a métodos), porque elas têm o mesmo comportamento As classes fazem a mesma operação (método), mas de forma diferente – "O quê" é igual – "Como" é diferente
139.
Polimorfismo public staticvoid main(String[] args) { Animal a1 = new Cao(); Animal b1 = new SerHumano(); a1.comer(); b1.comer(); } Eu com o foçinho enfiado na minha tijela. Eu como sentado na mesa, com garfo e faca.
Exercícios Pense sobrea implementação do seguinte programa, dado em pseudo-código Programa de Controle Bancácio 1. Abra uma conta de número 1 para João com CPF 309140605-06. Nesta conta, deposite R$1000,00. 2. Abra uma conta de número 2 para Ana com CPF 123456789-01. Transfira R$400,00 da conta de João para a conta de Ana. 3. Imprima o saldo da conta de João. 4. Imprima o saldo da conta de Ana.
142.
Exercícios Quais asclasses que podemos identificar neste exemplo? • Quais são os atributos relevantes para o nosso modelo do mundo real? • Quais os comportamentos devem ser modelados?
Controle de fluxoÉ impossível imaginarmos algum programa que não precise executar nenhum código condicional ! O controle de fluxo é uma parte chave que qualquer linguagem tem, e o Java por sua vez oferece várias formas de fazer isto. Temos declarações de “if”, “for” para loops e muito mais.
145.
Controle de fluxoAs declarações “if” e “switch” são tipo de controles condição/decisão que permite aos nossos programas se comportarem diferentemente em uma “encruzilhada”, dependendo do resultado do teste lógico. O Java também provê três declarações de loop diferentes ( for, while e do ). As exceptions por sua vez não dão uma forma elegante de tratarmos error de run-time. Temos ainda as assertions, que foram adicionados na versão 1.4 do Java, que nos permite debugarmos e checarmos condições durante nossos testes.
146.
IF A formamais básica de “IF” é : if (booleanExpression) { System.out.println("Inside if statement"); } Onde a expressão deve ser verdadeira para que o código entre as chaves seja executado.
147.
IF / ELSEif (x > 3) { System.out.println("x é maior que 3"); } else { System.out.println("x não é maior que 3"); }
Switch, exemplo ( código mais limpo ) int x = 3; switch (x) { case 1: System.out.println("x is equal to 1"); break; case 2: System.out.println("x is equal to 2"); break; case 3: System.out.println("x is equal to 3"); break; default: System.out.println("Still no idea what x is"); }
155.
Expressão legal paraswitch/case switch (expression) { case constant1: code block case constant2: code block default: code block }
156.
Switch/case, break Obreak não é obrigatório na construção do switch, mas se não utilizarmos um break e a expressão for avaliada pare true, então o Java continuará avaliando as próximas expressões.
157.
Switch/case, break inta = 10; switch (a) { case 10: System.out.println("O valor é 10 !"); case 20: System.out.println("O valor é 20 !"); case 30: System.out.println("O valor é 30 !"); default: System.out.println("Nada feito, é default mesmo !"); } Resultado trágico : ============== O valor é 10 ! O valor é 20 ! O valor é 30 ! Nada feito, é default mesmo !
158.
Loops ( while) O loop “while” é utilizado em cenários onde não sabemos quantas vezes a declaração será repetida, então continuaremos no loop enquanto a condição for verdadeira. A expressão utilizada deverá sempre ser uma expressão lógica, ou seja, retornar true ou false ! while (expression) { // do stuff } Ou ainda : int x = 2; while(x == 2) { System.out.println(x); ++x; }
159.
Loops (do ...While) do { System.out.println("Inside loop"); } A declaração do/while é diferente de while, pois a expressão interna será executada antes da checagem.
160.
Loops ( for) A declaração for nos permite declarar uma ou mais variáveis do mesmo tipo dentro dos parênteses depois da declaração for, se declarmos mais de uma variável, então necessitamos delimitá-las por vírgula : for (int x = 10, y = 3; y > 3; y++) { }
Introdução I/O fornececomunicação com dispositivos – arquivos, console, networks, etc. • Onde o acesso aos dados podem ser: – sequenciais, aleatório, binário, caracteres, linhas, blocos, objetos, etc.
163.
I/O Streams I/O Stream representam uma fonte de input e um destino de output. Uma stream pode representar diferentes tipos de fontes e destinos, incluindo arquivos no disco, dispositivos, outros programas e arrays em memória. Streams suportam diferentes tipos de dados, incluindo simples bytes, tipos primitivos, caracteres de localização, e objetos. Algumas streams simplesmente passam dados, outras manipulam e transformam os dados de maneira útil. Não importa muito como elas trabalham internamente, todas streams representam o mesmo modelo simples de programação : Uma stream é uma sequencia de dados. Um programa usa uma input stream para ler dados de uma origem para um destino, um item por vez.
Byte Streams Os programas usam byte streams para input e output de bytes de 8 bits. Todas as classes de byte stream são descendentes de InputStream e OutputStream. Existem muitas classes byte stream, e para demonstrarmos como os byte stream trabalham, iremos utilizar o file I/O byte stream ; FileInputStream e FileOutputStream.
168.
Usando um ByteStream import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class CopyBytes { public static void main(String[] args) throws IOException { FileInputStream in = null; FileOutputStream out = null; try { in = new FileInputStream("xanadu.txt"); out = new FileOutputStream("outagain.txt"); int c; while ((c = in.read()) != -1) { out.write(c); } } finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } } }
169.
Usando um ByteStream O programa CopyBytes lê o conteúdo do arquivo dentro de um loop e escreve para uma output stream, um byte de cada vez.
170.
Usando um ByteStream O método read retorna um int, isto para nos permitir usar o resultado -1 para sabermos que o programa atingiu o fim da stream. Sempre fecha streams, isto é muito importante, pois esta prática garante que não ficaremos com recursos presos sem necessidade. Byte Streams devem ser utilizadas somente para I/O primitivos.
171.
Character Streams O Java armazena caracteres usando convenção Unicode. Stream de caracteres para I/O são traduzidas automáticamente de e para o conjunto de caracteres locais. Para a maioria das aplicações, I/O com caracteres é tão simples quanto com byte streams. O input e output é feito com classes de stream que fazem a tradução automética de conjuntos de caracteres. Um programa que usa streams de caracteres no lugar de byte streams adapta-se automáticamente aos caracteres locais e está pronta para internacionalização ( sem trabalho extra).
172.
Usando Character StreamsTodas as streams de caractere são descendentes de Reader e Writer. Como acontece com byte streams, existem character streams que são especializadas para fazer I/O: FileReader e FileWriter
173.
Usando Character Streamsimport java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class CopyCharacters { public static void main(String[] args) throws IOException { FileReader inputStream = null; FileWriter outputStream = null; try { inputStream = new FileReader("xanadu.txt"); outputStream = new FileWriter("characteroutput.txt"); int c; while ((c = inputStream.read()) != -1) { outputStream.write(c); } } finally { if (inputStream != null) { inputStream.close(); } if (outputStream != null) { outputStream.close(); } } } }
174.
Usando Character StreamsO programa CopyCharacters é muito semelhante ao CopyBytes. A grande diferença é que CopyCharacters usa FileReader e FileWriter para input e output no lugar de FileInputStream e FileOutputStream.
175.
Streams de caracteresque usam Byte Streams Existe também a possibilidade de fazer “wrapper” para byte streams. A stream de caracteres usa uma byte stream para executar o I/O físico, enquanto a stream de caracteres trata a tradução entre os caracteres e bytes. FileReader por exemplo usa FileInputStream, enquanto FileWriter usa FileOutputStream.
176.
I/O em linhasinteiras I/O com caracteres geralmente é utilizado com conjuntos maiores do que com caracteres únicos. Um conjunto comum é uma linha, que são vários caracteres agrupados com um terminador de linha no final. Um terminador de linha pode ser um carriage-return/line-feed (“\r\n”), carriage-return (“\r”), ou line-feed (“\n”).
177.
I/O em linhasinteiras Modificaremos o nosso exemplo anterior, afim de torná-lo um I/O orientado a linhas. Usaremos também duas novas classes, BufferedReader e PrintWriter.
178.
I/O em linhasinteiras import java.io.FileReader; import java.io.FileWriter; import java.io.BufferedReader; import java.io.PrintWriter; import java.io.IOException; public class CopyLines { public static void main(String[] args) throws IOException { BufferedReader inputStream = null; PrintWriter outputStream = null; try { inputStream = new BufferedReader(new FileReader("xanadu.txt")); outputStream = new PrintWriter(new FileWriter("characteroutput.txt"));
179.
I/O em linhasinteiras String l; while ((l = inputStream.readLine()) != null) { outputStream.println(l); } } finally { if (inputStream != null) { inputStream.close(); } if (outputStream != null) { outputStream.close(); } } } }
180.
Buffered Streams Os exemplos anteriores que utilizamos são do tipo unbuffered . Ou seja, toda leitura ou escrita é tratada diretamente pelo sistema operacional. Isto pode fazer com que o programa seja menos eficiente, visto que toda requisição desencadeia acesso ao disco, rede ou qualquer outra ação que seja cara. Para reduzir este tipo de sobrecarga, a plataforma Java implementa o I/O buferizado. Input streams buferizadas lêem dados da memória de uma área conhecida como buffer, a API nativa é invocada somente quando o buffer estiver vazio. Da mesma forma output streams escrevem dados para um buffer, e a API nativa é invocada somente quando o buffer estiver cheio. Um programa pode converter uma stream não buferizada para uma buferizada, usando wrappers, onde passamos o objeto não buferizado para o construtor de uma stream buferizada.
181.
Buffered Streams inputStream= new BufferedReader(new FileReader("xanadu.txt")); outputStream = new BufferedWriter(new FileWriter("characteroutput.txt")); Existem quatro classes de stream buferizadas para fazermos wrapper de streams não buferizadas : BufferedInputStreame BufferedOutputStream criam bute streams buferizados, enquanto BufferedReader e BufferedWriter criam streams de caracteres buferizados.
182.
Descarregando Buffered StreamsDevemos escrever os dados do buffer de tempos em tempos, pois é exatamente isso que queremos, escrever os dados em um meio persistente. Esta ação é conhecida como flushing o buffer. Algumas classes de output buferizadas suportam autoflush , especificado por um argumento opicional no construtor. Quando o autoflush está ligado, alguns eventos causam o descarregamento do buffer ( flush ). Por exemplo, um autoflush em objetos PrintWriter acontecem em cada invocação do método println ou format. Para realizar o flush na stream de forma manual, basta usar o método flush.
183.
Escaneando e formatandoInput e Output as vezes envolvem a tradução de formatos estranhos para formato humano. Para a realização desta tarefa o Java provê duas APIs. A API scanner quebra o input em tokens individuais associados com bits de dados. A API formatting monta os dados em formato bem formatado pronto para a leitura humana.
184.
Escaneando e formatandoimport java.io.*; import java.util.Scanner; public class ScanXan { public static void main(String[] args) throws IOException { Scanner s = null; try { s = new Scanner(new BufferedReader(new FileReader("xanadu.txt"))); while (s.hasNext()) { System.out.println(s.next()); } } finally { if (s != null) { s.close(); } } } }
185.
Escaneando e formatandoIn Xanadu did Kubla Khan A stately pleasure-dome ... Usando um token diferente : s.useDelimiter(",\\s*")
186.
Traduzindo tokens individuaisA classe Scanner suporta todos os tipos primitivos do Java ( com exceção de char ), e também BigInteger e BigDecimal. Também valores numéricos podem usar diferentes separadores.
187.
Traduzindo tokens individuaisimport java.io.FileReader; import java.io.BufferedReader; import java.io.IOException; import java.util.Scanner; import java.util.Locale; public class ScanSum { public static void main(String[] args) throws IOException { Scanner s = null; double sum = 0; try { s = new Scanner(new BufferedReader(new FileReader("usnumbers.txt"))); s.useLocale(Locale.US); while (s.hasNext()) { if (s.hasNextDouble()) { sum += s.nextDouble(); } else { s.next(); } } } finally { s.close(); } System.out.println(sum); } }
Formatação Stream deobjetos que implementam formatação são instâncias de PrintWriter (stream de caracter), ou PrintStream (classe de byte stream). Como todos os objetos de streams de bytes ou caracteres, instâncias de PrintStream e PrintWriter implementam o conjunto padrão de métodos write para output de byte ou caractere. Em adição, ambos PrintStream e PrintWriter implementam o mesmo conjunto de métodos para conversão de dados interno para output formatado. Onde dois níveis de formatação são providos : print e println formatam valores individuais numa maneira padrão format formata quase qualquer valor numérico baseado em uma string de formatação, com várias opções de formatação.
190.
Formatação public classRoot { public static void main(String[] args) { int i = 2; double r = Math.sqrt(i); System.out.print(“A raiz quadrada de "); System.out.print(i); System.out.print(" é "); System.out.print(r); System.out.println("."); i = 5; r = Math.sqrt(i); System.out.println(" A raiz quadrada de " + i + " é " + r + "."); } } A raiz quadrada de 2 é 1.4142135623730951. A raiz quadrada de 5 é 2.23606797749979.
191.
O método formatO método format formata múltiplos argumentos baseado em uma string. public class Root2 { public static void main(String[] args) { int i = 2; double r = Math.sqrt(i); System.out.format("The square root of %d is %f.%n", i, r); } }
192.
O método formatComo usado no exemplo anterior, todos os formatadores começam com um % e terminam em 1 ou 2 caracteres que especificam o tipo de output formatado. d – formata um valor inteiro como decimal f - formata um valor ponto flutuante como decimal n – gera um delimidador que é específico de uma plataforma x – formata um inteiro como hexadecimal s - formata qualquer valor como string tB – formata um inteiro como um “local-specific” nome de mês
193.
O método formatpublic class Format { public static void main(String[] args) { System.out.format("%f, %1$+020.10f %n", Math.PI); } } Resultado : 3.141593, +00000003.1415926536
194.
O método formatOs elementos adicionais de nossa formatação são todos opcionais. Precision – para pontos flutuantes é a precisão do valor formatado ( pode ser truncado). Width – o tamanho mínimo do valor formatado. Flags – especifica formatação adicional, neste caso o número será sempre exibido com o sinal + Argument Index – nos permite explicitamente encontrarmos um determinado argumento.
195.
I/O na linhade comandos Um programa também pode rodar na linha de comandos para interagir com o usuário final. O Java suporta este tipo de interação atráves do Console. Uma alternativa avançada as streams é o Console. Este objeto possui a maior parte das features disponíveis pelas stream standard, e outros objetos. O console é bem interessante para entradas de senha. Este objeto também provê input e output de streams que são streams de caracteres, através de seus métodos reader e writer. Antes de um programa poder usar o Console, o mesmo deve tentar recuperar este objeto invocando o método System.console(). Se o objeto Console estiver disponível este método o retornará, senão o mesmo retornará NULL, e então a interação com o console não será possível, pois o sistema operacional não suporta esta operação, ou o programa foi executado em um ambiente não interativo.
196.
import java.io.Console; importjava.util.Arrays; import java.io.IOException; public class PegaSenha { public static void main (String args[]) throws IOException { Console c = System.console(); if (c == null) { System.err.println("Sem console."); System.exit(1); } String login = c.readLine("Digite seu login: "); char [] oldPassword = c.readPassword("Digite sua senha : ");
197.
if (verify(login, oldPassword)){ boolean noMatch; do { char [] newPassword1 = c.readPassword("Digite sua senha: "); char [] newPassword2 = c.readPassword("Digite sua senha: "); noMatch = ! Arrays.equals(newPassword1, newPassword2); if (noMatch) { c.format("A senha não confere. Tente de novo.%n"); } else { change(login, newPassword1); c.format("Senha de %s modificada.%n", login); } Arrays.fill(newPassword1, ' '); Arrays.fill(newPassword2, ' '); } while (noMatch); }
Data Streams Data streams suportam I/O binário de tipos primitivos (boolean, char, byte, short, int, long, float, and double) e também Strings. Todos os data stream implementam as interfaces DataInput ou DataOutput. Conheceremos também suas famosas implementações, DataInputStream e DataOutputStream.
200.
Data Streams (output ) import java.io.BufferedOutputStream; import java.io.DataOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class UseOutputDataStream { static final String dataFile = "pedido"; static final double[] prices = { 19.99, 9.99, 15.99, 3.99, 4.99 }; static final int[] units = { 12, 8, 13, 29, 50 }; static final String[] descs = { "Camisa do Java", "Chaveiro do Java", "Disquete", "Pen Drive", "Boné" };
201.
Data Streams (output ) public static void main(String[] args) throws FileNotFoundException, IOException { DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dataFile))); //Escrevendo para a stream for (int i = 0; i < prices.length; i ++) { out.writeDouble(prices[i]); out.writeInt(units[i]); out.writeUTF(descs[i]); } } }
202.
Data Streams (input ) import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.EOFException; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class UseInputDataStream { static final String dataFile = "pedido"; public static void main(String[] args) throws FileNotFoundException, IOException { DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(dataFile))); double price; int unit; String desc; double total = 0.0;
203.
Data Streams (output ) //Lendo do arquivo try { while (true) { price = in.readDouble(); unit = in.readInt(); desc = in.readUTF(); System.out.format("You ordered %d units of %s at $%.2f%n", unit, desc, price); total += unit * price; } } catch (EOFException e) { } System.out.println("Total = " + total); } } Nota : DataStreams detectam o fim de arquivo capturando EOFException, ao invés de testarem um valor de retorno. E todas implementações de métodos de DataInput usam EOFException como retorno.
204.
Object Streams Da mesma forma que streams suportam serialização de primitivos, elas também suportam I/O para objetos. Várias, mas nem todas as classes standard suportam serialização para seus objetos. Estas mesmas devem implementar a interface Serializable. As classes de object stream são ObjectInputStream e ObjectOutputStream. Essas classes implementam ObjectInput e ObjectOutput, que são sub-interfaces de DataInput e DataOutput. Isso significa que todos os métodos de I/O para dados primitivos cobertos em Data Streams são também implementados em streams de objetos. Se o método readObject() não retornar o tipo de objeto esperado, e ouver uma tentativa de cast para o tipo corredo, então a exception ClassNotFoundException poderá ser lançada.
205.
Output e Inputde objetos complexos Os métodos writeObject e readObject são muito simples de usar, mas eles contém uma lógica muito sofisticada de gerenciamento de objetos. Muitos objetos contém referências para outros objetos. Se readObject precisa reconstruir um objeto de uma stream, então o mesmo tem que reconstruir TODOS os objetos do grafo. Estes objetos adicionais podem ter suas próprias referências, que também deverão ser resolvidas e etc. Uma única invocação de writeObject pode causar que um grande número de objetos sejam escritos para a stream.
Object Streams Sedois objetos dentro da mesma stream contiverem referência para um mesmo objeto, então eles irão referenciar um único objeto quando eles forem reconstruídos. Pois uma stream pode conter somente uma cópia de um objeto, apesar de poder conter um número infinito de referencias ao mesmo. Se escrevermos um objeto para uma stream duas vezes, então nós realmente estaremos escrevendo somente a referência duas vezes.
208.
Object Streams Objectob = new Object(); out.writeObject(ob); out.writeObject(ob); Mas, se um único objeto for escrito para duas streams diferentes, então o mesmo será efetivamente duplicado.
209.
Arquivos Mantivemos ofoco de nossa discussão nas streams, que nos dão um modelo simples de leitura e escrita de dados. Streams trabalham com uma grande variedade de fontes de dados e destinos, incluindo arquivos no disco. Mas, streams não suportam todas as operações que são comuns com arquivos em disco, e é onde veremos dois conceitos não-stream : File Random Access File
210.
File Objects A classe File nos torna muito fácil escrever código independente de plataforma que examina e manipula arquivos. O nome desta classe é um pouco confuso, pois instâncias de Files representam nomes de arquivos e não arquivos propriamente ditos, e o arquivo correspondente ao nome pode mesmo nem existir.
211.
Capturando as propriedadesde um arquivo import java.io.File; import java.io.IOException; import static java.lang.System.out; public class FileStuff { public static void main(String args[]) throws IOException { out.print("File system roots: "); for (File root : File.listRoots()) { out.format("%s ", root); } out.println(); for (String fileName : args) { out.format("%n------%nnew File(%s)%n", fileName); File f = new File(fileName); out.format("toString(): %s%n", f); out.format("exists(): %b%n", f.exists()); out.format("lastModified(): %tc%n", f.lastModified());
Random Access FileRandom acess files permitem o acesso aleatório ao conteúdo de um arquivo. new RandomAccessFile("xanadu.txt", "r"); new RandomAccessFile("xanadu.txt", "rw"); int skipBytes(int) — Move o ponteiro do arquivo para a frente com o número de bytes especificado. void seek(long) — Posiciona o pointeiro antes do byte especificado. long getFilePointer() — Retorna o a localização corrente do byte.
O que éuma exception ? O termo exception vem da frase “exceptional event”. Uma exception é um evento, que por sua vez ocorre durante a execução de um programa, que “bagunça” o fluxo normal do mesmo. Quando um erro ocorre dentro de um método, o método cria um objeto e o entrega ao sistema de runtime. O objeto é chamado de objeto de exceção, e contém informações sobre o erro, incluindo o seu tipo e estado do programa quando o erro aconteceu. A criação de objetos de exceção e a entrega deles ao sistema de runtime é chamado de “ throwing an exception ”, ou lançamento de exceções. Após um método lançar uma exceção, o sistema de runtime tenta encontrar alguém para tratar a mesma. O conjunto possível de candidatos a tratar a exceção é a lista ordenada de métodos que foram invocados até chegar ao método que lançou a exceção. Esta lista é denominada call stack .
Tratamento de exceçãoO sistema de runtime procura o call stack por um método que contém um bloco de código que possa tratar a exceção. Este bloco de código é denominado exception handler . A busca inicia-se com no método onde o erro ocorreu e segue através da call stack em ordem reversa que os métodos foram invocados. Quando um handler apropriado é encontrado, o sistema de runtime passa a exceção para o handler. Um exception handler é considerado apropriado se o tipo de objeto de exceção lançado é do mesmo tipo tratado pelo handler. O exception handler escolhido catch the exception , ou a caputra. Se o sistema de runtime procura em toda call stack e não consegue achar um handler, enão o sistema de runtime ( e o programa ) terminarão.
Capturando e tratandoexceções Um código Java válido para tratar exceções deve : Usar uma declaração try para capturar a exceção, e o mesmo deve prover um tratador para esta exception. Ou O método deve especificar que o mesmo lança a exception, onde o método deve também declarar a cláusula throws .
220.
Três tipos deexceção O primeiro tipo de exception as chamadas checked exeption . Estas exceptions são detectadas pelo compilador Java, e temos como exemplos : java.io.FileNotFoundException O segundo tipo de exception é o tipo error . Esta exception é ocasionada por algo externo a aplicação, e a aplicação geralmente não consegue antecipar-se a este tipo de exceção. Podemos usar como exemplo a abertura de um arquivo, pois podemos conseguir abrir o mesmo, mas na hora de gravarmos recebemos um erro por conta de uma falha de hardware que nos impediu de gravarmos o arquivo, exemplo : java.io.IOErro O terceiro tipo de exception são as runtime exceptions , que são internas a aplicação, mas a mesma não consegue se prevenir da mesma. Este tipo geralmente aponta para bugs, tais como error de lógica ou mal uso da API, exemplo : NullPointerException
221.
Capturando e tratandoexceções public class Numeros { public static void main(String []args) { int[] a = new int[5]; a[0] = 5; a[1] = 3; a[2] = 6; a[3] = 9; a[4] = 88; for (int i = 0; i < 6; i++) { int j = a[i]; } } } Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5 at Numeros.main(Numeros.java:13)
222.
O bloco tryA primeira coisa que devemos fazer para tratarmos um código de lança uma exceção é colocá-la em um bloco try : try { //codigo aqui } catch...
223.
O bloco try/ catch Nós criamos tratadores combinando blocos try e catch, onde cada catch será um tratador para uma excepção diferente : import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; public class OpenFile { public static void main(String[] args) { File f = new File("MeuArquivo.txt"); PrintWriter out = null; try { out = new PrintWriter(f); } catch (FileNotFoundException ex) { System.out.println("Não consegui abir o arquivo. " + ex.getMessage()); } catch (IOException ex) { System.out.println("Peguei uma IOException. " + ex.getMessage()); } } }
224.
O bloco finallyO bloco finally sempre é executado quando um try existe. Isto garante que o bloco finally será executado mesmo quando uma exceção inesperada aconteça. Mas o finally é muito útil além de tratar exceções. O finally permite ao programador ter qualquer código de limpeza sendo pulado acidentamente por algum return, continue ou break. Colocar código de limpeza dentro do finally é uma ótima prática. }finally{ if (out != null ) { System.out.println("Fechando o arquivo..."); out.close(); }else{ System.out.println("O arquivo não estava aberto !"); } }
225.
Especificando exceptions lançadaspor um método Vimos anteriormente que podemos tratar as exceptions dentro de nossos próprios métodos, mas existe ainda a opção de deixarmos este tratamento para todo código “cliente” que invocar nosso método. Para isso precisamos adicionar a cláusula throws na assinatura de nosso método, seguido das possíveis exceções que nosso código lançará :
226.
Especificando exceptions lançadaspor um método import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; class TrataArquivo { public void abreArquivo() throws FileNotFoundException { File f = new File("MeuArquivo.txt"); PrintWriter out = null; out = new PrintWriter(f); out.println("ABCDEFGH"); out.close(); } }
227.
Especificando exceptions lançadaspor um método public class OpenFile { public static void main(String[] args) { TrataArquivo ta = new TrataArquivo(); try { ta.abreArquivo(); } catch (FileNotFoundException ex) { System.out.println("Não consegui abrir o arquivo..."); } } }
228.
Lançando exceções Émuito simples lançar exceções, tudo que necessitamos fazer é utilizarmos a cláusula throw dentro do método desejado : throw umObjeto Throwable ;
229.
Lançando exceções publicclass LancandoExceptions { public double calculaPagamento(int mes) throws Exception { if (mes < 1 || mes > 12) { throw new Exception("Mês inválido !"); } return 99.7; } }
Filhos de ThrowableError – Quando acontece um erro na virtual machine ela lança uma exceção deste tipo. E os programas geralmente não capturam ou lançam este tipo de exceção. Exception – Um objeto deste tipo indica que um problema ocorreu, mas isso não é um problema da VM e sim do programa, e geralmente os programas usam suas próprias exceptions para tratar condições de erro. Podemos usar como exemplos de exceptions : IllegalAccessException – Indica que um método não pode ser encontrado. NegativeArraySizeException – Indica que o programa tentou criar um array com tamanho negativo. A classe RuntimeException é reservada para exceptions que dizem respeito ao uso incorreto da API, e podemos citar como exemplo o NullPointerException, que é a tentativa de operação sobre um objeto nulo.
232.
Exceções em cadeiaUma aplicação pode tratar uma exceção simplesmente lançando uma outra exceção. Esta técnica é muito útil, pois podemos capturar uma exceção genérica e transformá-la em outra mais específica : try { } catch (IOException e) { throw new MyException(“Outro Erro", e) ; }
233.
StackTrace O objetoStackTrace é responsável por retornar um texto com a cadeia de métodos invocados até o lançamento da exceção : public static void main(String[] args) { Exception e = new Exception("Um erro foi gerado por mim !"); e.printStackTrace(); } Resultado : java.lang.Exception: Um erro foi gerado por mim ! at LancandoExceptions.main(LancandoExceptions.java:13)
234.
Criando uma exceçãopublic class MinhaExcecao extends Exception { public MinhaExcecao() { super(); } public MinhaExcecao(String message) { super(message); } }
235.
Nota sobre uncheckedexceptions Muitos programadores sentem-se tentados a escrever código que herdam e lançam somente unchecked exceptions, pois as mesmas não são checadas pelo compilador. Isto é uma péssima prática ! Uma exception que pode ser lançada por um método é parte de sua interface pública, e todos que invocam esses métodos devem saber sobre as exceções que o método pode lançar, e então os mesmos podem decidir como tratá-las. Runtime Exceptions representam problemas que são resultado de programação, e o código cliente não é esperado que se recupera deste tipo de erro. Estes erros incluem exceções de aritimética, divisão por zero, null pointer exceptions, exception de índices dentre outros. Regra básica : Se o cliente pode se recuperar da exception, então a exception deve ser checked, caso contrário, ela deve ser unchecked.
236.
Exceptions são Umaforma organizada de tratar um evento excepcional que aconteceu durante o fluxo do seu programa. As exceptions eliminam os códigos tipo espaguete ( bacalhau ) da forma tradicional de tratamento de erros.
Concorrência Nós usuáriosde computadores acreditamos e confiamos que nossos sistemas podem fazer mais de uma coisa ao mesmo tempo. Assumimos que podemos continuar trabalhando no work enquanto fazemos download de músicas, imprimimos algo, copiamos arquivos e etc. Mesmo um simples aplicativo é esperado fazer mais de uma coisa de cada vez. A plataforma Java foi re-estruturada do zero para suportar programação concorrente, com suporte concorrente básico na linguagem java e em suas bibliotecas. Desde a versão 5.0 que a plataforma Java incluiu também a biblioteca de concorrência.
239.
Processos e threadsEm programação concorrente, existem duas unidades básicas de execução : processos e threads . Em Java a programação concorrente está mais focada em threads. Mas de qualquer forma os processos também são importantes. Um computador normalmente possui vários processos ativos e threads. E isto também é verdadeiro para sistemas que possuem uma única linha de execução, e possui somente uma thread sendo executada naquele momento. Tempo de processamento para um único core é compartilhado entre os processos e threads através de uma feature do SO chamada “time slicing”. Hoje em dia é muito comum que os computadores tenham vários procesadores com vários cores, e isto aumenta em muito a capacidade de execução concorrente de processos e threads. Mas a concorrência também é possível em sistemas simples, onde não existam vários processadores ou cores de execução.
240.
Processos Um processoé um ambiente de execução auto-contido. E um processo geralmente tem um conjunto privado e completo de recursos de runtime, e em particular cada processo possui sus própria área de memória. Processos são geralmente vistos como sinônimos de programas ou aplicações, entretanto oque o usuário vê como uma simples aplicação pode ser na realidade um conjunto de processos cooperando. Para facilitar a comunicação entre processos, vários SOs suportam recursos de Inter Process Communication (IPC), tal como pipes ou sockets. IPC não é usado somente para a comunicação entre processos no mesmo sistema, mas processos em diferentes sistemas A grande maioria das implementações da JVM rodam em um único processo. Uma aplicação Java pode criar processos adicionais usando um objeto ProcessBuilder.
Threads Threads sãotambém conhecidas como processos leves. Ambos processos e threads provêem um ambiente de execução, mas criar novas threads requer muito menos recursos do que criar novos processos. Threads existem dentro de processos, e cada processo possui pelo menos uma. As threads compartilham os recursos do processo, incluindo memória e arquivos. Isso aumenta em muito a eficiência, mas pode acarretar em uma comunicação problemática. Execução multi-thread é uma feature essencial da plataforma Java. Onde cada aplicação possui pelo menos uma thread, ou várias, se contarmos as threads do sistema que realizam trabalhos como gerenciamento de memória e tratamento de sinais. Mas da perspectiva do programador o programa é iniciado com uma única thread, chamada main thread .
243.
Objetos Thread Cadathread é associada com uma instância da classe Thread . E existem duas formas de usarmos o objeto thread : Para controlar a thread diretamente, simplesmente instanciamos uma Thread cada vez q a aplicação precisar realizar alguma tarefa assíncrona. Para abstrair o gerenciamento da thread do resto da aplicação, passamos a tarefa a um executor.
244.
Definir e iniciaruma Thread Criar um objeto Runnable. A interface Runnable define um método chamado run, que é esperado conter o código a ser executado em uma thread. O objeto runnable então é passado no construtor da thread para ser executado : public class HelloRunnable implements Runnable { public void run() { System.out.println("Hello from a thread!"); } public static void main(String args[]) { (new Thread(new HelloRunnable())).start(); } }
245.
Definir e iniciaruma Thread Criar uma sublasse de Thread. Podemos fazer isso pois a classe Thread também implementa runnable diretamente. Podemos então criar uma subclasse e prover o código para o método run : public class HelloThread extends Thread { public void run() { System.out.println("Hello from a thread!"); } public static void main(String args[]) { (new HelloThread()).start(); } }
246.
Dando uma pausana execução com sleep O método Thread.sleep causa a suspensão da execução da thread corrente por um período específico de tempo. Isto é uma forma eficiente para termos tempo de processamento disponível para outras threads de uma aplicação, ou ainda para outras aplicações rodarem. O método sleep pode também ser usado para marcar o ritmo de execução, como por exemplo aguardar por outra thread. public static native void sleep(long millis) throws InterruptedException; public static void sleep(long millis, int nanos) throws InterruptedException;
247.
Exemplo public classSleepMessages { public static void main(String args[]) throws InterruptedException { String importantInfo[] = { "Mares eat oats", "Does eat oats", "Little lambs eat ivy", "A kid will eat ivy too" }; for (int i = 0; i < importantInfo.length; i++) { //Pause for 4 seconds Thread.sleep(4000); //Print a message System.out.println(importantInfo[i]); } } }
248.
Nota No exemploanterior vimos que o método main declara uma InterruptedException, que é a exception que o método sleep lança quando outra thread interrompe a thread corrente enquanto o sleep está ativo.
249.
Interrupções Uma interrupçãoé um indicativo que a thread deve de fazer aquilo que estiver fazendo, e fazer alguma outra coisa. É de inteira responsabilidade do programador dizer como a thread responde a uma interrupção, mas é muito comum a thread ser terminada nesses casos. A thread envia uma interrupção invocando o método interrupt no objeto Thread para a thread que será interrompida. E para este mecanismo funcionar direito, a thread interrompida deve suportar sua própria operação.
250.
Suportando interrupções Athread suporta interrupções através de vários métodos, podendo lançar a exceção InterruptedException, onde a execução será abortada. for (int i = 0; i < 10; i++) { //Pausa por 4 segundos try { Thread.sleep(4000); } catch (InterruptedException e) { //Exceção capturada, e nada mais a fazer. return; } //Print a message System.out.println(i); }
251.
Suportando interrupções Existemvários métodos que lançam InterruptedException, e os mesmos foram configurados para cancelar sua execução corrente e retornar imediatamente qiuando uma interrupção for recebida. public static native void sleep(long millis) throws InterruptedException; public static void sleep(long millis, int nanos) throws InterruptedException {} public final synchronized void join(long millis) throws InterruptedException {} public final synchronized void join(long millis, int nanos) throws InterruptedException {} public final void join() throws InterruptedException {}
252.
Sabendo se umainterrupção foi recebida As vezes as threads podem ficar um tempo muito longo sem invocar nenhum método que lança uma InterruptedException, então podemos invocar o método Thread.interrupted para sabermos se uma interrupção foi recebida. if (Thread.interrupted()) { //Interrupção recebida return; }
253.
Joins O métodojoin permite uma thread aguardar pelo término do trabalho de outra. minhaThread.join(); Causa a interrupção da thread corrente até que minhaThread termine seu trabalho.
Sincronização Threads comunicam-seprimáriamente compartilhando o acesso a campos de objetos que elas referenciam. Esta forma de comunicação é muito eficiente, mas também é refém de dois erros : interferência de thread e erro de inconsistência de memória.
256.
Interferência Interferências acontecemquando duas operações, rodando em diferentes threads, mas operando sobre o mesmo dado se intercalam. public class Contador { private int campo = 0; public void incrementa() { campo++; } public void subtrai() { campo--; } public int valorAtual() { return campo; } }
257.
Exemplo de interferênciaThread 1 pega o contador Thread 2 pega o contador Thread 1 recupera o valor e o incrementa (1) Thread 2 recupera o valor e o decrementa (-1) Thread 1 armazena o valor em c, que agora vale (1) Thread 2 armazena o valor em c, que agora vale (-1)
258.
Métodos sincronizados OJava provê duas formas básicas de sincronização : métodos sincronizados e declarações sincronizadas. Para fazer um método se tornar sincronizado, somente precisamos adicionar a palavra chave synchronized em sua declaração.
259.
Métodos sincronizados publicclass ContadorSincronizado { private int c = 0; public synchronized void increment() { c++; } public synchronized void decrement() { c--; } public synchronized int value() { return c; } }
260.
Métodos sincronizados Agoraque temos um contador sincronizado, temos o seguinte resultado : Não é mais possível termos mais de uma invocação em métodos sincronizados simultâneamente. Quando uma thread está executando um método sincronizado de um objeto, todas as outras thread que invocam este mesmo método estão suspensas, até que a primeira thread termine seu trabalho com o objeto. Quando um método sincronizado existe, o mesmo garante a consistência com qualquer invocação futura de um método sincronizado do mesmo objeto. Isto garante que mudanças no estado do objeto sejam visíveis a todas as threads. Obs : Construtores não podem receber a cláusula synchronized, pois somente uma thread consegue criar uma instância por vez, e isto também ocasionará em um erro de compilação.
261.
Locks implícitos esincronização A sincronização é feita atrvés de uma dispositivo interno chamado “monitor lock” . Locks implícitos comandam o acesso exclusivo ao estado do objeto. Cada objeto tem um lock implícito associado a ele. Uma thread que precisa acesso exclusivo e consistente a um campo de um objeto precisa pegar um lock implícito antes de acessá-lo, e então liberá-lo quando terminar seu trabalho. A thread é dona do lock entre o momento em quen o pega, até o momento da liberação. Enquanto uma thread tiver o lock sobre o objeto, nenhuma outra thread conseguirá pegar o mesmo lock, ou seja, as outras threads serão bloqueadas quando tentarem realizar o lock.
262.
Locks em métodossincronizados Quando uma thread invoca um método sincronizado, a mesma adquire automáticamente o lock para o método do objeto e o libera quando o método retornar.
263.
Declarações sincronizadas Outraforma de criarmos código sincronizada é através das declarações sincronizadas . Ao contrário dos métodos sincronizados, as declarações devem especificar o objeto que provê o lock : public void addName(String name) { synchronized(this) { lastName = name; nameCount++; } nameList.add(name); }
264.
DeadLock O deadlocké uma situação onde duas ou mais threads ficam bloqueadas para sempre, esperando uma pela outra.
Introdução Uma coleçãoé um container, ou seja, um objeto que tem a capacidade de agrupar vários elementos em uma única unidade. Coleções são utilizadas para guardar, recuperar, manipular e comunicar dados agregados. Geralmente elas representam algum agrupamento natural, como por exemplo lista de funcionários, grupo de emails, e etc.
267.
O framework decoleções É a arquitetura unificada para representar e maniuplar coleções, onde todos os frameworks possuem : Interfaces : Que são dados abstratos que representam as coleções. As interfaces permitem que as coleções sejam manipuladas independentemente dos detalhes de implementação. Implementações : São as implementações concretas das interfaces, ou seja, elas são as estruturas “de fato”. Algorítimos : São métodos que executam operações úteis, tal como pesquisa e ordenação em objetos que implementam interfaces de coleções. Os algorítimos são polimórficos, ou seja, o mesmo método pode ser usado em diferentes implementa~ções.
268.
Benefícios do frameworkde coleções Reduz o trabalho com programação : Pois provê ótimas estruturas de dados e algorítimos, o framework de coleções nos libera para concentrarmos somente nas partes importantes do nosso programa, ao invés de ficarmos focados em problemas de “baixo-nível”. Aumenta a velocidade de programação e a qualidade : Pois provê implementações de alta performance e alta qualidade em suas estruturas e algorítimos. As várias implementações são intercambiáveis, então os programas podem mudar de implementação fácilmente. Reduz o tempo de aprendizado. Reduz o tempo de escrita de novas APIs Possibilita o reuso.
269.
Interfaces As interfacesdo core encapsulam diferentes tipos de coleções, que são mostradas na próxima figura. Estas interfaces permitem que as coleções sejam manipuladas independente de sua representação. As coleções do core são a pedra fundamental do Java Collections Framework.
270.
Collection A raizda hierarquia de coleções. Uma collection representa um grupo de objetos denominados elementos. A interface Collection é o denominador comum entre todas as coleções que a implementam e é usada para passar coleções a métodos e manipulá-las de forma genérica.
271.
Set É umacoleção que não pode ter elementos duplicados. Esta interface modela a abstração matemática de “conjunto”.
272.
List Uma coleçãoordenada ( também conhecida como sequência). As listas podem conter elementos duplicados. O usuário geralmente tem o controle preciso de onde o elemento é inserido na mesma, e pode acessá-lo usando um índice de posição.
273.
Queue Uma coleçãousada para carregar múltiplos elementos antes de processá-los. Queues típicamente, mas não necessáriamente, ordenam elementos no modo FIFO (first-in, first-out). Entre as exceções estão priority queues, que ordenam os elementos de acordo com um comparator fornecido.
274.
Map Um objetoque mapeia chaves e valores. Um mapa não pode ter chaves duplicadas, e uma chave só pode mapear um único valor.
275.
Sorted SortedSet -Um conujunto que mantém seus elementos em ordem ascendente. SortedMap – Um mapa que mantém os seus mapeamentos em ordem ascendente de chave. Este mapa é análogo ao SortedSet.
Atravessando coleções Declaraçãofor-each for (Object o : collection) { System.out.println(o); } Iterators public interface Iterator<E> { boolean hasNext(); E next(); void remove(); //optional } static void filter(Collection<?> c) { for (Iterator<?> it = c.iterator(); it.hasNext(); ) if (!cond(it.next())) it.remove(); }
278.
Operações em massasobre Collections Operações em massa são executadas em cima de uma coleção inteira. containsAll – retorna true se a coleção destino possui todos os itens na coleção especificada. addAll – adiciona todos os elementos da coleção especificada na coleção destino. removeAll – remove da coleção destino todos os elementos que também estiverem contidos na coleção especificada. retainAll – remove da coleção destino todos os elementos que não estiverem contidos na coleção especificada. clear – remove todos os elementos da coleção. c.removeAll(Collections.singleton(e)); c.removeAll(Collections.singleton(null));
279.
A interface Collectione Arrays O método toArray é provido como uma ponte de ligação entre coleções e APIs antigas que esperam arrays como entrada. As operações com arrays permitem que o conteúdo de uma coleção seja traduzido para um array. Object[] a = c.toArray();
Implementações de SetO Java possui 3 implementações para a interface Set. HashSet – Armazena os elementos em uma hash table, é a implementação de melhor performance, mas a mesma não garante order alguma no momento da iteração TreeSet – Armazena os elementos em formato red-black tree, ordena os elementos baseado nos seus valores, e é substancialmente mais lenta que HashSet. LinkedSet – Implementada como hash table com uma linked list, ordena os elementos baseada na order em que eles foram inseridos no conjunto. Collection<Type> noDups = new HashSet<Type>(c); Collection<Type> noDups = new LinkedHashSet<Type>(c);
282.
Operações em massacom Sets Operações em massa são muito interessantes em Sets, pois elas são executadas de forma algébriga. s1.containsAll(s2) — retorna true se s2 é um subconjunto de s1. (s2 é um subconjunto de s1 se s1 contém todos os elementos que estão em s2.) s1.addAll(s2) — transforma s1 na união de s1 e s2. (A união de dois sets é o set contendo todos os elementos contidos em ambos sets.) s1.retainAll(s2) — transforma s1 na interseção de s1 e s2. (A interseção de dois sets é um set contendo somente os elementos comuns em ambos sets.) s1.removeAll(s2) — transforma s1 na diferença (assimétrica) de s1 e s2. (Por exemplo, a diferença entre s1 menos s2 é o set contendo todos os elementos encontrados em s1 mas não em s2.)
283.
Operações em massacom Sets Para calcular a união, interseção ou a diferença entre sets de forma não destrutiva, então devemos copiar o set antes de invocarmos as operações em massa : Set<Type> union = new HashSet<Type>(s1); union.addAll(s2); Set<Type> intersection = new HashSet<Type>(s1); intersection.retainAll(s2); Set<Type> difference = new HashSet<Type>(s1); difference.removeAll(s2);
284.
A interface Listpublic interface List<E> extends Collection<E> { // Positional access E get(int index); E set(int index, E element); //optional boolean add(E element); //optional void add(int index, E element); //optional E remove(int index); //optional boolean addAll(int index, Collection<? extends E> c); //optional // Search int indexOf(Object o); int lastIndexOf(Object o); // Iteration ListIterator<E> listIterator(); ListIterator<E> listIterator(int index); // Range-view List<E> subList(int from, int to); }
285.
Implementações de ListO Java possui duas implementações para List. ArrayList – Geralmente é a implementação de melhor performance. LinkedList – Oferece melhor performance sob certas circunstâncias. Vector “intruso” – Foi refatorado para implementar List.
286.
Operações sobre Listlist1.addAll(list2); //Forma não destrutiva List<Type> list3 = new ArrayList<Type>(list1); list3.addAll(list2); //acesso posicional e pesquisa public static <E> void swap(List<E> a, int i, int j) { E tmp = a.get(i); a.set(i, a.get(j)); a.set(j, tmp); }
287.
Iterators É retornadopelas operações de iterators da lista. public interface ListIterator<E> extends Iterator<E> { boolean hasNext(); E next(); boolean hasPrevious(); E previous(); int nextIndex(); int previousIndex(); void remove(); //optional void set(E e); //optional void add(E e); //optional } for (ListIterator<Type> it = list.listIterator(list.size()); it.hasPrevious(); ) { Type t = it.previous(); ... }
288.
Queue public interfaceQueue<E> extends Collection<E> { E element(); boolean offer(E e); E peek(); E poll(); E remove(); } static <E> List<E> heapSort(Collection<E> c) { Queue<E> queue = new PriorityQueue<E>(c); List<E> result = new ArrayList<E>(); while (!queue.isEmpty()) result.add(queue.remove()); return result; }
289.
A interface Mappublic interface Map<K,V> { // Basic operations V put(K key, V value); V get(Object key); V remove(Object key); boolean containsKey(Object key); boolean containsValue(Object value); int size(); boolean isEmpty(); // Bulk operations void putAll(Map<? extends K, ? extends V> m); void clear();
290.
A interface Map// Collection Views public Set<K> keySet(); public Collection<V> values(); public Set<Map.Entry<K,V>> entrySet(); // Interface for entrySet elements public interface Entry { K getKey(); V getValue(); V setValue(V value); } } Existem três implementações para a interface Map : HashMap, TreeMap e LinkedHashMap. Que por sua vez são análogas as implementações de Set.
291.
Operações com Mapimport java.util.*; public class Freq { public static void main(String[] args) { HashMap<String, Integer> m = new HashMap<String, Integer>(); // Initialize frequency table from command line for (String a : args) { Integer freq = m.get(a); m.put(a, (freq == null) ? 1 : freq + 1); } System.out.println(m.size() + " distinct words:"); System.out.println(m); } } for (Map.Entry<KeyType, ValType> e : m.entrySet()) System.out.println(e.getKey() + ": " + e.getValue());
Introdução Generics éa alteração mais significante da linguagem Java desde a sua versão 1.0. A adição das generics no java 5.0 foi o resultado de uma especificação ( JSR 14 ), que foi feita em 1999. Generics são muito úteis porque elas nos permitem escrever código que é seguro e fácil de ler, ao invés de código que trabalha com Objects e usa vários casts. As generics são muito úteis no trabalho com collections, tal como o ArrayList.
294.
Introdução Generics sãomuito parecidas com as famosas templates do C++. Programação com generics significa escrever código que pode ser reutilizado por objetos de diferente tipos.
295.
Usando coleções comcast List myIntList = new LinkedList(); // 1 myIntList.add(new Integer(0)); // 2 Integer x = (Integer) myIntList.iterator().next(); // 3 Famoso código “saco de gatos”
296.
Com Generics Umainterface ou classe pode ser declarada para receber um ou mais parâmetros, que são escritos entre os sinais de menor e maior < e >. List <Integer> myIntList = new LinkedList<Integer>(); // 1' myIntList.add(new Integer(0)); // 2' Integer x = myIntList.iterator().next(); // 3'
297.
Especificação de genericsDefinição da interface List : public interface List <E>{ void add(E x); Iterator<E> iterator(); } public interface Iterator<E>{ E next(); boolean hasNext(); }
298.
Programando com genericsÉ muito fácil utilizarmos uma classe genérica como ArrayList. E a maioria de nós programadores mortais iremos simplesmente digitar ArrayList<String>, pois esta declaração já faz parte da linguagem, e é tão natural quanto se estivessemos declarando um array de strings : String[]. Infelizmente não é tão fácil implementar uma classe genérica, pois os programadores que utilizarão este código podem querer plugar todos os tipos de classes como parâmetro de tipo. E os mesmos esperam que tudo funcione sem restrição ou mensagem de erro.
299.
Wrappers Todo tipoem Java é um tipo referência ou primitivo. Um tipo referência é qualquer classe, instância ou array. Todos os tipos referência são subclasses de Object. Existem 8 tipos de primitivos, e cada um deles possui uma classe ( Wrapper ) correspondente.
300.
Wrappers Primitivo Referênciabyte Byte short Short int Integer long Long float Float double Double boolean Boolean char Character
301.
Boxing e UnboxingA conversão de primitivo para refência é chamado de boxing, e a conversão de referência para primitivo é chamado de unboxing. O Java com generics insere mecanismos de boxing e unboxing quando necessário, deixando o programador livre de criar um wrapper ou convertê-lo para um primitivo. List<Integer> list = new ArrayList<Integer>(); list.add(1); //Boxing int n = list.get(0); //Unboxing //É o mesmo que : List<Integer> list = new ArrayList<Integer>(); list.add(new Integer(1)); int n = list.get(0);
302.
Definição de classegenérica public class Pair<T> { public Pair() { first = null; second = null; } public Pair(T first, T second) { this.first = first; this.second = second; } public T getFirst() { return first; } public T getSecond() { return second; } public void setFirst(T newValue) { first = newValue; } public void setSecond(T newValue) { second = newValue; } private T first; private T second; }
303.
Definição de classegenérica Temos em nossa classe “Pair” uma variável de tipo T, que está entre < > depois do nome da classe. Vale a pena lembrar que uma classe genérica pode ter mais de um tipo de variável. Poderíamos ter definido a classe Pair usando dois parâmetros : public class Pair<T, U> { . . . }
304.
Padrões Os “typevariables” são utilizados dentro da definição da classe para especificar o retorno do método, tipos de campos e variáveis locais : private T first; É uma prática comum usar letras em caixa alta para tipos, e mantê-los curtos. As bibliotecas do Java usam a variável E para tipo de elemento de coleção, K e V para chave e valor ( key/value ) de um mapa/tabela, e T ( e também U e S, se necessário), para qualquer outro tipo.
305.
Instanciando tipos genéricosPara tal tarefa necessitamos somente substituir as variáveis de tipo pelo tipo desejado : Pair<String>
306.
Método genérico evarargs Public static <T> void addAll(list<T>, T... arr) { For (T tipo : arr ) { list.add(tipo); } }
307.
Testando a classegenérica Pair public class PairTeste { public static void main(String[] args) { Pair<String> p = new Pair<String>(); p.setFirst("a"); p.setSecond("b"); } }
308.
foreach Existe umaforma mais rápida e inteligente de iterar em arrays e coleções : double[] ar = {1.2, 3.0, 0.8}; int sum = 0; for (double d : ar) { sum += d; }
309.
foreach List<String> names= new ArrayList<String>(); names.add("a"); names.add("b"); names.add("c"); for (String name: names) { System.out.println(name.charAt(0)); }