Escolar Documentos
Profissional Documentos
Cultura Documentos
Parte II
Java Programmer
Parte II
COD.: 1842_0
Java Programmer
Parte II
Créditos
Todos os direitos autorais reservados. Este manual não pode ser copiado, fotocopiado, reproduzido,
traduzido ou convertido em qualquer forma eletrônica, ou legível por qualquer meio, em parte ou
no todo, sem a aprovação prévia, por escrito, da Monte Everest Participações e Empreendimentos
Ltda., estando o contrafator sujeito a responder por crime de Violação de Direito Autoral, conforme
o art.184 do Código Penal Brasileiro, além de responder por Perdas e Danos. Todos os logotipos
e marcas utilizados neste material pertencem às suas respectivas empresas.
"As marcas registradas e os nomes comerciais citados nesta obra, mesmo que não sejam assim identificados, pertencem
aos seus respectivos proprietários nos termos das leis, convenções e diretrizes nacionais e internacionais."
Java Programmer
Parte II
Coordenação Geral
Marcia M. Rosa
Coordenação Editorial
Henrique Thomaz Bruscagin
Autoria
Braulio Consani Moura
Revisão Ortográfica e
Gramatical
Marcos Cesar dos Santos Silva
Diagramação
Paloma da Silva Teixeira
Edição nº 1 | 1842_0
Março/ 2018
Este material constitui uma nova obra e é uma derivação da seguinte obra original, produzida por TechnoEdition
Editora Ltda., em Set/2014: Java Programmer.
4
Sumário
5
Java Programmer - Parte II
Capítulo 14 - Programação funcional ................................................................................. 55
14.1. Introdução ............................................................................................56
14.1.1. Vantagens da programação funcional.................................................... 56
14.1.2. Um primeiro exemplo ...........................................................................56
14.2. Interface funcional ................................................................................59
14.2.1. A anotação @FunctionalInterface ........................................................... 59
14.2.2. Exemplos de interface funcional............................................................ 60
14.3. Expressões lambda ...............................................................................60
14.3.1. Forma geral ..........................................................................................61
14.3.2. Expressões com parâmetros ................................................................. 61
14.3.3. Expressões sem parâmetros.................................................................. 62
14.3.4. Expressões com um único parâmetro .................................................... 62
14.3.5. Corpo da expressão lambda .................................................................. 63
14.3.6. Expressões com valor de retorno .......................................................... 64
14.4. Referenciando métodos ........................................................................ 65
14.5. O pacote java.util.function .................................................................... 68
Pontos principais ................................................................................................ 69
Teste seus conhecimentos...................................................................................................... 71
Mãos Obra! ..................................................................................................................................... 73
6
Sumário
7
Java Programmer - Parte II
8
11 Tratamento de
exceções
à Bloco try/catch;
à throws;
à finally;
à Exceções e a pilha de métodos em Java;
à Hierarquia de exceções;
à Principais exceções;
à Exceções personalizadas.
Java Programmer - Parte II
11.1. Introdução
Normalmente, os aplicativos que desenvolvemos possuem diversas tarefas a
serem executadas. É possível que, em algum momento, uma delas gere um
erro ou exceção, isto é, uma ocorrência que faça com que o fluxo normal do
programa seja alterado. Isso pode ocorrer por diversos motivos, como uma
falha de hardware, por exemplo. Um erro ou exceção pode ser simples ou
complexo: em alguns casos, a execução do programa continua, em outros, ela
pode ser interrompida.
try {
bloco de código
}
blocos catch e finally. . .
Você pode fechar seu código dentro de um bloco try de duas maneiras:
10
Tratamento de exceções 11
• Colocando o código inteiro dentro de um único bloco try, gerando
diversos manipuladores associados a ele. Veja um exemplo:
try {
}catch(tipo_de_exceção identificador){
}catch(tipo_de_exceção identificador){
11
Java Programmer - Parte II
12
Tratamento de exceções 11
11.3. throws
Para indicar que um método pode gerar uma exceção, utilizamos o comando
throws na sua declaração. Isso é necessário, por exemplo, em uma operação
com arquivos. Considere que o programa espera um nome de arquivo qualquer
para abri-lo e apresentar o conteúdo na tela. Se o usuário informar o nome do
arquivo errado, ou mesmo se não digitá-lo, poderá ser gerada uma interrupção
do programa.
11.4. finally
Um bloco finally (e as instruções contidas nele) é sempre executado após a
finalização de um bloco try, mesmo quando ocorre uma exceção inesperada.
13
Java Programmer - Parte II
14
Tratamento de exceções 11
Veja, a seguir, a pilha de chamada de métodos de Java:
A exceção pode ser lançada para outros métodos da pilha, mas também podemos
lançá-la fora do método main(), no final da pilha. Neste caso, a JVM é interrompida
e o rastreamento da pilha é apresentado na saída.
15
Java Programmer - Parte II
16
Tratamento de exceções 11
11.7. Principais exceções
Várias exceções verificadas e não verificadas são lançadas pelos métodos
existentes nas bibliotecas de Java e, conforme já mencionado, existem centenas
de exceções nativas do Java. No entanto, algumas destas exceções destacam-
se por serem de uso comum.
11.7.1. Throwable
Hierarquicamente, esta é a classe base de todas as exceções utilizadas pelo
Java. Nesta classe, encontramos as subclasses Error e Exception, que são
utilizadas de maneira convencional para indicar que situações incomuns
ocorreram. Como você viu, em uma cláusula catch, um dos argumentos pode
ser Throwable ou uma de suas subclasses.
17
Java Programmer - Parte II
A JVM lança somente objetos que são instâncias da própria classe Throwable
ou de suas subclasses. Quando uma situação incomum ocorre, as instâncias
são criadas para fornecerem informações importantes.
18
Tratamento de exceções 11
11.7.1.1. Exceções encadeadas
Muitas vezes, uma exceção pode causar outra exceção, ou seja, um programa
pode lançar uma segunda exceção como resposta à primeira. Para saber
quando isso ocorre, você pode usar o recurso de encadeamento de exceções.
Veja um exemplo:
Algumas vezes, a classe que lança um objeto Throwable está inserida em uma
abstração de camadas baixas e uma operação em um nível mais superior falha
por causa de um erro na camada inferior. Usando uma exceção que contém
um cause, você possibilita à camada superior enviar detalhes da falha ao seu
chamador, evitando a propagação de um erro da camada inferior e mantendo
flexibilidade para alterar a implementação da camada superior sem alterar sua
API e, particularmente, as exceções lançadas pelos seus métodos.
19
Java Programmer - Parte II
11.7.2. Error
Muitos erros que ocorrem durante a execução de um programa são situações
bastante incomuns e, por isso, são considerados graves. Para indicar que esses
erros ocorreram e que não devem ser pegos por uma aplicação adequada,
existe uma subclasse de Throwable: a classe Error.
11.7.3. Exception
A classe Exception e suas subclasses têm como função indicar determinadas
condições que uma aplicação pode capturar em um bloco catch. Funcionam
como uma extensão da classe Throwable.
20
Tratamento de exceções 11
11.7.4. NullPointerException
Trata-se de uma exceção não verificada pertencente ao pacote java.lang.
11.7.5. NumberFormatException
É uma exceção não verificada também pertencente ao pacote java.lang.
21
Java Programmer - Parte II
11.7.6. ArrayIndexOutOfBoundsException
Essa é outra exceção não verificada, também pertencente ao pacote java.lang.
11.7.7. ArithmeticException
Trata-se de uma exceção não verificada, também pertencente ao pacote java.
lang.
22
Tratamento de exceções 11
11.7.8. ClassCastException
Outra exceção não verificada pertencente ao pacote java.lang.
11.7.9. IOException
Já esta é uma exceção verificada pertencente ao pacote java.io.
23
Java Programmer - Parte II
Veja um exemplo:
24
Tratamento de exceções 11
Ao criar uma exceção própria, você estende a classe Exception para criar uma
nova classe dela. Veja no exemplo a seguir como fazer isso:
25
Java Programmer - Parte II
26
Tratamento de exceções 11
No método setNota, observando a linha if(nota < 0 || nota > 10), se esta
condição for verdadeira, é gerada uma nova exceção (NotaInvalidaException
e = new NotaInvalidaException()). Na classe CadastroNotas, a seguir,
trataremos esta exceção:
27
Java Programmer - Parte II
Pontos principais
Atente para os tópicos a seguir. Eles devem ser estudados com muita
atenção, pois representam os pontos mais importantes do capítulo.
• Quando precisa lançar uma exceção, você tem duas opções: uma é usar
uma exceção já criada, seja nativa da própria linguagem Java ou criada
por terceiros; a outra é criar você mesmo sua exceção. Isso pode ser útil
em muitos casos. Uma exceção personalizada sempre é uma extensão da
classe Exception.
28
11 Tratamento de
exceções
Teste seus conhecimentos
Java Programmer - Parte II
1. Qual cláusula utilizamos para indicar que um método pode gerar uma
exceção?
☐ a) try
☐ b) catch
☐ c) throws
☐ d) finally
☐ e) Nenhuma das alternativas anteriores está correta.
☐ a) try
☐ b) catch
☐ c) throws
☐ d) catches
☐ e) throw
30
11 Tratamento de
exceções
Mãos à obra!
Java Programmer - Parte II
Laboratório 1
A – Verificando valores numéricos
2. Dentro do método main, solicite que o usuário digite uma frase qualquer,
utilizando o método nextLine() da classe Scanner;
32
12 As bibliotecas
Java e o Javadoc
à Conceito de API;
à Javadoc e a documentação oficial Java;
à Criação de uma documentação Javadoc.
Java Programmer - Parte II
34
As bibliotecas Java e o Javadoc 12
Uma novidade que surgiu a partir do Java 9 foi a possibilidade de realizar uma
busca pela documentação através do campo SEARCH, o que não existia em
versões anteriores.
35
Java Programmer - Parte II
/**
Comentário Javadoc de uma classe
Aqui se encontra como a classe funciona
*/
É importante enfatizar que qualquer outro lugar além dos descritos no exemplo
anterior (onde se coloca o comentário Javadoc) será ignorado pelo gerador.
Além disso, tags podem ser utilizadas para documentar alguns aspectos e
elementos para que tenham posicionamento e formatação especiais, como:
36
As bibliotecas Java e o Javadoc 12
Pontos principais
Atente para os tópicos a seguir. Eles devem ser estudados com muita
atenção, pois representam os pontos mais importantes do capítulo.
37
12 As bibliotecas
Java e o Javadoc
Teste seus conhecimentos
Java Programmer - Parte II
☐ a) // conteúdo da documentação
☐ b) /* conteúdo da documentação */
☐ c) /** conteúdo da documentação */
☐ d) /* conteúdo da documentação **/
☐ e) /// conteúdo da documentação ///
☐ a) HTML
☐ b) PDF
☐ c) .DOC
☐ d) XML
☐ e) .TXT
40
13 Testes unitários
com Java
42
Testes unitários com Java 13
43
Java Programmer - Parte II
44
Testes unitários com Java 13
Considere a classe utilitária adiante contendo apenas um método:
return numero;
}
45
Java Programmer - Parte II
46
Testes unitários com Java 13
O desenvolvimento de casos de teste utilizando o JUnit é realizado através de
annotations e assertions. Na sequência, serão apresentados os principais,
acompanhados de uma explicação sucinta a respeito.
Antes e depois:
13.3.1.2. Assertions
Depois que a instância foi preparada e a funcionalidade executada, assertions
garantem que as condições desejadas foram atingidas, caso contrário, o teste
falha.
47
Java Programmer - Parte II
48
Testes unitários com Java 13
Após a execução de cada caso de teste definido, o framework apresenta um
relatório de execução. A partir do resultado, verifica-se a necessidade de
corrigir o algoritmo testado ou aferir se a unidade testada está correta.
return numero;
}
49
Java Programmer - Parte II
13.4. Conclusão
Teste unitário é um poderoso recurso disponível ao desenvolvedor para testar
código, proporcionando meios para a melhoria da qualidade e da confiabilidade
do software produzido.
Neste capítulo, foi apresentada uma visão geral do JUnit, como configurá-lo
na IDE e como implementar um teste unitário simples. Para aprofundar-se
em outros conceitos relacionados, aplique testes unitários em contextos e
ambientes mais complexos e consulte a documentação oficial da ferramenta
(versão 5 ou superior): http://junit.org/junit5/docs/current/user-guide/.
50
Testes unitários com Java 13
Pontos principais
Atente para os tópicos a seguir. Eles devem ser estudados com muita
atenção, pois representam os pontos mais importantes do capítulo.
51
13 Testes unitários
com Java
Teste seus conhecimentos
Java Programmer - Parte II
54
14 Programação
funcional
à Interface funcional;
à Expressões lambda;
à Referenciando métodos;
à O pacote java.util.function.
Java Programmer - Parte II
14.1. Introdução
Neste capítulo, exploraremos um novo paradigma de programação já utilizado
por algumas das linguagens da atualidade e que, a partir da versão 8, também
pode ser utilizado pelo Java. Trata-se da programação funcional.
56
Programação funcional 14
Um exemplo de implementação para esta interface pode ser visto na classe
Soma:
Seguindo este conceito, para cada operação aritmética que possa ser utilizada
pela aplicação, devemos criar uma nova classe implementadora conforme a
necessidade (soma, divisão, potência etc.).
Repare, no última código (classe Executando), que o objeto operacao não tem
atributos (objeto sem estado) e possui um único método, chamado execute().
É esta forma de desenvolvimento que chamamos de programação funcional.
Neste formato de programação, encapsulamos as rotinas de execução (funções)
em simples objetos que podem ser chamados posteriormente a qualquer
momento.
57
Java Programmer - Parte II
58
Programação funcional 14
14.2. Interface funcional
Chamamos de interface funcional aquela que possui somente um método
abstrato (sem corpo), exigindo a implementação de apenas um método pela
classe responsável.
O método abstrato, por sua vez, pode possuir qualquer tipo de retorno,
podendo até não haver retorno (void) e também possuir quaisquer quantidades
e tipos de argumentos (parâmetros de entrada). O uso de genéricos também
é permitido.
59
Java Programmer - Parte II
Uma expressão lambda sempre deve ser atribuída a uma variável de tipo
funcional (interface funcional), como no exemplo anterior, ou passada como
argumento na chamada de um método que aceita um tipo funcional, como no
exemplo a seguir:
60
Programação funcional 14
14.3.1. Forma geral
De forma geral, uma expressão lambda possui duas seções separadas pelo
símbolo “->” (menos-maior):
• Interface
• Expressão
61
Java Programmer - Parte II
• Interface
• Expressão
• Interface
62
Programação funcional 14
• Expressão
63
Java Programmer - Parte II
64
Programação funcional 14
Mas, se a expressão lambda for pequena, composta por uma única instrução,
podemos simplesmente indicar a instrução de retorno após o símbolo “->”
(menos-maior), sem chaves e sem a cláusula return:
Suponhamos que em sua aplicação exista uma classe que possui um método
pronto que realiza exatamente aquilo que precisamos implementar em nossa
função:
65
Java Programmer - Parte II
66
Programação funcional 14
Referenciando métodos
67
Java Programmer - Parte II
A fim de suportar o uso de ELs, o Java 8 traz uma vasta quantidade de interfaces
funcionais predefinidas que facilitam a implementação destas rotinas de
processamento. Tais interfaces foram disponibilizadas em um novo package
denominado java.util.funcion.
68
Programação funcional 14
Pontos principais
Atente para os tópicos a seguir. Eles devem ser estudados com muita
atenção, pois representam os pontos mais importantes do capítulo.
69
14 Programação
funcional
Teste seus conhecimentos
Java Programmer - Parte II
72
14 Programação
funcional
Mãos à obra!
Java Programmer - Parte II
Laboratório 1
Neste laboratório, vamos criar um array contendo diversos salários (array de
valores double) e utilizar a classe auxiliar DoubleArrayUtils para manipular
os salários através de expressões lambda.
Salários
1.350,00
4.320,15
8.235,25
2.500,55
1.830,00
850,26
3.614,29
12.500,00
74
Programação funcional 14
B – Obtendo os salários mais altos
75
15 Coleções e
mapas
78
Coleções e mapas 15
15.2. Principais operações de coleções
Além das operações básicas, como adição e remoção de objetos na coleção,
outras operações são realizadas:
• Collection;
• List;
• Set;
• Map;
• Sorted Set;
• Sorted Map.
79
Java Programmer - Parte II
• Mapa (Map)
• Conjunto (Set)
• Lista (List)
80
Coleções e mapas 15
Em uma implementação, a classificação corresponde a um tipo de ordenamento
específico. Uma classe de implementação pode receber uma das seguintes
características:
• Indexada e classificada;
15.4. Generics
Generics (ou genéricos) são um recurso que permite tornar tipos em
parâmetros para a definição de classes, métodos e interfaces. Isso permite
que você reutilize o mesmo código em diferentes entradas. Código construído
com Generics possui as seguintes vantagens em relação a estruturas de código
que não os utilizem:
• A eliminação de casts;
81
Java Programmer - Parte II
82
Coleções e mapas 15
Para criar uma instância da classe genérica, você deve usar a palavra-chave
new e declarar o tipo (fechado com sinais de maior e menor, <>) entre o nome
da classe e os parênteses, da seguinte maneira:
83
Java Programmer - Parte II
Com isso, um índice inteiro é utilizado para acessar os elementos. Estes podem
receber valor null e podem ser duplicados, o que é permitido pelas classes que
implementam a interface List.
• ArrayList
Esta lista foi implementada na versão 1.4 de Java e diz respeito a um array
que pode aumentar de tamanho dinamicamente. Ele não é classificado, mas é
indexado.
• LinkedList
Para realizar inserções, bem como exclusões com rapidez, utilize esse tipo de
lista. Contudo, é preciso ressaltar que o processo de iteração de seus elementos
pode não ser tão rápido se comparado ao ArrayList.
• Vector
84
Coleções e mapas 15
Observe o exemplo a seguir, que ilustra alguns métodos presentes em coleções
que implementam a interface List:
85
Java Programmer - Parte II
• HashSet
86
Coleções e mapas 15
• LinkedHashSet
• TreeSet
• boolean hasNext()
Este método retorna true se a iteração tiver mais elementos e false caso
contrário.
• E next()
87
Java Programmer - Parte II
• void remove()
O exemplo adiante utiliza a classe TreeSet que garante que a ordem dos
elementos seja ascendente, tomando por base sua ordem natural:
88
Coleções e mapas 15
15.6.2. Equivalência de objetos (equals)
Para comparar o conteúdo de dois objetos, ou seja, para comparar se dois
objetos são significativamente equivalentes, utilize o método equals(). Use
o operador == apenas para verificar se um mesmo objeto é referenciado por
duas variáveis distintas, ou seja, se apontam para um mesmo endereço de
memória.
O método equals() retorna true se os argumentos forem iguais entre si, caso
contrário, retorna false. A sua sintaxe é a seguinte:
89
Java Programmer - Parte II
90
Coleções e mapas 15
O método equals() recebe também como argumento o valor null. Considerando
a variável a, por exemplo, a operação a.equals(null) retorna false para qualquer
valor de a que seja diferente de null.
15.6.3. Hashing
Ao armazenar um tipo de elemento em um endereço de alguns tipos de
estrutura de dados, você realiza um processo chamado hashing. Esse endereço
da estrutura de dados é gerado a partir de um algoritmo que toma por base o
valor a ser armazenado.
Você deve saber que uma classe pode conter um método de código de hashing
ineficiente (com distribuição ruim dos objetos nos grupos), apesar de retornar
um código hash válido de acordo com o contrato entre equals e hashCode.
91
Java Programmer - Parte II
92
Coleções e mapas 15
15.6.4. Método forEach()
Outra forma de realizar a iteração entre os itens de uma coleção é através do
método forEach().
93
Java Programmer - Parte II
Através deste método, podemos remover de nossa coleção todos os itens que
não satisfaçam a um determinado critério.
94
Coleções e mapas 15
15.6.6. Interface Comparable
O método de comparação int compareTo(Object o) é definido pela interface
Comparable. O resultado deste método pode ser um número negativo, positivo
ou zero.
Veja:
• Zero indica que o objeto e o objeto passado como parâmetro são iguais.
95
Java Programmer - Parte II
colecao.stream()
.algumMetodo(lambda1)
.outroMetodo(lambda2)
.maisUmMetodo(lambda3);
96
Coleções e mapas 15
97
Java Programmer - Parte II
98
Coleções e mapas 15
Caso desejemos uma ordenação diferente da natural ou mesmo se os elementos
não possuírem um critério natural, podemos chamar este método passando
uma expressão lambda de ordenação:
Veja o resultado:
Neste exemplo, na linha 17, criamos uma expressão lambda que implementa
o critério de comparação entre dois funcionários (representados por f1 e f2) e
realizamos a comparação pelo nome (método getNome()).
99
Java Programmer - Parte II
Confira o resultado:
100
Coleções e mapas 15
15.7.2. Método filter()
Obtém um stream contendo alguns dos elementos do stream original.
101
Java Programmer - Parte II
Confira o resultado:
102
Coleções e mapas 15
15.7.4. Método skip()
Este método desconsidera os primeiros n itens do stream original. Tem o efeito
oposto ao do método limit().
Veja o resultado:
103
Java Programmer - Parte II
104
Coleções e mapas 15
Veja um outro exemplo, com a mesma lista de funcionários. Mas, desta vez,
utilizamos o stream de Funcionario para obter um stream de String, contendo
simplesmente os seus cargos:
105
Java Programmer - Parte II
106
Coleções e mapas 15
15.7.7. Método count()
Este método retorna um número inteiro longo (long), informando a quantidade
de itens que está sendo considerada no stream.
Veja o resultado:
107
Java Programmer - Parte II
Veja um exemplo:
Para obter o possível valor contido nesta entidade, utilize o método get().
108
Coleções e mapas 15
15.8. Interface Map
Esta interface define uma estrutura de dados que mapeia pares chave-valor.
Um mapa não pode conter chaves duplicadas, pois cada chave deve mapear,
no máximo, um valor.
Além disso, o conteúdo de um mapa pode ser visualizado como uma coleção
de chaves, uma coleção de valores ou um conjunto de mapeamentos chave-
valor. A ordem de um mapa é a ordem em que os iteradores retornam seus
elementos na visualização de coleção do mapa.
109
Java Programmer - Parte II
Para que seja possível retornar o valor associado à chave passada como
parâmetro, utilize a sintaxe a seguir:
V get(Object key)
V remove(Object key)
int size()
110
Coleções e mapas 15
Observe o exemplo a seguir:
111
Java Programmer - Parte II
• Algoritmos: São métodos com funções úteis nas coleções, como ordenar
uma lista;
112
Coleções e mapas 15
Pontos principais
Atente para os tópicos a seguir. Eles devem ser estudados com muita
atenção, pois representam os pontos mais importantes do capítulo.
• Coleções do tipo Map substituíram a classe Dictionary, que era uma classe
totalmente abstrata. Você deve saber que esta coleção mapeia pares
chave-valor. Lembre-se que um mapa não pode conter chaves duplicadas,
pois cada chave pode mapear, no máximo, um valor;
113
15 Coleções e
mapas
Teste seus conhecimentos
Java Programmer - Parte II
☐ a) Adição de objetos.
☐ b) Verificação de existência de objeto ou grupo de objetos.
☐ c) Iteração pelo conjunto.
☐ d) Alteração de endereço de objetos.
☐ e) Recuperação de um objeto no conjunto.
☐ a) Stack
☐ b) Set
☐ c) Map
☐ d) List
☐ e) Collection
116
Coleções e mapas 15
117
15 Coleções e
mapas
Mãos à obra!
Java Programmer - Parte II
Laboratório 1
A – Utilizando um objeto HashMap parametrizado para guardar notas de
alunos
2. Dentro dele, crie uma classe com o nome Cap15_Lab1 e insira a estrutura
básica de um programa Java;
120
Coleções e mapas 15
Laboratório 2
A – Criando a estrutura do programa e um tipo construído denominado
Estudante
2. Dentro dele, crie uma classe com o nome Cap15_Lab2 e insira a estrutura
básica de um programa Java;
• nome: String;
• notaMatematica: double;
• notaPortugues: double;
• media: double.
Nota de Nota de
Nome
Matemática Português
Joana 8,5 8,5
Antônio 6,0 9,0
Mariana 7,5 9,0
Ricardo 7,0 6,0
Gustavo 9,5 10,0
3. Utilize o método forEach() para aplicar uma expressão lambda que, para
cada item, calcula a média das notas de matemática e português e assinala
com o método setMedia();
121
15 Coleções e
mapas
Projeto Prático – Fase 3
Java Programmer - Parte II
• equals;
• hashCode;
Atividades
1. Atualizar todos os métodos que possuem coleções para uma estrutura de
dados apropriada (List com ArrayList):
124
16 Arquivos – I/O
e NIO
à I/O;
à try-with-resources;
à Leitura de arquivos de texto;
à NIO – Arquivos e diretórios.
Java Programmer - Parte II
16.1. I/O
A linguagem Java trabalha com um fluxo controlável de entrada e saída de
informações, chamado stream, que também é definido como fluxo Input/
Output (entrada/saída), ou simplesmente fluxo I/O. Além disso, o stream é
manipulado por objetos e classes da linguagem Java. Nos tópicos a seguir,
serão apresentadas as classes que representam os streams de saída e entrada,
assim como seus respectivos métodos. Você também conhecerá as classes
usadas para a leitura de arquivos binários e de texto e o uso de paths.
126
Arquivos – I/O e NIO 16
Depois de compilado e executado o código anterior, um arquivo do tipo .txt
será gerado com o nome GerarArquivo, como mostra a imagem a seguir:
Uma condição para que as aplicações sejam capazes de definir uma subclasse
de OutputStream é oferecer pelo menos um método de gravação de byte de
saída.
127
Java Programmer - Parte II
16.1.1.1. Métodos
Neste tópico, serão apresentados cada um dos métodos da classe
OutputStream:
• write (int b)
Tendo como parâmetro o argumento b (o byte), o método write (int b), cuja
implementação se faz necessária nas subclasses de OutputStream, grava o
byte especificado para o stream de saída.
• write(byte[] b)
Este método possui os parâmetros b (dados), off (offset de início nos dados) e
len (quantidade de bytes a ser gravada). Além disso, a partir do array de byte
especificado, grava bytes len, com início no offset off do stream de saída.
• flush()
• close()
128
Arquivos – I/O e NIO 16
16.1.2. Classe InputStream
As classes que representam um stream de entrada de bytes têm como
superclasse a InputStream, cuja sintaxe é a seguinte:
Se sua intenção é fazer com que uma aplicação defina uma subclasse de
InputStream, é necessária a utilização de um método que retorne o próximo
byte de entrada.
16.1.2.1. Métodos
Veja, a seguir, os métodos da classe InputStream:
• read()
O método read(), cuja implementação deve ser oferecida por uma subclasse,
faz a leitura do próximo byte de dados que chega do stream de entrada, sendo
que o byte de valor retornado apresentará um valor int entre 0 e 255.
• read(byte[] b)
129
Java Programmer - Parte II
• skip(long n)
O método skip(n) tem como função pular e ignorar n bytes de dados do stream
de entrada. Ele retorna o número atual de bytes pulados.
• available()
Este método é responsável por retornar o número de bytes que podem ser
lidos ou pulados a partir desse stream.
• close()
Com o stream fechado, os recursos de sistema que estavam sendo usados por
ele são disponibilizados para outras tarefas.
• mark(int readlimit)
• reset()
• markSupported()
130
Arquivos – I/O e NIO 16
16.1.3. Leitura de arquivos binários
Para fazer a leitura de arquivos binários, é recomendável o emprego da classe
FileInputStream, que é comumente usada para ler streams de bytes não
processados.
Você pode utilizar ponteiros para indicar locais relativos ao diretório inicial, no
sistema. Este procedimento é possível, pois não há como modificar o diretório
atual.
131
Java Programmer - Parte II
16.2. try-with-resources
O bloco de instrução try-with-resources pode ser considerado como um
simples try que declara um ou mais recursos com o propósito de fechá-lo(s)
automaticamente com o término do bloco.
Uma lista de classes que implementam estas interfaces pode ser verificada nos
docs oficiais da linguagem Java (dentre elas, as apresentadas neste capítulo).
132
Arquivos – I/O e NIO 16
16.2.1. Exceções suprimidas
A preocupação com as denominadas exceções suprimidas (suppressed
exceptions) surge com o advento do bloco try-with-resources para os efeitos
gerados em objetos que implementam a interface AutoCloseable.
• Uma exceção ocorre no bloco try e, dessa forma, o controle passa para
um bloco catch devido e;
133
Java Programmer - Parte II
134
Arquivos – I/O e NIO 16
• Charsets e seus decodificadores e codificadores associados:
Responsáveis pela tradução entre bytes e caracteres Unicode;
Método Descrição
Retorna uma String contendo o caminho completo
toAbsolutePath()
do Path.
Retorna uma String contendo o nome do arquivo
getFileName()
ou diretório especificado pelo Path.
Retorna o Path referente ao diretório que contém
getParent()
este Path.
Cria um novo Path para um arquivo ou subdiretório
resolve(String)
contido no diretório especificado por este Path.
135
Java Programmer - Parte II
136
Arquivos – I/O e NIO 16
Utilizamos a classe Files (pacote java.nio.file) na manipulação de um Path.
Todos os seus métodos são estáticos. Alguns deles são listados na tabela a
seguir:
Método Descrição
Verifica se o Path especificado (arquivo ou
Files.exists(path)
diretório) existe, retornando um boolean.
Verifica se o Path especificado existe e é um
Files.isDirectory(path)
diretório.
Verifica se o Path especificado existe e é um
Files.isRegularFile(path)
arquivo.
Retorna um long contendo o tamanho em bytes
Files.size(path)
do arquivo especificado pelo Path.
Files.createDirectory(path) Cria um diretório referente ao Path especificado.
Cria recursivamente os diretórios referentes ao
Files.createDirectories(path)
Path especificado.
Move o arquivo ou diretório especificado por
Files.move(path1, path2)
um Path.
Copia o arquivo ou diretório especificado por
Files.copy(path1, path2)
um Path.
Files.delete(path) Apaga o arquivo ou diretório especificado.
Cria um arquivo de tamanho zero (arquivo
Files.createFile(path)
vazio), conforme o Path especificado.
Retorna um Stream<Path> apontando para
os arquivos e subdiretórios contidos no Path
Files.list(path)
especificado, a partir do qual pode-se criar uma
expressão lambda para processá-los.
137
Java Programmer - Parte II
Veja um exemplo:
138
Arquivos – I/O e NIO 16
Pontos principais
Atente para os tópicos a seguir. Eles devem ser estudados com muita
atenção, pois representam os pontos mais importantes do capítulo.
139
16 Arquivos – I/O
e NIO
Teste seus conhecimentos
Java Programmer - Parte II
☐ a) write()
☐ b) print()
☐ c) flush()
☐ d) close()
☐ e) Todas as alternativas anteriores são métodos da classe
OutputStream.
142
16 Arquivos – I/O
e NIO
Mãos à obra!
Java Programmer - Parte II
Laboratório 1
A – Escrevendo caracteres em um arquivo externo
3. Crie um método estático com o nome escrever, que não retorne nada e que
receba uma variável do tipo String de nome texto como parâmetro;
1. Crie um método estático com o nome ler, que não retorne nada e que não
receba nenhum parâmetro;
144
Arquivos – I/O e NIO 16
Laboratório 2
A – Copiando arquivos entre diretórios
• O método main().
5. Verifique se o diretório backup existe. Caso não exista, crie-o. Para isso,
utilize os métodos Files.exists() e Files.createDirectory();
8. Compile e execute.
145
16 Arquivos – I/O
e NIO
Projeto Prático – Fase 4
Java Programmer - Parte II
Importação de filmes
Um arquivo importado do Excel (.CSV) contendo vários filmes do repositório
de dados da base do IMDb será utilizado para que seja implementada a
funcionalidade de importação dos filmes do arquivo para a base de dados da
aplicação.
Para isso, a aplicação irá processar o arquivo, gerando os objetos do tipo Filme.
Em seguida, cada filme processado será adicionado a uma lista de filmes que,
ao final do processamento, estará disponível para inserção dos filmes “em
lote” na base de dados da aplicação.
Esta inserção “em lote” será apenas processada na fase de implantação da base
de dados, portanto, a aplicação deve simular a chamada ao DAO que realizará
o mapeamento necessário no futuro.
Atividades
1. Ler o arquivo informado no parâmetro do método do “Controller”:
148
17 Threads
à Programação multithreaded;
à Implementando multithreading;
à Construtores;
à Estados da thread;
à Scheduler;
à Prioridades das threads;
à Sincronização;
à Bloqueios;
à Deadlock;
à Interação entre threads.
Java Programmer - Parte II
17.1. Introdução
Thread é uma classe em Java que permite a execução de diferentes tarefas
simultaneamente. O termo thread diz respeito a linhas que compartilham um
mesmo contexto e cuja execução ocorre de forma concomitante.
• Um início;
• Uma sequência;
• Um ponto de execução;
• Um final.
150
Threads 17
Multithreaded se refere a um programa que permite a execução simultânea e
em paralelo de várias linhas, ou seja, multithreaded significa programação a
partir de diversas linhas de execução. Um programa multithread é composto
por duas ou mais threads, cada qual definindo um caminho de execução.
151
Java Programmer - Parte II
Quanto à criação de threads, esta toma como base o fato de cada thread ser
capaz de executar o método run(), seja este o seu próprio método ou o método
de outros objetos. Sendo assim, a criação de threads pode ser realizada:
152
Threads 17
A implementação da interface Runnable ocorre com mais frequência do que a
extensão da classe Thread. A extensão da classe Thread é um procedimento
menos complexo, contudo, em modelos OO (Orientados a Objetos), este não
é o procedimento mais adequado, tendo em vista ser o objetivo da herança
prover uma versão mais específica da superclasse de caráter genérico.
O método run(), é utilizado para iniciar uma tarefa. Nas situações em que você
deseja executar uma tarefa em segundo plano, ou seja, executar uma tarefa
na própria thread, essa thread será a executora do código. Vale destacar que
o código sempre deve ser escrito em uma thread separada do método run().
17.3.1. java.lang.Thread
Estender a classe java.lang.Thread significa criar uma classe a partir dela, ou
seja, criar uma classe que obtenha a herança de java.lang.Thread. A partir
desta criação, realize o seguinte procedimento:
153
Java Programmer - Parte II
Apenas o método public void run() deve ser sobreposto. Se o método public void
start() é sobreposto, a thread não é criada na Java Virtual Machine nem registrada
no escalonador.
154
Threads 17
Observe o exemplo a seguir:
17.3.2. java.lang.Runnable
Uma thread também pode ser criada por meio da execução do método public
void run() pertencente a algum objeto que esteja fora da árvore de herança de
java.lang.Thread. Porém, tendo em vista que a thread é sempre representada
por uma subclasse de java.lang.Thread, a implementação deve ser realizada
por meio do construtor Thread(Runnable r) da classe Thread. Isto para que
essa thread seja capaz de executar o código do objeto de outra classe.
155
Java Programmer - Parte II
17.4. Construtores
Instanciar uma classe Thread é o primeiro passo para criar uma thread de
execução, embora ainda seja necessário um objeto Thread nas situações
em que o método run() se encontra na classe de implementação da interface
Runnable e nas ocasiões em que esse método se encontra em uma classe
estendida de Thread.
156
Threads 17
A fim de criar uma instância de java.lang.Thread para a qual a tarefa deve ser
passada, utilize o código seguinte:
Você pode utilizar um construtor sem argumentos a fim de criar uma thread.
Ao fazer isso, essa thread iniciará o trabalho chamando seu próprio método
run(). Nas situações em que estender a classe Thread, a intenção é que a
thread chame seu próprio método. Contudo, quando você implementa a
interface Runnable, faz-se necessário alertar essa thread quanto à execução
de seu método.
Você viu, até este momento, como instanciar uma thread, mas não como iniciá-
la. Uma thread não iniciada ainda não é uma thread de execução. Isso significa
que ela está no estado new, ou seja, ela não é considerada como uma thread
ativa.
A fim de verificar se uma determinada thread está ativa, você pode chamar o
método isAlive() na instância da classe Thread. Este método é capaz de definir
se uma thread foi iniciada sem que o seu método run() tenha sido concluído.
Para que a thread seja considerada ativa, a JVM necessita de algum tempo
para configurá-la após a chamada do método start(). Uma vez chamado este
método, a thread será considerada inativa somente após ter sido descartada.
157
Java Programmer - Parte II
Estado da
Descrição
thread
Uma thread encontra-se no estado new quando já há uma instância
de Thread criada, porém, seu método start() ainda não foi chamado.
New
Assim, uma thread neste estado ainda está inativa, ainda não é uma
thread de execução.
Uma thread neste estado está pronta para ser executada, mas ainda
não foi selecionada pelo scheduler como sendo uma thread pronta
para o processamento. Quando está no estado ready to run, a
Ready to thread é considerada ativa. Ela entra neste estado pela primeira vez
run assim que seu método start() é chamado, mas pode entrar neste
estado em outras situações, como no momento em que acaba de ser
processada, ou quando retorna de outros estados, como resume,
blocked e suspended.
Uma thread neste estado está em execução, o que ocorre no momento
em que o scheduler a seleciona, a partir do pool executável, como
sendo um processo cuja execução deve ocorrer prontamente. Vale
destacar que uma thread pode sair do estado running por algumas
Running razões, desde uma decisão do scheduler para que ela saia, até
o fato de a thread estar em um dos estados que serão descritos
posteriormente: resume, blocked e suspended; os quais indicam
que a thread está no estado ready to run, mas não está no estado
running.
A thread está neste estado quando retorna às suas atividades, no
Resume momento em que um determinado evento ocorre, após ter ficado
no estado suspended ou blocked.
A thread está neste estado quando se encontra aguardando por um
Blocked recurso. Porém, ela retornará ao estado ready to run no momento
em que este recurso for disponibilizado.
A thread está no estado suspended quando seu código de execução
a informou para que ficasse inativa durante um certo período de
Suspended
tempo. Nesta situação, a thread retorna ao estado ready to run
assim que expira seu prazo de suspensão.
A thread está neste estado nas situações em que seu método run()
é finalizado, ou seja, nas situações em que a thread está inativa.
Terminated Threads inativas não podem ser reativadas. Sendo assim, caso você
chame o método start() de uma instância de Thread que esteja
inativa, receberá uma exceção de tempo de execução.
158
Threads 17
A classe Thread contém os métodos stop() e suspend(), os quais permitem
que uma thread informe a outra thread a respeito de sua suspensão. Contudo,
esses métodos foram considerados depreciados e, dessa forma, não devem ser
utilizados. Nesse rol de depreciados, também devem ser incluídos os métodos
destroy() e resume().
17.6. Scheduler
O scheduler é o responsável por definir quais threads serão executadas em
um dado momento, além de fazer com que a thread saia do estado ready to
run. Nas situações em que somente uma máquina realiza o processamento, é
possível que apenas uma thread seja executada por vez, sendo que o scheduler
é o responsável por determinar qual thread será processada.
É importante saber que, para ser selecionada pelo scheduler, uma thread deve
estar qualificada, ou seja, deve estar no estado ready to run. Embora haja
uma fila de threads a serem executadas, não é possível assegurar que a ordem
dessa fila será obedecida. A ordem normal seria a seguinte:
• Assim que a execução da thread for concluída, esta passa para o final da
fila;
• Esta thread, então, aguardará até que chegue em primeiro lugar da fila
novamente para que possa ser, mais uma vez, executada.
159
Java Programmer - Parte II
• Deslocamento de threads
É possível que uma thread seja deslocada por outra cuja prioridade é mais
alta. Caso a thread cuja prioridade é mais baixa não ceda o controle, ela é
deslocada por uma de prioridade mais alta independentemente das tarefas
que estiver realizando, uma vez que, teoricamente, uma thread de prioridade
mais elevada pode ser executada no momento necessário. O mecanismo que
permite a execução de thread com prioridade mais alta no momento desejado
é chamado de multitarefa preemptiva.
Além das JVMs que utilizam um scheduler com divisão de tempo, há aquelas
que utilizam um scheduler capaz de permitir que uma thread seja executada até
o momento em que seu método run() seja finalizado. Entretanto, o scheduler
que trabalha com prioridades para as threads ainda é o mais utilizado pelas
Java Virtual Machines. Com este scheduler, é comum que as threads com
prioridade mais elevada sejam executadas em primeiro lugar.
160
Threads 17
A prioridade é como uma garantia de ordem de execução de threads.
Apesar disso, não é possível confiar que, por conta dessas prioridades, o
comportamento de um determinado programa será o mais adequado. Ainda,
você não pode confiar nas prioridades quando projetar um programa com
diversas threads, porque, em última instância, o scheduler da JVM está atrelado
ao tipo de algoritmo executado pelo sistema operacional.
Nesse código, s está referenciando uma thread, a qual terá a mesma prioridade
da thread principal. Isso ocorre porque essa thread está executando o código
que realiza a criação da instância de Segmento.
161
Java Programmer - Parte II
O método yield(), portanto, deve ser utilizado nas situações em que se deseja
executar uma thread que tem prioridade igual à thread que está em execução
no momento.
162
Threads 17
Algumas outras formas do método join() permitem determinar o período de
tempo para que a thread especificada seja finalizada. O nome atribuído a esse
método (join = juntar) deve-se ao fato de que a thread que o chama aguarda
até que a thread especificada junte-se a ela.
163
Java Programmer - Parte II
Em que:
O método sleep() também possui uma outra forma, mas esta apenas é útil nos
ambientes em que a determinação do período de suspensão pode ser realizada
em milissegundos e em nanossegundos. A forma de utilização em questão é:
164
Threads 17
Depois de compilado e executado o código anterior, o resultado será como o
exibido na figura seguir:
17.8. Sincronização
Os recursos compartilhados apenas podem ser utilizados por uma thread de
cada vez, porém, no decorrer da execução de alguns programas, é possível
que haja mais de uma thread necessitando de acesso a esses recursos. Para
resolver essa situação, utilize a sincronização.
Assim que uma thread consegue acessar o recurso desejado, o acesso a ele
é bloqueado às outras threads. Quando isso acontece, dizemos que a thread
entrou no monitor, e qualquer outra thread que tentar entrar nele ficará em
estado suspended até que a thread inicial deixe o monitor. A thread encontrada
no monitor pode entrar novamente nele se desejar.
165
Java Programmer - Parte II
Mais especificamente, temos uma race condition nas situações em que mais
de uma thread acessa o mesmo método de forma concomitante, causando
uma competição por esse método. As consequências de uma race condition
podem ser desastrosas, mas também há momentos em que um programa
funciona de forma adequada apesar desse problema. Isso acontece porque
uma race condition pode ocorrer de forma discreta, bem como não pode
ser prevista, uma vez que o momento em que um chaveamento de contexto
ocorrerá não é garantido.
166
Threads 17
17.8.2. Bloco sincronizado
O processo de sincronização deve ser realizado somente sobre o trecho de
código necessário para a proteção dos dados, uma vez que tal processo exclui
a possibilidade de haver concorrência. Sendo assim, caso um método apresente
um escopo maior do que o necessário para sincronização, você pode reduzir
tal escopo de forma a sincronizar apenas uma parte desse método, ou seja,
apenas um bloqueio, o qual é chamado de bloco sincronizado.
Quanto aos métodos estáticos, estes podem ser sincronizados, porém, essa
sincronização precisa de um único bloqueio para toda a classe. Esse bloqueio
é o da instância de java.lang.Class, a qual representa cada classe carregada
em Java. A sincronização de métodos estáticos é feita da seguinte maneira:
167
Java Programmer - Parte II
synchronized(objeto){
Os blocos não precisam ser colocados entre chaves { } quando for realizada a
sincronização de comandos. Ressaltamos que o código descrito anteriormente
(objeto) refere-se ao objeto a ser sincronizado.
17.9. Bloqueios
Bloqueios e sincronização são dois conceitos relacionados entre si, uma vez que
a sincronização funciona com os bloqueios. Há algumas questões importantes
a respeito de ambos que devem ser levadas em consideração:
• Uma classe não precisa que todos os seus métodos sejam sincronizados.
Sendo assim, pode haver tanto métodos sincronizados quanto métodos
não sincronizados em uma classe;
168
Threads 17
Em suma, quando o bloqueio de um objeto está sendo utilizado por uma thread,
outra thread não poderá utilizar um método sincronizado desse objeto.
Embora o bloqueio de um objeto possa ser acessado por uma thread de cada
vez, cada uma dessas threads pode acessar mais de um objeto por vez. Esses
bloqueios, então, são liberados gradativamente com o desenrolar da pilha.
Dessa forma, é possível que a thread obtenha o objeto e, ainda, utilize-o para
chamar um método sincronizado presente nele, pois a JVM sabe que a thread
em questão já possui o bloqueio.
• Classe java.lang.Thread;
• Método wait().
• Método join();
• Método notify();
• Método sleep();
• Método yield().
O método notify() pode tanto manter quanto liberar o bloqueio. Ele o libera
quando a thread sai do código sincronizado após o método ter sido chamado.
169
Java Programmer - Parte II
17.10. Deadlock
Um deadlock ocorre nas situações em que duas threads dependem uma da
outra em um par de objetos que estão sincronizados. Em situações como esta,
temos uma ou mais threads cuja execução está paralisada, esperando pelo
acesso a um recurso que já foi alocado por outra thread.
170
Threads 17
No código apresentado, há possibilidade de ocorrer um deadlock, o que é
demonstrado nas linhas 11 e 19. Ele é justificado de acordo com a seguinte
situação: read() foi iniciado por uma thread e write() foi iniciado por uma
outra thread. O risco de impasse existe porque as duas threads são capazes
de ler e gravar de forma independente. Já que a thread de leitura (read)
possui o recurso X, e a thread de gravação (write) possui o recurso Y, ambas
permanecerão paralisadas, aguardando a desistência uma da outra.
Tendo em vista que wait() e notify() são métodos de instância da classe Object,
é possível que haja uma lista de threads aguardando o recebimento de uma
notificação de um objeto. Para que uma thread entre nessa lista, o método
wait() do objeto de destino deve ser executado e, quando isso acontece, é
preciso que o método notify() do objeto de destino seja chamado para que
essa thread possa executar alguma outra instrução. Somente uma thread
poderá continuar sua execução caso haja várias threads esperando em um
mesmo objeto. Caso contrário, nenhuma ação ocorrerá.
171
Java Programmer - Parte II
172
Threads 17
• Na linha 11, é utilizado o método y.wait() para que SegmentoX não
chegue até a linha 16 antes que SegmentoY possa finalizar seus cálculos;
Este código esperará até que o método notify() seja chamado no objeto
ObjetoA. O código anteriormente descrito mostra que, enquanto a thread
estiver esperando, ela libera o bloqueio para outras threads, mas, para que
retorne à sua execução, ela necessita novamente desse bloqueio. O método
notify() fará a notificação a qualquer thread que esteja aguardando no objeto
this.
173
Java Programmer - Parte II
Caso a thread não seja interrompida, ela pode continuar sua execução até
que receba uma notificação, ou até a expiração do prazo de espera. Esse
prazo máximo de espera, determinado pelo método wait(), também pode ser
estabelecido em milissegundos, o que é feito da seguinte maneira:
Uma thread libera prontamente seu bloqueio assim que o método wait() é
chamado em um objeto, porém, isso não acontece necessariamente quando o
método notify() é chamado. Neste caso, o bloqueio apenas será liberado no
momento em que a thread tiver concluído o código sincronizado.
Assim que todas as threads são notificadas, elas iniciam uma competição em
busca do bloqueio. Dessa forma, as threads entram em ação sem que haja
a necessidade de uma notificação adicional, uma vez que o bloqueio será
utilizado e liberado por cada uma dessas threads.
174
Threads 17
Utilizar o método notifyAll() é importante principalmente nas situações em
que você tem diversas threads aguardando em um objeto ou, ainda, quando
deseja que a thread certa seja notificada. Com o método notify(), somente
uma thread será notificada, impossibilitando assegurar que esta será a thread
certa.
Método Métodos
Métodos
definido na definidos Métodos Métodos não
definidos na
interface na classe estáticos estáticos
classe Object
Runnable Thread
join()
notify()
sleep() sleep() join()
notifyAll() run()
start() yield() start()
wait()
yield()
Para que essa notificação seja recebida por todas as threads, é preciso que o
método notifyAll() seja chamado. Sendo assim, é preciso que esses métodos
sejam chamados em uma thread que possua o monitor do objeto ao qual
ela pertence. Vale ressaltar que, em razão disso, esses métodos devem ser
invocados em blocos sincronizados, ou em outros métodos.
175
Java Programmer - Parte II
Pontos principais
Atente para os tópicos a seguir. Eles devem ser estudados com muita
atenção, pois representam os pontos mais importantes do capítulo.
• Instanciar uma classe Thread é o primeiro passo para criar uma thread de
execução, embora ainda seja necessário um objeto Thread nas situações
em que o método run() se encontra na classe de implementação da
interface Runnable e nas ocasiões em que esse método se encontra em
uma classe estendida de Thread;
176
Threads 17
177
17 Threads
180
Threads 17
181
17 Threads
Mãos à obra!
Java Programmer - Parte II
Laboratório 1
A – Criando a classe ThreadLab
1. Crie uma classe com o nome ThreadLab que estenda a classe Thread;
2. Crie um construtor que receba uma String como parâmetro e passe a String
para o construtor da classe pai;
184
Threads 17
Laboratório 2
A – Modificando a classe ThreadLab para trabalhar de forma sincronizada
185
Java Programmer - Parte II
3. Execute o programa:
Dessa vez o acesso foi sincronizado entre as threads. Enquanto uma thread
não terminou sua execução, a outra não pôde obter o lock do objeto para
executar. Isso só ocorreu após o término da execução de uma das threads.
186
18
Geração de Pacotes -
Instalação de
Aplicações Java (JAR)
Arquivos JAR são gerados no formato ZIP, portanto os arquivos podem ser
empacotados e desempacotados utilizando os softwares de compressão
tradicionais.
188
Geração de Pacotes - Instalação de Aplicações Java (JAR)
18
18.2.1. Geração de um pacote executável
A partir do Eclipse, selecione a opção de exportação de projeto:
189
Java Programmer - Parte II
190
Geração de Pacotes - Instalação de Aplicações Java (JAR)
18
18.2.2. Utilização de uma biblioteca em projetos
Para utilizar este mesmo pacote gerado como biblioteca de um outro projeto,
o procedimento também é bem simples, utilizando a IDE.
A partir daí, o projeto atual pode referenciar e importar qualquer classe contida
na biblioteca.
191
Java Programmer - Parte II
Pontos principais
Atente para os tópicos a seguir. Eles devem ser estudados com muita
atenção, pois representam os pontos mais importantes do capítulo.
192
Geração de Pacotes -
18 Instalação de
Aplicações Java (JAR)
Teste seus conhecimentos
Java Programmer - Parte II
194
19 Banco de dados
com Java - JDBC
à Pacote java.sql;
à Conexões com banco de dados;
à Operações na base de dados;
à Operações parametrizadas;
à Transações;
à Consultas.
Java Programmer - Parte II
19.1. Introdução
O JDBC (Java Data Base Connectivity) é uma especificação elaborada no Java
para prover a acessibilidade a aplicações com bancos de dados por esta
linguagem, cuja primeira versão foi criada em 1997.
Esta API proporciona um acesso aos bancos de dados de forma fácil e simples,
especialmente acesso a dados armazenados em um banco de dados relacional.
Trata-se de um padrão de acesso a dados obedecido pela indústria de bancos
de dados.
A fim de seguir este padrão, os fabricantes devem distribuir drivers JDBC aos
desenvolvedores Java.
Com JDBC, você pode escrever aplicativos Java para gerenciar estas três
atividades de programação:
Uma vez que muitos dos novos recursos são opcionais e, consequentemente,
há alguma variação em drivers e as características que eles suportam, você
deve sempre verificar a documentação do driver para ver se ele suporta um
recurso antes de tentar usá-lo.
196
Banco de dados com Java - JDBC 19
19.2. Pacote java.sql
A API JDBC foi configurada para que você possa executar instruções SQL em
um banco de dados, bem como acessar e executar stored procedures e outras
rotinas programáticas.
Para isso, utilize um pacote chamado java.sql. Com ele, você pode acessar e,
também, processar os dados que estão armazenados em uma fonte de dados,
bem como abrir tabelas, além de realizar diversas operações, como inclusão,
alteração, exclusão de dados e consultas aos dados de uma tabela.
197
Java Programmer - Parte II
Com o framework Java SQL, é possível ter diversos drivers de banco de dados.
Todos os drivers possíveis são carregados por DriverManager, o qual, na
sequência, solicita que cada driver tente estabelecer a conexão com a URL de
destino.
Para estabelecer uma conexão com o banco de dados de sua preferência, utilize
a seguinte sintaxe para obter um objeto de conexão com o banco de dados:
try {
Connection con = DriverManager.getConnection(
“url”,”myLogin”, “myPassword”);
} catch (SQLException e) {
// realiza o tratamento em caso de falha
}
198
Banco de dados com Java - JDBC 19
A sintaxe de Connection é a seguinte:
Para criar um novo objeto Connection, a forma mais comum é utilizar o método
getConnection(), estático, na classe DriverManager.
199
Java Programmer - Parte II
• Campo: codigo, tipo INT, Primary Key (PK), Not Null, default 1;
200
Banco de dados com Java - JDBC 19
201
Java Programmer - Parte II
O método close() pode lançar erros e, por esse motivo, o bloco try/catch
deve ser utilizado para fechar a conexão com o banco de dados. Com relação
à chamada a esse método, recomendamos que ela seja colocada dentro do
bloco finally.
202
Banco de dados com Java - JDBC 19
A partir do Java 7, é possível utilizar o try-with-resources (try com recursos)
para inicializar os objetos Connection, Statement e Resultset. Para tanto,
basta declará-los dentro do comando try, que se encarrega de fechar os
recursos automaticamente ao final do bloco. Veja um exemplo de como esse
recurso pode ser usado com conexões de banco de dados:
Para realizar tais operações na base de dados, contamos com três diferentes
interfaces. Cada qual com sua característica:
Interface Descrição
Utilizada na realização de operações mais simples que
Statement
possuam valores fixos.
Utilizada na realização de operações parametrizadas, em
PreparedStatement que, a cada execução, novos valores são operados pelo
statement.
CallableStatement Utilizado na chamada/execução de stored procedures.
203
Java Programmer - Parte II
204
Banco de dados com Java - JDBC 19
A principal vantagem deste tipo de statement é que sua instrução pode ser
executada diversas vezes, cada hora com valores diferentes.
PreparedStatement ps = cn.prepareStatement(
“INSERT INTO tab VALUES (?, ?, ?, ?, ?, ?)”);
205
Java Programmer - Parte II
206
Banco de dados com Java - JDBC 19
19.6. Transações
Chamamos de transação um conjunto de operações atômicas realizadas na
base de dados e que podem ser desfeitas em situações de falha ou outro
problema.
• setAutoCommit(boolean);
• commit();
• rollback().
207
Java Programmer - Parte II
19.7. Consultas
As consultas na base de dados são realizadas mediante o comando SELECT.
Através dele, podemos obter os dados contidos em uma ou mais tabelas,
seguindo critérios, agrupamentos e/ou ordenações, conforme necessidade da
aplicação.
Após executar a consulta através deste comando, deve-se mover o cursor para
a primeira linha do ResultSet e, se esta linha existir, podemos coletar os seus
dados e avançar para a próxima linha.
Para avançar o cursor para a próxima linha, utilize o método next(). Além de
forçar o cursor a avançar, este método retorna um booleano informando se a
próxima linha existe ou não:
208
Banco de dados com Java - JDBC 19
Tendo avançado para uma linha válida, podemos então coletar os dados de
algum campo daquele registro através de um método get, conforme o tipo do
campo:
209
Java Programmer - Parte II
Pontos principais
Atente para os tópicos a seguir. Eles devem ser estudados com muita
atenção, pois representam os pontos mais importantes do capítulo.
• Para executar instruções SQL, é necessário ter a API JDBC, cuja primeira
versão foi criada em 1997. Esta API proporciona um acesso a banco de
dados fácil e simples. Isto quer dizer que ela permite acessar qualquer
tipo de dados tabulares, especialmente dados armazenados em um banco
de dados relacional;
210
19 Banco de dados
com Java - JDBC
Teste seus conhecimentos
Java Programmer - Parte II
☐ a) close()
☐ b) stop()
☐ c) break()
☐ d) dbend()
☐ e) Nenhuma das alternativas anteriores está correta.
☐ a) Path
☐ b) DriverManager
☐ c) Connection
☐ d) ResultSet
☐ e) CallableStatement
212
19 Banco de dados
com Java - JDBC
Mãos à obra!
Java Programmer - Parte II
Laboratório 1
Neste laboratório, você criará um cadastro de funcionários.
• DAOException();
• DAOException(String);
• DAOException(Throwable);
• DAOException(String, Throwable).
• int id;
• String nome;
• double salario;
• int cargoId.
214
Banco de dados com Java - JDBC 19
Este método será responsável por carregar o driver especificado pela constante
DRIVER e abrir a conexão com a base de dados utilizando as constantes URL,
USER e PASSWORD. A conexão aberta deverá ser retornada para quem tiver
chamado o método.
Este método será responsável por fechar os itens passados como parâmetros:
cn, st e rs. Cada um destes itens é opcional, o que significa que podem possuir
o valor null. O método deverá fechar cada um destes parâmetros (se não forem
nulos) com um tratamento de erro que não faz nada (bloco catch vazio).
Todo o código criado neste método deverá ser colocado em um bloco try, com
exceção das declarações de variáveis de conexão e statement.
215
Java Programmer - Parte II
Todo o código criado neste método deverá ser colocado em um bloco try,
com exceção das declarações de variáveis de conexão, statement e resultset.
216
Banco de dados com Java - JDBC 19
E – Criando a aplicação principal
217
Banco de dados
19 com Java - JDBC
Conclusão
Agora chegou o momento de construir a camada de persistência da aplicação,
assim como implementar os métodos de mapeamento objeto-relacional
contidos na classe DAO (Data Access Object).
Atividades
1. Importar o schema contendo a tabela filme para o MySQL Workbench;
3. Criar dois métodos na classe DAO que serão utilizados pelos demais métodos
quando necessitarem abrir ou fechar conexões com a base de dados:
• getConnection();
• closeConnection().
• Remoção de filme;
220
Apêndice I
Instalando e configurando
o ambiente Java
Java Programmer - Parte II
222
Apêndice I - Instalando e configurando o ambiente Java
223
Java Programmer - Parte II
224
Apêndice I - Instalando e configurando o ambiente Java
225
Java Programmer - Parte II
1. Clique no menu File / New / Class. A mesma opção pode ser acessada ao
clicar com o botão direito do mouse sobre o Package Explorer:
3. Clique em Finish. O arquivo será criado na pasta src e aberto para edição.
226
Apêndice I - Instalando e configurando o ambiente Java
Para executar o código, basta clicar no botão de execução (botão verde com
símbolo de play), disposto na barra de ferramentas do Eclipse. Você também
pode utilizar o menu Run / Run.
227
Apêndice II
String, Math e
LocalDateTime
Java Programmer - Parte II
2.1. Introdução
Na medida em que é responsável por definir as classes mais importantes, as
quais são importadas de forma automática, os pacotes java.lang e java.util
são de suma importância para a linguagem de programação Java. A seguir,
abordaremos os conceitos relacionados a três grupos de classes distintos:
String, Math e a classe LocalDateTime, do pacote java.time.
Nesse exemplo, o valor da String nome, que é “João”, teve “ cliente especial”
adicionado ao seu final, ou seja, o valor resultante é “João cliente especial”.
Como não é possível alterar uma String, a JVM não é capaz de inserir uma nova
String àquela referenciada por nome. Sendo assim, um novo objeto String, cujo
valor é “João cliente especial”, foi criado e, então, referenciado por nome.
Perceba que o exemplo tem três objetos String: o primeiro com valor “João”,
o segundo com valor “João cliente especial” e o terceiro, que, na verdade,
é um argumento literal concatenado, também é um objeto String (“ cliente
especial”), embora apenas “João” e “João cliente especial” sejam referenciados
por nome2 e por nome, respectivamente.
230
Apêndice II – String, Math e LocalDateTime
• Na segunda linha, outro objeto String é criado pela Java Virtual Machine. O
valor desse objeto é “Aluno Módulo Avançado”, porém, nada o referencia.
Sendo assim, esse segundo objeto é perdido de forma imediata;
Nesse último exemplo, inicialmente, foi criado um novo objeto String cujo
valor é “Aluno”, porém, em seguida, ele foi perdido. Apesar disso, a string
“Aluno” original continua sem alterações, bem como a ainda a referencia. Na
sequência, um novo objeto String, cujo valor é “eluno”, foi criado pela VM.
Esse objeto, contudo, também é perdido. Dessa forma, o objeto String original,
cujo valor é “Aluno”, permanece sem alterações, e a continua referenciando-o.
231
Java Programmer - Parte II
Embora diversos métodos tenham sido chamados para criar uma nova string
que altere a existente, esta não foi alterada em razão de uma variável de
referência não ser atribuída à nova string.
232
Apêndice II – String, Math e LocalDateTime
• “passa para”;
No total, foram criados oito objetos String, mas seis foram perdidos, restando
apenas dois: “passa para fim” e “passa para começo”.
Assim que encontra uma string literal, o compilador verifica o pool constante
de strings, com a finalidade de identificar se há uma string literal igual à
encontrada. Caso haja essa coincidência, não será criado qualquer novo objeto
String, e uma referência será direcionada ao novo valor literal para a string já
existente.
233
Java Programmer - Parte II
Para assegurar sua inalterabilidade, uma classe String é marcada como final
e, assim, os métodos do objeto String não são modificados de forma alguma.
• charAt(Numero_do_Indice)
• concat(Texto_A_Ser_Concatenado)
A função deste método é retornar um novo objeto String, composto pelo valor
da string que foi passada para ele, acrescido ao final da string que foi utilizada
a fim de chamar esse objeto.
234
Apêndice II – String, Math e LocalDateTime
• equalsIgnoreCase(Argumento)
235
Java Programmer - Parte II
• length()
Este método tem como função retornar o tamanho apresentado pela string
utilizada com a finalidade de chamar o método, como no exemplo a seguir:
• replace(Caractere_Antigo, Caractere_Novo)
Este método retorna um novo objeto String que apresenta como valor a String
utilizada com a finalidade de chamar o método e modificá-la pelas substituições
decorrentes.
236
Apêndice II – String, Math e LocalDateTime
• substring(Posição_Inicial, Posição_Final)
A função deste método é retornar uma parte do objeto String, o qual foi
utilizado na chamada do método. Essa parte do objeto String também é
denominada substring. O primeiro argumento (Posição_Inicial) diz respeito
ao local em que a substring inicia e começa em zero.
Assim, caso este argumento seja 5, o último caractere da string retornada será
da posição 5 da string original, e isso corresponde a 4. Ou seja, como regra
geral, o método substring inclui o caractere apontado pelo delimitador inicial
e exclui o caractere apontado pelo delimitador final.
237
Java Programmer - Parte II
• toLowerCase()
A função deste método é retornar um novo objeto String, cujo valor refere-se
à string que foi utilizada para chamar o método, em caixa baixa. Ao utilizar
toLowerCase(), o resultado obtido terá todos os seus caracteres convertidos
para caixa baixa. Veja:
• toUpperCase()
A função deste método é retornar o objeto String que contém o valor da string
utilizada para chamar o método com todos os caracteres convertidos em caixa
alta. Observe:
238
Apêndice II – String, Math e LocalDateTime
• trim()
Assim como os outros métodos, trim() também retorna um novo objeto String
que apresenta como valor a string utilizada sem espaços em branco no seu
início e fim, caso existam. Veja o exemplo:
• toString()
239
Java Programmer - Parte II
• append (“Texto_a_acrescentar”)
240
Apêndice II – String, Math e LocalDateTime
241
Java Programmer - Parte II
• reverse()
• toString()
resultado = método1().método2().método3();
242
Apêndice II – String, Math e LocalDateTime
• Então, um objeto String final, de valor “TxSTx FINAL”, foi criado pelo
método replace().
243
Java Programmer - Parte II
244
Apêndice II – String, Math e LocalDateTime
• Essa classe também não pode ser estendida por ser definida como final.
2.2.1. Métodos
Em razão de serem estáticos, os métodos da classe Math podem ser acessados
a partir do nome da classe. Normalmente, esses métodos são chamados da
seguinte maneira:
resultado = Math.umMétodoMathEstático();
• abs()
Veja um exemplo:
O retorno será 1.
245
Java Programmer - Parte II
• max()
Este método retorna o maior entre dois números distintos. Possui quatro
assinaturas:
Veja um exemplo:
• min()
Veja um exemplo:
246
Apêndice II – String, Math e LocalDateTime
• random()
Sem utilizar quaisquer parâmetros, retorna um valor entre 0.0 e 1.0, do tipo
double. A assinatura deste método é public static double random ( ).
Veja um exemplo:
• ceil()
Veja um exemplo:
O retorno será 4.
• floor()
Veja um exemplo:
O retorno será 3.
247
Java Programmer - Parte II
• round()
Este método retorna um número inteiro que esteja mais próximo ao número
utilizado no argumento. Possui duas assinaturas:
Veja um exemplo:
• sin()
• cos()
Veja um exemplo:
O retorno será 1.
248
Apêndice II – String, Math e LocalDateTime
• tan()
Veja um exemplo:
• sqrt()
Veja um exemplo:
O retorno será 3.
• toDegrees()
Veja um exemplo:
249
Java Programmer - Parte II
• toRadians()
Veja um exemplo:
3. Faça um loop for que percorra todo o array numeros. Dentro do loop,
declare uma variável com o nome n do tipo Double e atribua a ele um número
randômico entre 1 e 100;
250
Apêndice II – String, Math e LocalDateTime
LocalDateTime variavel =
LocalDateTime.parse(“0000-00-00T00:00:00.000”);
251
Java Programmer - Parte II
Para criar uma máscara de conversão com o padrão desejado, utilize o método
estático ofPattern() da classe DateTimeFormatter:
DateTimeFormatter mascara =
DateTimeFormatter.ofPattern(“[FORMATO_MASCARA]”);
Podemos, então, aplicar esta máscara ao método parse() para obter a data/
hora a partir de um string no formato especificado:
LocalDateTime variavel =
LocalDateTime.parse(“[DATA_HORA]”, mascara);
252
Apêndice II – String, Math e LocalDateTime
Símbolo Descrição
y Ano
M Mês
d Dia do mês (1-31)
h Hora (1-12)
H Hora (0-23)
m Minuto
s Segundo
S Milissegundo
E Dia da semana
D Dia do ano
w Semana do ano
W Semana do mês
a Marcador AM/PM
253
Java Programmer - Parte II
Método Descrição
getYear() Retorna o ano.
Retorna uma das instâncias da
getMonth()
enumeração Month.
getMonthValue() Retorno o número do mês (1-12).
getDayOfMonth() Retorna o dia do mês (1-31).
Retorna uma das instâncias da
getDayOfWeek()
enumeração DayOfWeek.
getHour() Retorna a hora do dia (0-23).
getMinute() Retorna o minuto (0-59).
getSecond() Retorna o segundo (0-59).
getNano() Retorna o nanossegundo.
Veja um exemplo:
254
Apêndice II – String, Math e LocalDateTime
Método Descrição
withYear(int) Gera uma cópia com o ano modificado.
withMonth(int) Gera uma cópia com o mês modificado.
withDayOfMonth(int) Gera uma cópia com o dia modificado.
withHour(int) Gera uma cópia com a hora modificada.
withMinute(int) Gera uma cópia com o minuto modificado.
withSecond(int) Gera uma cópia com o segundo modificado.
Gera uma cópia com o nanossegundo
withNano(int)
modificado.
255
Apêndice III
JavaFX
Java Programmer - Parte II
3.1. Introdução
Com o Java, podemos criar aplicações que interagem com o usuário através de
elementos como caixas de diálogos e janelas, que podem conter botões, caixas
de texto, ícones, menus, e outros elementos interativos. De uma forma geral,
chamamos a estes componentes de interface gráfica, cujo principal objetivo é
tornar a sua aplicação amigável e de fácil utilização pelo usuário.
Observe:
258
Apêndice III – JavaFX
Veja um exemplo:
259
Java Programmer - Parte II
Observe:
Ao salvar a sua interface gráfica com o Scene Builder, será gerado um arquivo
FXML que poderá ser posteriormente editado pela própria ferramenta ou em
algum editor de texto.
260
Apêndice III – JavaFX
Após gerado, o arquivo .fxml deverá ser incorporado à sua aplicação Java:
261
Java Programmer - Parte II
262
Apêndice III – JavaFX
3.3.1. Stage
Todos os componentes visuais do JavaFX são renderizados em uma região
denominada Window. A classe javafx.stage.Window trata-se de uma abstração
que possui diferentes implementações, em conformidade com o ambiente/
sistema operacional em que a aplicação está sendo executada.
Propriedade/Método Descrição
Permite assinalar o texto a ser exibido na barra
setTitle()
de títulos da janela.
setWidth() e Definem a largura e altura inicial da janela,
setHeight() respectivamente.
Definem a posição da janela em relação à tela
setX() e setY() do computador (área de trabalho do sistema
operacional).
Define se a janela possuirá tamanho fixo (false)
setResizable()
ou variável (true).
show() Exibe a janela.
263
Java Programmer - Parte II
3.3.2. Scene
A classe javafx.scene.Scene representa a película de fundo da região em que
os elementos gráficos serão exibidos. Através do método setFill(), podemos
definir uma cor, foto ou efeito de fundo para sua janela. Este método aceita os
seguintes tipos como argumentos:
Tipo Descrição
ImagePattern Permite definir uma imagem de fundo para sua janela.
LinearGradient Permite definir um efeito de mudança linear de cores.
RadialGradient Permite definir um efeito de mudança radial de cores.
Color Define uma simples cor de fundo para sua janela.
264
Apêndice III – JavaFX
265
Java Programmer - Parte II
3.3.3. Pane
javafx.scene.layout.Pane é a classe base para os diversos tipos de painéis
da biblioteca JavaFX. Utilizamos painéis para especificar o posicionamento
dos demais componentes em tela, de forma a se reorganizarem conforme o
tamanho da janela.
Segue adiante uma breve descrição dos principais painéis, todos pertencentes
ao pacote javafx.scene.layout:
266
Apêndice III – JavaFX
267
Java Programmer - Parte II
3.3.4. Button
Um componente Button representa um botão em que o usuário pode clicar ou
pressionar a barra de espaço para que algum evento seja disparado.
• Text: Define o rótulo a ser exibido pelo botão. Utilize o caractere “_”
(underline) para definir a tecla de acesso. O underline deve preceder a letra
desejada e a propriedade Mnemonic Parsing precisa estar habilitada;
268
Apêndice III – JavaFX
3.3.5. TextField
Este componente representa uma caixa de texto em que o usuário poderá
digitar. Observe:
Sua principal propriedade é a Text, que permite definir um texto inicial a ser
exibido pela caixa. Utilize os métodos getText() e setText() para manipular
programaticamente o conteúdo digitado pelo usuário.
3.3.6. Label
Um rótulo utilizado na exibição de mensagens fixas em sua janela:
3.3.7. ImageView
Permite adicionar uma imagem ou ícone em uma posição específica. Veja um
exemplo:
269
Java Programmer - Parte II
3.3.8. CheckBox
Componente que pode ser marcado ou desmarcado pelo usuário:
3.3.9. RadioButton
Possui a mesma funcionalidade de uma CheckBox, porém, pode ser utilizado
em grupos em que podemos ter a seleção exclusiva. Observe:
270
Apêndice III – JavaFX
3.4.1. Identificadores
Cada componente a ser controlado dinamicamente deve possuir um
identificador único dentro do arquivo FXML. Para assinalar o id (identificador)
de um componente, basta selecionar o componente desejado e, na seção Code
do Inspector, digitar o id desejado na caixa fx:id:
271
Java Programmer - Parte II
3.4.2. Eventos
Os eventos são as ações realizadas sobre os componentes de uma interface
gráfica, como um clique, pressionar de tecla, fechamento de janela etc.
Evento Descrição
Executado ao clicar ou ativar (pressionar da tecla
On Action
ENTER) sobre o componente.
On Mouse Clicked Executado ao clicar sobre o componente.
Executado ao passar o ponteiro sobre o
On Mouse Entered
componente.
Executado ao sair com o ponteiro de cima do
On Mouse Exited
componente.
Executado ao baixar um dos botões do mouse
On Mouse Pressed
sobre o componente.
Executado ao liberar o botão do mouse que havia
On Mouse Released
sido baixado sobre o componente.
Executado quando o usuário digita algum
On Key Typed
caractere sobre o componente.
Executado quando o usuário baixa alguma tecla
On Key Pressed
sobre o componente.
Executado quando o usuário libera a tecla que foi
On Key Released
baixada sobre o componente.
272
Apêndice III – JavaFX
273
Java Programmer - Parte II
274
Apêndice III – JavaFX
275
Java Programmer - Parte II
276
Apêndice IV
Java em módulos - Jigsaw
Java Programmer - Parte II
Todo o JDK foi reestruturado para o novo formato de módulos, porém de uma
forma ainda pouco invasiva quanto à antiga forma de classpaths já utilizada
em versões anteriores.
http://openjdk.java.net/projects/jigsaw/spec/sotms/
278