Baixe o app para aproveitar ainda mais
Prévia do material em texto
Guia Prático para Certificação Atualize sua certificação Java 6 para Java 8 Rinaldo Pitzer Jr., Rodrigo Moutinho Version v1.0.3, 2020-04-14 Índice Licença . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Contribuidores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Começando. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Objetivos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Language Enhancements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Objetos Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Try com recursos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Múltiplas Exception no mesmo catch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Métodos static e default em Interfaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 Localization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Localização (Locale) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Pacote de Recursos (Resource Bundle) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 Data e Hora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Formatação de Números e Datas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 Fusos Horários . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 Lambda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 Interfaces Funcionais (Functional Interfaces) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 Expressões Lambda (Lambda Expression) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 Interfaces Funcionais Pré-Construídas (Built-in Interfaces) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 Referências a Métodos (Method Reference) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 Java Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 Utilizando Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 Streams Paralelos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 Concurrency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 Pacote Concurrent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 Locks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 Executando tarefas com ExecutorService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 Framework Fork/Join . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177 Java File I/O (NIO.2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 DirectoryStream e FileVisitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 Files com Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 WatchService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 Java Collections. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 Diamond Operator (Operador Diamante) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 Collections e lambda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229 Buscar por dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 Fazendo cálculos e coletando resultados de Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232 Melhorias de Java 8 em Coleções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 Maps e Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 Assume the following . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240 Apêndice A: Dicas para ter sucesso na prova!. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 Cenário 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 Cenário 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242 Cenário 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242 Apêndice B: Teste seu conhecimento! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 Gratuito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 Pagos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 Apêndice C: Referências . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245 Material Complementar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245 Licença MIT License Copyright (c) 2019 Rinaldo Pitzer Jr. e Rodrigo Moutinho Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1 Contribuidores Por ser um livro de código aberto, recebemos várias mudanças de conteúdo e erratas ao longo de seu desenvolvimento. Aqui estão todas as pessoas que contribuíram para a versão em português do livro como um projeto de código aberto. Obrigado a todos por ajudarem a tornar este livro melhor para todos. Rinaldo Pitzer Júnior Rodrigo Moutinho semantic-release-bot Esse texto é praticamente o mesmo utilizado no Pro Git 2. Acesse o texto original aqui. 2 https://raw.githubusercontent.com/progit/progit2/master/book/contributors.asc Começando Introdução Este projeto serve como material de apoio na realização do exame 1Z0-813 que atualiza qualquer profissional com certificação Java 6 ou inferior, para a versão 8. No momento desta documentação, o voucher do exame custa R$ 597,00 no Brasil. Objetivos Como guia para criação deste livro foi utilizado todos os objetivos citados na seção "Review Exam Topics", de acordo com o site da certificação. A missão deste livro é criar o maior número de exemplos práticos possíveis para ajudar você a colocar a mão na massa. Quanto maior for seu contato com os códigos da versão 8 do Java, mais confiante estará na hora do exame, e também para lidar com projetos em Java 8 no mercado de trabalho. 3 https://education.oracle.com/upgrade-to-java-se-8-ocp/pexam_1Z0-813 https://education.oracle.com/upgrade-to-java-se-8-ocp/pexam_1Z0-813 Language Enhancements Objetos Strings Objetivo Develop code that uses String objects in the switch statement, binary literals, and numeric literals, including underscores in literals. - Desenvolver código que utilize objetos String em instruções Switch, binários literais, e numéricos literais, incluindo underscore (_) em literais. String em instruções Switch É esperado que o candidato saiba compreender e analisar o uso de Strings em instruções switch, como no seguinte exemplo. src/org/j6toj8/languageenhancements/stringinswitch/StringInSwitch_Complete.java public static void main(String[] args) { String mes = "jan"; switch (mes) { case "jan": System.out.println("Janeiro"); break; case "fev": System.out.println("Fevereiro"); break; case "mar": System.out.println("Março"); break; default: break; } } Apesar da certificação ter foco nas atualizações trazidas pelo Java 7 e 8, é esperado que o candidato entenda também conceitos de versões anteriores do Java. Por isso, serão apresentadas algumas regras que talvez você já conheça sobre switch, mas utilizando String no switch. 1. Todo case deve ser único, não pode se repetir. 2. O default pode aparecer em qualquer posição no switch. 4 src/org/j6toj8/languageenhancements/stringinswitch/StringInSwitch_Default.java public static void main(String[] args) { String mes = "jan"; switch (mes) { case "jan": System.out.println("Janeiro"); break; default: // COMPILA - O default pode estar em qualquer posição break; case "jan": // NÃO COMPILA - Já existe o case "jan" System.out.println("Janeiro2"); break; case "mar": System.out.println("Março"); break; } } 3. Tipos suportados em switch. ◦ int e Integer ◦ byte e Byte ◦ short e Short ◦ char e Character ◦ String ◦ valores de Enums 4. Tipos não suportados em switch. 5 src/org/j6toj8/languageenhancements/stringinswitch/StringInSwitch_Type.java public static void main(String[] args) { Long mes = 1L; switch (mes) { // NÃO COMPILA - Long não é um tipo suportado case 1L: System.out.println("Janeiro"); break; case 2L: System.out.println("Fevereiro"); break; default: break; } } 5. A execução se inicia em um case e somente para ao encontrar um break. src/org/j6toj8/languageenhancements/stringinswitch/StringInSwitch_Break.java public static void main(String[] args) { String mes = "jan"; switch (mes) { case "jan": System.out.println("Janeiro"); default: System.out.println("Não é um mês"); case "fev": System.out.println("Fevereiro"); break; case "mar": System.out.println("Março"); break; } } saída no console Janeiro Não é um mês Fevereiro Nesse caso a execução inicia no case "jan", passar pelo default e pelo case "fev" até parar no break, por isso as 3 strings aparecem no console. 6 6. Um switch vazio é válido, mesmo que não tenha utilidade. src/org/j6toj8/languageenhancements/stringinswitch/StringInSwitch_Empty.java public static void main(String[] args) { String mes = "jan"; switch (mes) {} // COMPILA - switch pode estar vazio, mesmo que seja inútil } 7. Todos os valores de case precisam ser constantes, ou seja, variáveis finais em tempo de compilação. Se o valor do case puder mudar em tempo de execução, o código não compila. src/org/j6toj8/languageenhancements/stringinswitch/StringInSwitch_ConstantOnly.java private static final String FEV = "fev"; private static String jan = "jan"; public static void getNomeMes(final String mai) { String mes = "jan"; final String mar = "mar"; String abr = "abr"; switch (mes) { case jan: // NÃO COMPILA - jan é um atributo comum, pode mudar em tempo de execução System.out.println("Janeiro"); break; case FEV: // COMPILA - FEV é uma constante em tempo de compilação, seu valor nunca muda System.out.println("Fevereiro"); break; case mar: // COMPILA - mar é uma constante em tempo de compilação, seu valor nunca muda System.out.println("Março"); break; case abr: // NÃO COMPILA - abr é uma variável comum, pode mudar em tempo de execução System.out.println("Abril"); break; case mai: // NÃO COMPILA - mai é final, mas não é constante, pode mudar em tempo de execução System.out.println("Maio"); break; } } 7 Pronto, essas são as regras de switch. Você provavelmente já conheçe algumas referentes à versões anteriores do Java, mas agora você as viu em switch que utilizam Strings. Isso não era possível antes do Java 7. Literais Binários e Numéricos, incluindo underscore( _ ) É esperado que o candidato saiba compreender e analisar o uso de literais binários e numéricos, como no seguinte exemplo. src/org/j6toj8/languageenhancements/literals/Literals_Complete.java int i1 = 1; // int int i2 = 1_000_000; // int com underscore int i3 = 0567; // octadecimal int i4 = 0xFA1; // hexadecimal int i5 = 0b0101; // binário long l1 = 1L; //long com L long l2 = 1l; // long com l long l3 = 12_345_6_7890_123456_789L; // long com underscore long l4 = 0xFA1L; // long hexadecimal double d1 = 1.00; // double double d2 = 100_000.01; // double com underscore double d3 = 1D; // double com D double d4 = 3.1E2; // notação científica = 3.1 * 10^2 = 3.1 * 100 = 310.0 float f1 = 1.00F; // float Apesar da certificação ter foco nas atualizações trazidas pelo Java 7 e 8, é esperado que o candidato entenda também conceitos de versões anteriores do Java. Por isso, serão apresentadas algumas regras que talvez você já conheça sobre literais. 1. No Java, Literal é qualquer número escrito diretamente no código, como todos do exemplo acima. 2. Por padrão, o Java interpreta literais como int. Ou seja, se não houver um sufixo no número para mudar seu tipo, ele é um int. src/org/j6toj8/languageenhancements/literals/Literals_Suffix.java int i1 = 1; // por padrão é int long l1 = 1L; // com um L no final, é um long double d1 = 1.0; double d2 = 1.0D; // com ou sem D no final, se tiver casa decimal é um double por padrão float f1 = 1.0F; // com um F no final, é um float 3. Por padrão, o Java interpreta literais como sendo decimais. Existem prefixos que mudam o sistema numérico do literal. 8 src/org/j6toj8/languageenhancements/literals/Literals_Prefix.java int i1 = 0567; // octadecimal - base 8 - começa com 0 int i2 = 0xFA1; // hexadecimal - base 16 - começa com 0x int i3 = 0b0101; // binário - base 2 - começa com 0b long l1 = 0xABCL; // long também pode ser hexadecimal - começa com 0x e termina com L 4. A partir do Java 7, é possível utilizar underscore (_) para separar visualmente um número. Isso não muda o valor do número, e serve apenas para tornar o código mais legível. src/org/j6toj8/languageenhancements/literals/Literals_Underscore.java int i1 = 1_000_000; // int com underscore - é o mesmo que escrever 1000000 int i2 = 10_00_00_0; // o underscore pode estar em qualquer posição entre 2 números int i3 = _1000; // NÃO COMPILA - o underscore não pode estar no início int i4 = 1000_; // NÃO COMPILA - o underscore não pode estar no final int i5 = 1___000; // COMPILA - vários underscore é permitido, desde que estejam entre 2 números int i6 = 0x_100; // NÃO COMPILA - entre marcador de base não é permitido int i7 = 0xF_F; // COMPILA - apesar de serem letras, representam valores numéricos dessa base long l1 = 12_345_6_7890_123456_789L; // long com underscore long l2 = 12_345_6_789_L; // NÃO COMPILA - não pode ficar ao lado de um marcador de tipo double d1 = 100_000.01; // double com underscore double d2 = 10_.01; // NÃO COMPILA - o underscore deve estar entre números double d3 = 10._01; // NÃO COMPILA - o underscore deve estar entre números Referências Strings em Switch • Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 598). Wiley. Edição do Kindle. • Strings in switch Statements. Java Documentation. • New Java 7 Feature: String in Switch support. DZone. Literais • Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 597). Wiley. Edição do Kindle. • Java/Literais. Wikibooks. 9 https://docs.oracle.com/javase/8/docs/technotes/guides/language/strings-switch.html https://dzone.com/articles/new-java-7-feature-string https://pt.wikibooks.org/wiki/Java/Literais Try com recursos Objetivo Develop code that uses try-with-resources statements, including using classes that implement the AutoCloseable interface. - Desenvolver código que utilize instruções try-with-resources, incluindo o uso de classes que implementam a interface AutoCloseable. É esperado que o candidato saiba compreender e analisar o uso da instrução try-with-resources, incluindo classes que implementam a interface AutoClosable. Antes de continuar, com base no exemplo a seguir, entenda a execução do método main e o que é apresentado no console após sua execução. src/org/j6toj8/languageenhancements/trywithresources/TryWithResouces_Complete.java public static void main(String[] args) throws IOException { // criação de 2 arquivos File file = new File("arquivo.txt"); File file2 = new File("arquivo2.txt"); // Exemplo try-with-resources com PrintWriter try (PrintWriter writer = new PrintWriter(file)) { // escreve no arquivo.txt writer.println("Olá Mundo!"); } // Exemplo try-with-resources com BufferedReader try (BufferedReader reader = Files.newBufferedReader(file.toPath())) { // imprime no console uma linha do arquivo.txt System.out.println(reader.readLine()); } // Exemplo try-with-resources com BufferedReader e BufferedWriter try (BufferedReader reader = Files.newBufferedReader(file.toPath()); BufferedWriter writer = Files.newBufferedWriter(file2.toPath())) { // lê a linha do arquivo.txt e escreve no arquivo2.txt writer.write(reader.readLine() + "2"); } // Exemplo try-with-resources com BufferedReader try (BufferedReader reader = Files.newBufferedReader(file2.toPath())) { // imprime no console uma linha do arquivo2.txt System.out.println(reader.readLine()); } // todos os Reader e Writer já foram fechados. } 10 O código acima utiliza dois arquivos, e faz leitura e escrita neles. A grande novidade desse código é a declaração de variáveis dentro de parênteses após a instrução try. Isso é a sintaxe chamada try- with-resources, e ela chama automaticamente o método close() dos recursos que estão sendo utilizados. Até o Java 6, seria necessário chamar o close() manualmente, como no exemplo abaixo. src/org/j6toj8/languageenhancements/trywithresources/TryWithResouces_Java6.java public static void main(String[] args) throws FileNotFoundException { File file = new File("arquivo.txt"); PrintWriter writer = null; try { writer = new PrintWriter(file); writer.println("Olá Mundo!"); } finally { if (writer != null) { writer.close(); // fechando o writer manualmente } } } 1. A instrução try-with-resources fecha automaticamente os recursos que implementam a interface AutoCloseable. 2. Ela não precisa de catch nem finally explícitos. src/org/j6toj8/languageenhancements/trywithresources/TryWithResouces_AutoCloseable.java static class Porta implements AutoCloseable { @Override public void close() { // chamado automaticamente pelo try-with-resources System.out.println("Porta fechada."); } } public static void main(String[] args) throws FileNotFoundException { try (Porta porta = new Porta()) { // Porta instanciada dentro da instrução try- with-resources System.out.println("try"); } } Saída no console try Porta fechada. 3. A instrução try-with-resources ainda pode ter catch e finally, apesar de não ser necessário. Nesse caso, os recursos são fechados depois do try e antes de qualquer catch ou finally. 4. O método close pode lançar uma exceção sendo capturada pelo catch, caso exista. 11 src/org/j6toj8/languageenhancements/trywithresources/TryWithResouces_WithCatchFinally.java static class Porta implements AutoCloseable { @Override public void close() throws Exception { // chamado automaticamente pelo try-with- resources System.out.println("Porta fechada."); throw new Exception(); // lança Exception } } public static void main(String[] args) throws FileNotFoundException { try (Porta porta = new Porta()) { // Porta instanciada dentro da instrução try- with-resources System.out.println("try"); } catch (Exception e) { System.out.println("catch"); } finally { System.out.println("finally"); } } Saída no console try Porta fechada. catch finally Ou seja, primeiro o try é chamado. Logo depois é chamado o método close() que ao final lança uma exceção. O catch captura essa exceção. E finalmente o finally é chamado. 5. Os recursos declarados na instrução try-with-resources são fechados na ordem inversa da declaração. 12 src/org/j6toj8/languageenhancements/trywithresources/TryWithResouces_Order.java static class Porta implementsAutoCloseable { @Override public void close() { // chamado automaticamente pelo try-with-resources System.out.println("Porta fechada."); } } static class Gaveta implements AutoCloseable { @Override public void close() { // chamado automaticamente pelo try-with-resources System.out.println("Gaveta fechada."); } } public static void main(String[] args) { try (Porta porta = new Porta(); Gaveta gaveta = new Gaveta()) { System.out.println("Olá."); } } Saída no console Olá. Gaveta fechada. Porta fechada. Ou seja, como a ordem de declaração dentro do try-with-resources foi Porta e depois Gaveta, a ordem de chamada do método close é inversa: Gaveta e depois Porta. 6. Os recursos declarados no try-with-resources só estão disponível dentro do bloco try. 13 src/org/j6toj8/languageenhancements/trywithresources/TryWithResouces_ResourceInsideTry.java static class Porta implements AutoCloseable { @Override public void close() { // chamado automaticamente pelo try-with-resources System.out.println("Porta fechada."); } } public static void main(String[] args) { try (Porta porta = new Porta()) { porta.toString(); } catch (Exception e) { porta.toString(); // NÃO COMPILA - variável porta só disponível dentro do bloco try } finally { porta.toString(); // NÃO COMPILA - variável porta só disponível dentro do bloco try } } 7. Somente classes que implementam AutoCloseable podem ser utilizadas dentro do try-with- resources. src/org/j6toj8/languageenhancements/trywithresources/TryWithResouces_NoAutoCloseable.java static class Prateleira {} public static void main(String[] args) { try (Prateleira prateleira = new Prateleira()) { // NÃO COMPILA - Prateleira não implementa AutoClosable System.out.println("Olá"); } } 8. Caso o método close() lance uma exceção checada (ou seja, que herda de Exception), o código só compila se existir um catch que capture aquela exceção, ou o método declare o throws. 14 src/org/j6toj8/languageenhancements/trywithresources/TryWithResouces_CloseException.java static class Porta implements AutoCloseable { @Override public void close() throws Exception { // declara throws Exception obrigatoriamente throw new Exception(); } } void try1() { try (Porta porta = new Porta()) { // NÃO COMPILA - exceção do close() não é capturada nem declarada System.out.println("Olá 1"); } } void try2() { try (Porta porta = new Porta()) { System.out.println("Olá 2"); } catch (Exception e) { // COMPILA - exceção capturada } } void try3() throws Exception { // COMPILA - exceção declarada no método try (Porta porta = new Porta()) { System.out.println("Olá 3"); } } 9. O Java 5 já possuía uma interface chamada Closeable, porém ela permite lançar apenas IOException. A nova interface AutoCloseable permite lançar qualquer exceção. Como Closeable atende a implementação de AutoCloseable, ela agora estende AutoCloseable. Logo, todas as classes que já implementavam Closeable podem ser utilizadas dentro do try-with-resources. Veja abaixo como era a interface Closeable antes e a partir do Java 7: Antes do Java 7 public interface Closeable { public void close() throws IOException; } A partir do Java 7 public interface Closeable extends AutoCloseable { public void close() throws IOException; } 10. Um comportamento novo são as exceções suprimidas (suppressed). Se ambos o bloco try e o 15 método close lançam exceção, a do close fica suprimida, pois a do try é lançada primeiro. src/org/j6toj8/languageenhancements/trywithresources/TryWithResouces_Suppressed.java static class Porta implements AutoCloseable { @Override public void close() { System.out.println("close"); throw new RuntimeException("erro no close"); // lança RuntimeException, mas só depois do try } } public static void main(String[] args) { try (Porta porta = new Porta()) { System.out.println("try"); throw new RuntimeException("erro no try"); // lança RuntimeException } catch (RuntimeException e) { // captura RuntimeException - qual foi capturada? System.out.println(e.getMessage()); // apresenta a mensagem da exceção do try System.out.println(e.getSuppressed()[0].getMessage()); // apresenta a mensagem da exceção suprimida, ou seja, do close } } Saída no console try close erro no try erro no close Ou seja, a exceção que de fato foi capturada foi a do bloco try, pois foi lançada primeiro. A exceção lançada pelo método close ficou suprimida, e fica disponível em um array no método getSuppressed() da exceção. 11. E por fim, é necessário lembrar que a instrução try "comum" ainda precisa obrigatoriamente de um catch ou finally. 16 src/org/j6toj8/languageenhancements/trywithresources/TryWithResouces_CommonTry.java public static void main(String[] args) { try { System.out.println("try"); } // NÃO COMPILA - try "comum" sem catch ou finally try { System.out.println("try"); } catch (Exception e) { } // COMPILA - try "comum" só com catch try { System.out.println("try"); } finally { } // COMPILA - try "comum" só com finally try { System.out.println("try"); } catch (Exception e) { } finally { } // COMPILA - try "comum" com catch e finally } Alguns tipos que implementam Closeable • InputStream e suas subclasses (FileInputStream, ObjectInputStream, etc) • OutputStream e suas subclasses (ByteArrayOutputStream, FileOutputStream, etc) • Reader e suas subclasses (BufferedReader, CharSequenceReader) • Writer e suas subclasses (BufferedWriter, PrintWriter, etc) Referências • Using Try-With-Resources Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 296). Wiley. Edição do Kindle. • Java – Try with Resources. • The try-with-resources Statement. Java Documentation. • Como funciona o try-with-resources? 17 https://www.baeldung.com/java-try-with-resources https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html https://pt.stackoverflow.com/questions/172909/como-funciona-o-try-with-resources/172910#172910 Múltiplas Exception no mesmo catch Objetivo Develop code that handles multiple Exception types in a single catch block. - Desenvolver código que lide com múltiplos tipos de Exception em um único bloco catch. É esperado que o candidato saiba compreender e analisar o uso da instrução try-catch com múltiplos tipos de Exception no mesmo bloco catch. Antes de continuar, com base no exemplo a seguir, entenda a execução do método main e o que é apresentado no console após sua execução. src/org/j6toj8/languageenhancements/multipleexception/MultipleException_Complete.java public static void main(String[] args) { try { throw new NullPointerException(); } catch (NullPointerException | IllegalArgumentException | IllegalStateException e) { System.out.println("Exceção capturada: " + e); } catch (Exception e) { System.out.println("Exceção capturada: " + e); } } O código anterior possui um bloco try-catch que você provavelmente já conhece. A novidade neste código está no primeiro bloco catch, onde várias exceções são declaradas e capturadas ao mesmo tempo. Saída no console Exceção capturada: java.lang.NullPointerException 1. Desde o Java 7, múltiplas exceções podem ser capturadas no mesmo catch. 2. Apenas uma variável é permitida para um bloco catch, e deve estar localizada no final. 18 src/org/j6toj8/languageenhancements/multipleexception/MultipleException_MultipleSameCatch.java public static void main(String[] args) { try { throw new NullPointerException(); } catch (NullPointerException | IllegalArgumentException e) { // COMPILA - múltiplas exceções no mesmo catch, só uma variável no final System.out.println("Exceção capturada: " + e); } catch (IllegalStateException ise | UnsupportedOperationException uoe) { // NÃO COMPILA - mais de uma variável declarada System.out.println("Exceção capturada: " + ise); } catch (ClassCastExceptioncce | ConcurrentModificationException) { // NÃO COMPILA - só uma variável, mas no lugar errado System.out.println("Exceção capturada: " + cce); } } 3. Não é permitido declarar exceções diferentes, mas que seriam redundantes levando em consideração a herança. src/org/j6toj8/languageenhancements/multipleexception/MultipleException_Redundant.java public static void main(String[] args) { try { throw new NullPointerException(); } catch (RuntimeException | IllegalArgumentException e) { // NÃO COMPILA - IllegalArgumentException herda de RuntimeException, logo seria redundante System.out.println("Exceção capturada: " + e); } } 4. Ao fazer catch de múltiplas Exception, não é permitido sobrescrever a variável da exceção. Mas é possível se for apenas uma Exception no catch. 19 src/org/j6toj8/languageenhancements/multipleexception/MultipleException_OverrideVar.java public static void main(String[] args) { try { throw new NullPointerException(); } catch (NullPointerException | IllegalArgumentException e) { e = new IllegalStateException(); // NÃO COMPILA - a variável não pode ser sobrescrita quando está em um multi-catch } catch (Exception e) { e = new IllegalStateException(); // COMPILA - ainda é possível sobrescrever a variável quando não é um multi-catch } } 5. Assim como nas versões anteriores, tipos mais genéricos de Exception devem vir depois, mais abaixo nos catch’s. src/org/j6toj8/languageenhancements/multipleexception/MultipleException_GenericsLower.java public static void main(String[] args) { try { throw new NullPointerException(); } catch (Exception e) { System.out.println("Exceção capturada: " + e); } catch (NullPointerException | IllegalArgumentException e) { // NÃO COMPILA - NullPointerException é mais específico que Exception, logo deveria ser capturada antes de Exception System.out.println("Exceção capturada: " + e); } } 6. Assim como nas versões anteriores, Exceções repetidas ainda são proibidas. src/org/j6toj8/languageenhancements/multipleexception/MultipleException_RepeatException.java public static void main(String[] args) { try { throw new NullPointerException(); } catch (NullPointerException | IllegalArgumentException e) { System.out.println("Exceção capturada: " + e); } catch (IllegalStateException | NullPointerException e) { // NÃO COMPILA - NullPointerException já foi capturada no catch anterior System.out.println("Exceção capturada: " + e); } } 20 7. Assim como nas versões anterior, Exceções checadas (aquelas que herdam de Exception) só podem estar em um catch caso algo no try lance elas. src/org/j6toj8/languageenhancements/multipleexception/MultipleException_CheckedException.java public static void main(String[] args) { try { throw new NullPointerException(); } catch (NullPointerException | IOException e) { // NÃO COMPILA - IOException não é lançada dentro do bloco try System.out.println("Exceção capturada: " + e); } } Referências • Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 291). Wiley. Edição do Kindle. • Catching Multiple Exception Types and Rethrowing Exceptions with Improved Type Checking. Java Documentation. Métodos static e default em Interfaces Objetivo Use static and default methods of an interface including inheritance rules for a default method. - Usar métodos static e default de uma interface, incluindo regras de herança para um método default. É esperado que o candidato saiba compreender e analisar o uso da dos modificadores static e default em métodos de interfaces. Antes de continuar, com base no exemplo a seguir, entenda a execução do método main e o que é apresentado no console após sua execução. 21 https://docs.oracle.com/javase/8/docs/technotes/guides/language/catch-multiple.html https://docs.oracle.com/javase/8/docs/technotes/guides/language/catch-multiple.html src/org/j6toj8/languageenhancements/staticdefaultininterfaces/StaticDefaultInInterfaces_Complete.java interface Corredor { static double calculeVelocidade(int distancia, int tempo) { return distancia / tempo; } default String correr() { return "Correndo"; } String correrRapido(); } static class Pessoa implements Corredor { @Override public String correrRapido() { return "Pessoa Correndo Rápido"; } public static void main(String[] args) throws IOException { System.out.println(Corredor.calculeVelocidade(100, 10)); System.out.println(new Pessoa().correr()); System.out.println(new Pessoa().correrRapido()); } } Saída no console 10.0 Correndo Pessoa Correndo Rápido O código anterior possui dois modificadores novos para interfaces, possíveis desde o Java 8: default e static. É possível perceber que esses dois métodos possuem corpo, algo que não era possível antes em uma interface. Então, vamos entender quais são as novas possibilidades. 1. Desde o Java 8, Interfaces podem ter métodos com o modificador static. 2. Métodos com o modificador static em interfaces são chamados iguais aos de uma classe comum, ou seja, não fazem parte da API da interface. Dessa forma, não são herdados pelas classes que implementam essa interface. 22 src/org/j6toj8/languageenhancements/staticdefaultininterfaces/StaticDefaultInInterfaces_Static.java interface Corredor { static double calculeVelocidade(int distancia, int tempo) { return distancia / tempo; } } static class Pessoa implements Corredor { public static void main(String[] args) throws IOException { System.out.println(Corredor.calculeVelocidade(100, 50)); // COMPILA - método static de uma interface sendo chamado como se fosse de uma classe comum System.out.println(Pessoa.calculeVelocidade(100, 50)); // NÃO COMPILA - o método static não é herdado, nem implementado, pela classe Pessoa } } 3. Desde o Java 8, Interfaces podem ter métodos com o modificador default. 4. Métodos default não precisam, mas podem, ser sobrescritos. src/org/j6toj8/languageenhancements/staticdefaultininterfaces/StaticDefaultInInterfaces_Default.java interface Corredor { default String correr() { return "Correndo"; } } static class Pessoa implements Corredor { } static class Cavalo implements Corredor { @Override public String correr() { return "Galopando"; } public static void main(String[] args) throws IOException { System.out.println(new Pessoa().correr()); System.out.println(new Cavalo().correr()); } } Veja que a classe Pessoa não sobrescreve o método correr(), mantendo o comportamento padrão da implementação feita na interface Corredor. A classe Cavalo, por outro lado, sobrescreve o método correr() para ter sua própria implementação. 23 Saída no console Correndo Galopando 5. Assim como os outros método de uma interface, os métodos static e default são sempre public, e não podem ser modificados para private ou protected. src/org/j6toj8/languageenhancements/staticdefaultininterfaces/StaticDefaultInInterfaces_AccessModifie rs.java interface Corredor { default String correr() { // COMPILA - não há modificador de acesso declarado, é automaticamente público return "Correndo"; } public default String correrRapido() { // COMPILA - modificador de acesso público explícito return "Correndo Rápido"; } protected default String correrDevagar() { // NÃO COMPILA - o método deve ser obrigatoriamente público return "Correndo Devagar"; } private default String correrExtremo() { // NÃO COMPILA - o método deve ser obrigatoriamente público return "Correndo ao Extremo"; } private static double calculeVelocidade(int d, int t) { // NÃO COMPILA - o método deve ser obrigatoriamente público return d / t; } } 6. Diferente dos outros método de uma interface, os métodos static e default não são abstract, e também não podem ser. Afinal, eles possuem implementação. Apenas métodos sem implementação são abstract. 24 src/org/j6toj8/languageenhancements/staticdefaultininterfaces/StaticDefaultInInterfaces_Abstract.javainterface Corredor { default String correr() { // COMPILA - método default não é abstract return "Correndo"; } abstract default String correrRapido() { // NÃO COMPILA - método default não pode ser declarado abstract return "Correndo Rápido"; } String correrDevagar(); // COMPILA - método comum, é abstract por padrão, mesmo que de forma implícita abstract String correrExtremo(); // COMPILA - método comum, declarado abstract de forma explícita abstract static double calculeVelocidade(int d, int t) { // NÃO COMPILA - método static não pode ser declarado abstract return d / t; } } 7. Se uma classe implementa duas interfaces que possuem métodos default repetidos, ela obrigatoriamente deve implementar o seu próprio. 25 src/org/j6toj8/languageenhancements/staticdefaultininterfaces/StaticDefaultInInterfaces_RepeatedDefa ult.java interface Corredor { default String correr() { return "Correndo"; } } interface Piloto { default String correr() { return "Piloto Correndo"; } } static class Pessoa implements Corredor, Piloto { // NÃO COMPILA - implementa duas interfaces com métodos repetidos e não sobrescreve } static class Gigante implements Corredor, Piloto { // COMPILA - implementa duas interfaces com métodos repetidos, mas sobrescreve e cria sua própria implementação @Override public String correr() { return "Gigante Correndo"; } } 8. Ao implementar múltiplas interfaces, é possível acessar a implementação default de uma delas. 26 src/org/j6toj8/languageenhancements/staticdefaultininterfaces/StaticDefaultInInterfaces_RepeatedDefa ultSuper.java interface Corredor { default String correr() { return "Correndo"; } } interface Piloto { default String correr() { return "Piloto Correndo"; } } static class Pessoa implements Corredor, Piloto { // COMPILA - mantém a implementação do Corredor no método correr() @Override public String correr() { return Corredor.super.correr(); } public static void main(String[] args) { System.out.println(new Pessoa().correr()); } } Saída no console Correndo 9. Quando uma interface herda de outra interface métodos default, estes podem ser mantidos, transformados em abstract ou redefinidos. 27 src/org/j6toj8/languageenhancements/staticdefaultininterfaces/StaticDefaultInInterfaces_InterfaceInher itance.java interface Corredor { default String correr() { return "Correndo"; } default String correrRapido() { return "Correndo Rápido"; } default String correrDevagar() { return "Correndo Devagar"; } } interface Piloto extends Corredor { String correrRapido(); default String correrDevagar() { return "Piloto Correndo Devagar"; } } Nesse exemplo, a interface Piloto herda de Corredor e mostra 3 cenários distintos: ◦ Mantém o método correr() inalterado; ◦ Altera o método correrRapido() para que seja abstract, fazendo com que qualquer classe que implemente a interface Piloto tenha que implementar esse método; ◦ Altera o método correrDevagar() para que tenha sua própria implementação Referências • Designing an Interface Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 48). Wiley. Edição do Kindle. • Static and Default Methods in Interfaces in Java. • Default Methods. Java Documentation. 28 https://www.baeldung.com/java-static-default-methods https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html Localization Localização (Locale) Objetivo Describe the advantages of localizing an application and developing code that defines, reads, and sets the locale with a Locale object. - Descrever as vantagens de localizar uma aplicação e desenvolver código que defina, leia e aplique a localidade em um objeto Locale. É esperado que o candidato saiba compreender e analisar aspectos de Internacionalização e Localização, incluindo o uso da da classe Locale. Alguns aspectos de uma aplicação podem depender do país e da linguagem. Por exemplo: • Formatos de escrita de data ◦ O dia 6 de Agosto de 2019 seria representado no Brasil por 06/08/2019, porém nos EUA seria 08/06/2019. • Formatos de escrita de valores monetários ◦ Dez Reais no Brasil seriam representados por R$ 10, enquanto na França Dez Euros seriam 10 €. • Formatos de separação de casas decimais ou milhares ◦ No Brasil utiliza-se vírgula para separar decimais e pontos para milhares: 100.245,03. Nos EUA, utiliza-se o inverso: 100,245.03. Por isso, para que sua aplicação lide corretamente com esses cenários, é necessário compreender dois aspectos: Internacionalização (Internationalization) e Localização (Localization). A Internacionalização, também chamada de i18n, é o ato de projetar sua aplicação para que seja possível facilmente adaptá-la para utilizar novos formatos e idiomas. A Localização, também chamada de l10n, é o ato de adaptar sua aplicação para de fato utilizar um novo formato específico. Antes de continuar, entenda a execução do método main no exemplo a seguir e o que é apresentado no console após sua execução. 29 src/org/j6toj8/localization/locale/Locale_Complete.java public static void main(String[] args) throws IOException { System.out.println(" - Constantes - "); System.out.println(Locale.CANADA); System.out.println(Locale.UK); System.out.println(" - Construtor - "); System.out.println(new Locale("pt", "BR")); System.out.println(new Locale("pt", "PT")); System.out.println(new Locale("ca", "ES", "VALENCIA")); System.out.println(" - Language Tags - "); System.out.println(Locale.forLanguageTag("en-CA")); System.out.println(Locale.forLanguageTag("pt-BR")); System.out.println(Locale.forLanguageTag("pt-PT")); System.out.println(Locale.forLanguageTag("ca-ES")); System.out.println(Locale.forLanguageTag("gsw-u-sd-chzh")); System.out.println(" - Builder - "); Locale locale1 = new Locale.Builder() .setLanguage("pt") .setRegion("BR") .build(); System.out.println(locale1); Locale locale2 = new Locale.Builder() .setLanguage("az") .setRegion("AZ") .setScript("Latn") .build(); System.out.println(locale2); Locale locale3 = new Locale.Builder() .setLanguage("bs") .setRegion("BA") .setVariant("POSIX") .setScript("Latn") .setExtension('c', "cc") .build(); System.out.println(locale3); } 30 Saída no console - Constantes - en_CA en_GB - Construtor - pt_BR pt_PT ca_ES_VALENCIA - Language Tags - en_CA pt_BR pt_PT ca_ES gsw__#u-sd-chzh - Builder - pt_BR az_AZ_#Latn bs_BA_POSIX_#Latn_c-cc No Java, a classe Locale no pacote java.util nos ajuda a lidar com esses aspectos. 1. Geralmente, um Locale é representado por um idioma e um país. ◦ pt_BR - Português do Brasil ◦ en_US - Inglês dos EUA ◦ it_CH - Italiano da Suíça ◦ fr_BE - Francês da Bélgica src/org/j6toj8/localization/locale/Locale_LocaleLanguageCountry.java new Locale("pt", "BR"); // Português do Brasil new Locale("en", "US"); // Inglês dos EUA new Locale("it", "CH"); // Italiano da Suíça new Locale("fr", "BE"); // Francês da Bélgica 2. Um Locale pode ter ainda uma Variante, um Script e Extensões. 31 src/org/j6toj8/localization/locale/Locale_VarScriptExtension.java public static void main(String[] args) throws IOException { Locale locale2 = new Locale.Builder() // az_AZ_#Latn .setLanguage("az") .setRegion("AZ") .setScript("Latn") .build(); Locale locale3 = new Locale.Builder() // bs_BA_POSIX_#Latn_c-cc .setLanguage("bs") .setRegion("BA") .setVariant("POSIX") .setScript("Latn") .setExtension('c', "cc") .build(); } No exame da certificação, a Oracle geralmente só utiliza idioma e país. 3. É possível construir um Locale com o Builder, com construtores, ou por uma Language Tag. src/org/j6toj8/localization/locale/Locale_LocaleInstantiation.java public static void main(String[] args) throws IOException { new Locale("pt", "BR"); // pt-BR com Construtor Locale.forLanguageTag("pt-BR"); // pt-BR comLanguageTag Locale localePtBR = new Locale.Builder() // pt-BR com Builder .setLanguage("pt") .setRegion("BR") .build(); } A diferença entre eles é: ◦ Com os construtores é possível passar apenas o idioma, a região (país) e uma variante. ◦ Com language tags é possível passar uma String no padrão IETF BCP 47. ◦ Com o builder é possível criar da forma mais específica possível: idioma, região, variante, script e extensões. 4. O Locale aceita letras maiúsculas e minúsculas escritas de forma incorreta. 32 https://en.wikipedia.org/wiki/IETF_language_tag src/org/j6toj8/localization/locale/Locale_LocaleCase.java public static void main(String[] args) throws IOException { System.out.println(new Locale("PT", "br")); System.out.println(Locale.forLanguageTag("PT-br")); Locale localePtBR = new Locale.Builder() .setLanguage("PT") .setRegion("br") .build(); System.out.println(localePtBR); } Saída no console pt_BR pt_BR pt_BR Nesse exemplo, escrevemos de forma incorreta: ◦ O idioma deveria ser minúsculo (pt), mas está maiúsculo (PT). ◦ A região deveria estar maiúscula (BR), está minúscula (br). Mesmo assim, o Locale é criado corretamente. Veja que isso é um código ruim. O ideal é sempre escrever respeitando maiúsculas e minúsculas. 5. Existem algumas constantes na classe Locale para as localizações mais populares. src/org/j6toj8/localization/locale/Locale_LocaleCommons.java public static void main(String[] args) throws IOException { System.out.println(Locale.CANADA); System.out.println(Locale.CANADA_FRENCH); System.out.println(Locale.CHINA); System.out.println(Locale.CHINESE); System.out.println(Locale.ENGLISH); System.out.println(Locale.ITALY); System.out.println(Locale.SIMPLIFIED_CHINESE); System.out.println(Locale.TRADITIONAL_CHINESE); } 33 Saída no console en_CA fr_CA zh_CN zh en it_IT zh_CN zh_TW 6. É possível recuperar o Locale padrão ou alterá-lo programaticamente. src/org/j6toj8/localization/locale/Locale_LocaleDefault.java public static void main(String[] args) throws IOException { System.out.println(Locale.getDefault()); // o padrão inicial muda de acordo com seu dispositivo Locale.setDefault(Locale.KOREA); // altera o Locale default System.out.println(Locale.getDefault()); // ko_KR } Saída no console pt_BR ko_KR 7. É possível verificar os Locale disponíveis, pois eles variam de acordo com a JVM sendo executada. src/org/j6toj8/localization/locale/Locale_LocaleAvailable.java public static void main(String[] args) throws IOException { Locale[] availableLocales = Locale.getAvailableLocales(); // imprime o 10 primeiros Locales disponíveis for (int i = 0; i < 10; i++) { System.out.println(availableLocales[i]); } } 34 Saída no console nn ar_JO bg kea nds zu am_ET fr_DZ ti_ET 8. Um Locale também pode ser representado somente pelo idioma. src/org/j6toj8/localization/locale/Locale_LocaleLanguageOnly.java public static void main(String[] args) throws IOException { System.out.println(new Locale("pt")); // português System.out.println(new Locale("en")); // inglês System.out.println(new Locale("es")); // espanhol System.out.println(new Locale("fr")); // francês } Saída no console pt en es fr Referências • Adding Internationalization and Localization Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 255). Wiley. Edição do Kindle. • Internationalization and Localization in Java 8. • Internationalization. Java Documentation. • i18n vs l10n — what’s the diff? • Internationalization: Understanding Locale in the Java Platform. Pacote de Recursos (Resource Bundle) 35 https://www.baeldung.com/java-8-localization https://docs.oracle.com/javase/tutorial/i18n/intro/index.html https://blog.mozilla.org/l10n/2011/12/14/i18n-vs-l10n-whats-the-diff/ http://www.oracle.com/us/technologies/java/locale-140624.html Objetivo Build a resource bundle for a locale and call a resource bundle from an application. - Construa um resource bundle (conjunto de recursos) para um Locale e invoque um resource bundle a partir de uma aplicação. É esperado que o candidato saiba compreender e analisar o uso de resource bundles e sua relação com a classe Locale. Ao codificar uma aplicação com internacionalização é comum o uso de resource bundles, ou "conjunto de recursos" em português. São arquivos, geralmente .properties ou classes Java, que armazenam Strings. Cada arquivo contém Strings em idiomas, ou Locales, diferentes. Antes de continuar, entenda a execução do método main no exemplo a seguir e o que é apresentado no console após sua execução. src/org/j6toj8/localization/resourcebundle/ResourceBundle_Complete.java public static void main(String[] args) { Locale.setDefault(new Locale("en", "US")); System.out.println("\n -- Locale padrão (en_US) -- "); ResourceBundle bundleDefault = ResourceBundle.getBundle("Text"); Set<String> keySetDefault = bundleDefault.keySet(); for (String string : keySetDefault) { System.out.println(string + " - " + bundleDefault.getString(string)); } System.out.println("\n -- Locale es_ES -- "); ResourceBundle bundleEsEs = ResourceBundle.getBundle("Text", new Locale("es", "ES")); Set<String> keySetEsEs = bundleEsEs.keySet(); for (String string : keySetEsEs) { System.out.println(string + " - " + bundleEsEs.getString(string)); } System.out.println("\n -- Locale pt_BR -- "); ResourceBundle bundlePtBr = ResourceBundle.getBundle("Text", new Locale("pt", "BR")); Set<String> keySetPtBr = bundlePtBr.keySet(); for (String string : keySetPtBr) { System.out.println(string + " - " + bundlePtBr.getString(string)); } } 36 ../../../resources/Text.properties phone=phone tripod tripod pen:pen keyboard=keyboard glass=glass sticker sticker paper:paper rubber rubber ../../../resources/Text_pt.properties paper = papel ../../../resources/Text_pt_BR.properties #arquivo do locale pt_BR pen=caneta ../../../resources/Text_es.properties keyboard=tec\ lado ../../../resources/Text_es_ES.properties !arquivo do locale es_ES glass=\tvaso 37 Saída no console -- Locale padrão (en_US) -- tripod - tripod keyboard - keyboard glass - glass paper - paper phone - phone rubber - rubber sticker - sticker pen - pen -- Locale es_ES -- tripod - tripod keyboard - teclado glass - vaso paper - paper phone - phone rubber - rubber sticker - sticker pen - pen -- Locale pt_BR -- tripod - tripod keyboard - keyboard glass - glass paper - papel phone - phone rubber - rubber pen - caneta sticker - sticker 1. O nome do Locale é o sufixo do nome do arquivo, e o resource bundle padrão não tem sufixo. Exemplos: ◦ Text.properties → Locale padrão ◦ Text_pt_BR.properties → Locale pt_BR ◦ Text_pt.properties → Locale pt ◦ Text_es_ES.properties → Locale es_ES ◦ Text_es.properties → Locale es 2. O arquivo .properties pode ser expresso com 3 separadores diferentes: = (igual), : (dois pontos) ou um espaço em branco. 38 ../../../resources/Text.properties phone=phone tripod tripod pen:pen keyboard=keyboard glass=glass sticker sticker paper:paper rubber rubber O mais comum é utilizar o = para separar as propriedades, mas as 3 funcionam da mesma forma. 3. Em arquivos .properties, linhas que começam com # ou ! são comentários. ../../../resources/Text_pt_BR.properties #arquivo do locale pt_BR pen=caneta ../../../resources/Text_es_ES.properties !arquivo do locale es_ES glass=\tvaso 4. Em arquivos .properties, apenas espaços no final da linha são considerados. ../../../resources/Text_pt.properties paper = papel Neste exemplo, não é possível ver, mas existem 3 espaços no final da linha. O resultado é o mesmo que escrever paper=papel{sp}{sp}{sp}. 5. Em arquivos .properties, se você terminar a linha com uma contrabarra, pode quebrar a linha. ../../../resources/Text_es.properties keyboard=tec\ lado Neste exemplo, seria o mesmo que escrever em uma única linha: keyboard=teclado. 6. Em arquivos .properties,você também pode usar os caracteres java como \t e \n. 39 ../../../resources/Text_es_ES.properties !arquivo do locale es_ES glass=\tvaso Neste exemplo, existe uma tabulação antes da palavra vaso. Você pode perceber no primeiro exemplo deste capítulo que a palavra vaso foi impressa no console com uma tabulação à esquerda. 7. Você pode recuperar todas as chaves e valores do resource bundle programaticamente. src/org/j6toj8/localization/resourcebundle/ResourceBundle_KeysProgrammatically.java public static void main(String[] args) { Locale.setDefault(new Locale("en", "US")); // Coloca o Locale en_US como padrão ResourceBundle bundle = ResourceBundle.getBundle("Text", new Locale("pt", "BR")); // Recupera o bundle 'Text' para o Locale pt_BR Set<String> keySet = bundle.keySet(); // Pega um Set com todas as chaves for (String key : keySet) { System.out.println(key + " - " + bundle.getString(key)); // Imprime "<chave> - <valor>" } } Saída no console tripod - tripod keyboard - keyboard glass - glass paper - papel phone - phone rubber - rubber pen - caneta sticker - sticker 8. O resource bundle também pode ser uma classe Java. 40 resource/Text_fr_CA.java import java.util.ListResourceBundle; public class Text_fr_CA extends ListResourceBundle { @Override protected Object[][] getContents() { return new Object[][] { {"pen", "stylo"}, {"glass", "verre"}, {"keyboard", "clavier"} }; } } src/org/j6toj8/localization/resourcebundle/ResourceBundle_JavaBundle.java ResourceBundle bundle = ResourceBundle.getBundle("Text", new Locale("fr", "CA")); System.out.println(bundle.getString("glass")); Saída no console verre 9. Ao utilizar classes Java, uma vantagem é poder armazenar valores que não sejam apenas String. resource/Text_fr_FR.java import java.math.BigDecimal; import java.util.ListResourceBundle; public class Text_fr_FR extends ListResourceBundle { @Override protected Object[][] getContents() { return new Object[][] { {"ten", new BigDecimal("10")} }; } } 10. A nomenclatura do arquivo é a mesma para classes Java e arquivos .properties, mudando apenas a extensão. Veja que os arquivos .properties se chamam Text_xx_XX.properties, e os arquivos .java se chamam Text_xx_XX.java. Programaticamente, ambos são utilizados da mesma forma. 41 11. Se houver um arquivo .properties e uma classe Java para o mesmo Locale, a classe Java é utilizada. resource/Text_fr_CA.java import java.util.ListResourceBundle; public class Text_fr_CA extends ListResourceBundle { @Override protected Object[][] getContents() { return new Object[][] { {"pen", "stylo"}, {"glass", "verre"}, {"keyboard", "clavier"} }; } } resource/Text_fr_CA.properties pen=stylo-in-ignored-properties glass=stylo-in-ignored-properties keyboard=stylo-in-ignored-properties src/org/j6toj8/localization/resourcebundle/ResourceBundle_JavaClassTakesPrecedence.java /* * Recupera o Bundle do arquivo "Text_fr_CA.java", * pois tem precedência sobre o arquivo "Text_fr_CA.properties" */ ResourceBundle bundle = ResourceBundle.getBundle("Text", new Locale("fr", "CA")); System.out.println(bundle.getString("pen")); System.out.println(bundle.getString("glass")); System.out.println(bundle.getString("keyboard")); Saída no console stylo verre clavier Veja que os valores apresentados no console são aqueles definidos no arquivo Text_fr_CA.java, mostrando que a classe Java tem precedência sobre um arquivo .properties para o mesmo Locale. 12. Ao buscar por um resource bundle, o Java tenta encontrar um arquivo com o Locale exato. Se não encontrar, busca na seguinte ordem: 42 a. Um arquivo do mesmo idioma, mas sem o país; b. Um arquivo do Locale padrão; c. Um arquivo do Locale padrão, mas sem o país; d. Um arquivo sem Locale, que é o resource bundle padrão; e. Lança MissingResourceException caso não encontre. Por exemplo, ao executar a aplicação com o Locale padrão en_US, e solicitar um Locale pt_BR, a ordem de busca do resource bundle seria a seguinte: i. Text_pt_BR → Locale exato ii. Text_pt → Locale solicitado, sem o país iii. Text_en_US → Locale padrão iv. Text_en → Locale padrão, sem o país v. Text → Resource Bundle padrão src/org/j6toj8/localization/resourcebundle/ResourceBundle_NotExactLocale.java Locale.setDefault(new Locale("pt", "BR")); // pt_BR como Locale padrão ResourceBundle bundle2 = ResourceBundle.getBundle("Text", new Locale("zh", "CN")); System.out.println(bundle2.getLocale()); // Bundle localizado para o Locale "zh_CH" (Chinês simplificado) ResourceBundle bundle = ResourceBundle.getBundle("Text", new Locale("it", "CH")); System.out.println(bundle.getLocale()); // Bundle localizado para o Locale "it_CH" (Italiano da Suíça) Saída no console pt_BR it Veja que o Locale padrão é pt_BR. Por isso ele foi utilizado ao solicitar um resource bundle para zh_CN, pois não existe um bundle para esse Locale. Por outro lado, ao solicitar um resource bundle para o Locale it_CH, ele encontrou o mais próximo, que seria o Locale it, mas sem um país específico. 13. Os arquivos mais específicos herdam as chaves e valores de arquivos mais genéricos, caso eles não as tenham. 43 src/org/j6toj8/localization/resourcebundle/ResourceBundle_Inheritance.java Locale.setDefault(new Locale("en", "US")); // pt_BR como Locale padrão ResourceBundle bundle = ResourceBundle.getBundle("Text", new Locale("pt", "BR")); System.out.println("Locale: " + bundle.getLocale()); // Bundle localizado para o Locale "pt_BR" (Português do Brasil) System.out.println(bundle.getObject("pen")); System.out.println(bundle.getObject("paper")); System.out.println(bundle.getObject("keyboard")); ../../../resources/Text.properties phone=phone tripod tripod pen:pen keyboard=keyboard glass=glass sticker sticker paper:paper rubber rubber ../../../resources/Text_pt.properties paper = papel ../../../resources/Text_pt_BR.properties #arquivo do locale pt_BR pen=caneta Saída no console Locale: pt_BR caneta papel keyboard Veja que nesse exemplo foi localizado um resource bundle com o Locale exato pt_BR. Porém, nem todas as chaves foram encontradas nesse arquivo: ◦ caneta foi localizado no arquivo Text_pt_BR.properties ◦ papel foi localizado no arquivo Text_pt.properties ◦ keyboard foi localizado no arquivo Text.properties 44 Referências • Using a Resource Bundle Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 258). Wiley. Edição do Kindle. • A Guide to the ResourceBundle. • Class ResourceBundle. Java Documentation. • About the ResourceBundle Class. Java Documentation. Data e Hora Objetivo Create and manage date- and time-based events by using LocalDate, LocalTime, LocalDateTime, Instant, Period, and Duration, including a combination of date and time in a single object. - Crie e gerencie eventos baseados em data e hora utilizando LocalDate, LocalTime, LocalDateTime, Instant, Period, e Duration, incluindo combinação de data e hora em um único objeto. O Java 8 possui uma forma totalmente nova de lidar com data e hora. Várias classes novas foram introduzidas no pacote java.time.*. Vejamos a seguir alguns exemplos no formado ISO-8601. • LocalDate → Data sem fuso horário, como 2007-12-03. • LocalTime → Hora sem fuso horário, como 10:15:30.125. • LocalDateTime → Uma data com hora sem fuso horário, como 2007-12-03T10:15:30.125. • ZonedDateTime → Uma data com hora e com fuso horário, como 2007-12-03T10:15:30.125+01:00 Europe/Paris. • Instant → Um ponto na linha do tempo, um instante. • Period → Uma quantidade de tempo baseado em data, como "2 anos, 3 meses and 4 dias". • Duration → Uma quantidade de tempo baseado em hora, como "34,5 segundos". Essas novas classes foram melhor projetadas para lidar com os conceitos de data, hora e tempo. As classes antigas, java.util.Date e java.util.Calendar, não caem na prova de certificação.Quase todas essas classes serão apresentadas nessa seção. A única exceção é ZonedDateTime, que será apresentada na seção de fusos horários e horário de verão. Todas as novas classes são imutáveis e thread safe. Ou seja, não é necessário se preocupar com concorrência. 45 https://www.baeldung.com/java-resourcebundle https://docs.oracle.com/javase/7/docs/api/java/util/ResourceBundle.html https://docs.oracle.com/javase/tutorial/i18n/resbundle/concept.html https://pt.wikipedia.org/wiki/Objeto_imut%C3%A1vel https://pt.wikipedia.org/wiki/Thread_safety LocalDate Um LocalDate representa uma data sem fuso horário, como 2007-12-03. 1. A prova geralmente irá utilizar datas no formato americano: mes/dia/ano. 2. É possível criar um LocalDate através do método static chamado now. src/org/j6toj8/localization/datetime/localdate/LocalDate_Now.java System.out.println(LocalDate.now()); Saída no console 2019-05-20 A saída no console irá apresentar a data atual. 3. Também é possível criar um LocalDate através do método static chamado of. 4. Você pode utilizar o enum Month ou um int para representar o mês. 5. Diferente das APIs antigas do Java, o mês agora começa no número 1, que é Janeiro. src/org/j6toj8/localization/datetime/localdate/LocalDate_Of.java System.out.println(LocalDate.of(2019, 5, 20)); System.out.println(LocalDate.of(2019, Month.MAY, 20)); Saída no console 2019-05-20 2019-05-20 6. Assim como todas a novas classes de data e hora, não é possível criar uma instância de LocalDate utilizando o construtor. src/org/j6toj8/localization/datetime/localdate/LocalDate_Constructor.java LocalDate localDate = new LocalDate(); // NÃO COMPILA! - não possui construtor padrão System.out.println(localDate); 7. Será lançada a exceção DateTimeException ao tentar criar uma data inválida. src/org/j6toj8/localization/datetime/localdate/LocalDate_Invalid.java System.out.println(LocalDate.of(2019, Month.MAY, 33)); 46 Saída no console Exception in thread "main" java.time.DateTimeException: Invalid value for DayOfMonth (valid values 1 - 28/31): 33 at java.time.temporal.ValueRange.checkValidValue(ValueRange.java:311) at java.time.temporal.ChronoField.checkValidValue(ChronoField.java:703) at java.time.LocalDate.of(LocalDate.java:248) at org.j6toj8.localization.datetime.localdate.LocalDate_Invalid.main(LocalDate_Invalid .java:10) 8. Existem vários métodos para somar e subtrair de LocalDate. src/org/j6toj8/localization/datetime/localdate/LocalDate_Manipulate.java LocalDate localDate = LocalDate.of(2019, Month.MAY, 20); System.out.println(localDate); System.out.println("+2 dias: " + localDate.plusDays(2)); System.out.println("+2 semanas: " + localDate.plusWeeks(2)); System.out.println("+2 meses: " + localDate.plusMonths(2)); System.out.println("+2 anos: " + localDate.plusYears(2)); System.out.println("+2 décadas: " + localDate.plus(2, ChronoUnit.DECADES)); System.out.println("-2 dias: " + localDate.minusDays(2)); System.out.println("-2 semanas: " + localDate.minusWeeks(2)); System.out.println("-2 meses: " + localDate.minusMonths(2)); System.out.println("-2 anos: " + localDate.minusYears(2)); System.out.println("-2 décadas: " + localDate.minus(2, ChronoUnit.DECADES)); Saída no console 2019-05-20 +2 dias: 2019-05-22 +2 semanas: 2019-06-03 +2 meses: 2019-07-20 +2 anos: 2021-05-20 +2 décadas: 2039-05-20 -2 dias: 2019-05-18 -2 semanas: 2019-05-06 -2 meses: 2019-03-20 -2 anos: 2017-05-20 -2 décadas: 1999-05-20 9. LocalDate é imutável, então é necessário armazenar o retorno de uma alteração em uma variável. 47 src/org/j6toj8/localization/datetime/localdate/LocalDate_Immutability.java LocalDate localDate = LocalDate.of(2019, Month.MAY, 20); System.out.println(localDate); localDate.plusDays(1); // chamada perdida - a nova data não foi armazenada em uma variável System.out.println(localDate); localDate = localDate.plusDays(1); // chamada útil - data armazenada na variável System.out.println(localDate); Saída no console 2019-05-20 2019-05-20 2019-05-21 10. É comum utilizar o encadeamento de chamadas com esses métodos. src/org/j6toj8/localization/datetime/localdate/LocalDate_Chaining.java LocalDate localDate = LocalDate.of(2019, Month.MAY, 20); System.out.println(localDate); System.out.println(localDate.plusDays(1).plusMonths(1).plusYears(1)); Saída no console 2019-05-20 2020-06-21 11. Ao manipular a data, o LocalDate irá manipular os meses e anos conforme necessário. src/org/j6toj8/localization/datetime/localdate/LocalDate_AdjustDifferentUnit.java LocalDate localDate = LocalDate.of(2019, Month.NOVEMBER, 30); System.out.println(localDate); System.out.println(localDate.plusDays(1)); // + 1 dia, vira o mês System.out.println(localDate.plusDays(32)); // + 32 dias, vira o ano System.out.println(localDate.plusMonths(2)); // + 2 meses, vira o ano Saída no console 2019-11-30 2019-12-01 2020-01-01 2020-01-30 48 LocalTime Um LocalTime representa uma hora sem fuso horário e sem data, como 10:15:30.125. 1. A hora é representada no formato hora:minuto:segundo.nano. 2. É possível criar um LocalTime através do método static chamado now. src/org/j6toj8/localization/datetime/localtime/LocalTime_Now.java System.out.println(LocalTime.now()); Saída no console 09:15:23.197 A saída no console irá apresentar a hora atual. 3. Também é possível criar um LocalTime através do método static chamado of. src/org/j6toj8/localization/datetime/localtime/LocalTime_Of.java System.out.println(LocalTime.of(9, 20, 1, 135000000)); System.out.println(LocalTime.of(9, 20, 1, 135)); System.out.println(LocalTime.of(9, 20, 1)); System.out.println(LocalTime.of(9, 20)); Saída no console 09:20:01.135 09:20:01.000000135 09:20:01 09:20 4. Assim como todas a novas classes de data e hora, não é possível criar uma instância de LocalTime utilizando o construtor. src/org/j6toj8/localization/datetime/localtime/LocalTime_Constructor.java LocalTime localTime = new LocalTime(); // NÃO COMPILA! - não possui construtor padrão System.out.println(localTime); 5. Será lançada a exceção DateTimeException ao tentar criar uma hora inválida. 49 src/org/j6toj8/localization/datetime/localtime/LocalTime_Invalid.java System.out.println(LocalTime.of(24, 2, 3)); // lança exceção: a hora deve estar entre 0 e 23 Saída no console Exception in thread "main" java.time.DateTimeException: Invalid value for HourOfDay (valid values 0 - 23): 24 at java.time.temporal.ValueRange.checkValidValue(ValueRange.java:311) at java.time.temporal.ChronoField.checkValidValue(ChronoField.java:703) at java.time.LocalTime.of(LocalTime.java:317) at org.j6toj8.localization.datetime.localtime.LocalTime_Invalid.main(LocalTime_Invalid .java:9) 6. Existem vários métodos para somar e subtrair de LocalTime. src/org/j6toj8/localization/datetime/localtime/LocalTime_Manipulate.java LocalTime localTime = LocalTime.of(9, 26, 12); System.out.println(localTime); System.out.println("+2 horas: " + localTime.plusHours(2)); System.out.println("+2 minutos: " + localTime.plusMinutes(2)); System.out.println("+2 segundos: " + localTime.plusSeconds(2)); System.out.println("+2 nanosegundos: " + localTime.plusNanos(2)); System.out.println("+2 microssegundos: " + localTime.plus(2, ChronoUnit.MICROS)); System.out.println("+2 milissegundos: " + localTime.plus(2, ChronoUnit.MILLIS)); System.out.println("-2 horas: " + localTime.minusHours(2)); System.out.println("-2 minutos: " + localTime.minusMinutes(2)); System.out.println("-2 segundos: " + localTime.minusSeconds(2)); System.out.println("-2 nanosegundos: " + localTime.minusNanos(2)); System.out.println("-2 microssegundos: " + localTime.minus(2, ChronoUnit.MICROS)); System.out.println("-2 milissegundos: " + localTime.minus(2, ChronoUnit.MILLIS)); 50 Saída no console 09:26:12 +2 horas: 11:26:12 +2 minutos: 09:28:12 +2 segundos: 09:26:14 +2 nanosegundos: 09:26:12.000000002 +2 microssegundos: 09:26:12.000002 +2 milissegundos: 09:26:12.002 -2 horas: 07:26:12 -2 minutos: 09:24:12 -2 segundos: 09:26:10 -2 nanosegundos:09:26:11.999999998 -2 microssegundos: 09:26:11.999998 -2 milissegundos: 09:26:11.998 7. LocalTime é imutável, então é necessário armazenar o retorno de uma alteração em uma variável. src/org/j6toj8/localization/datetime/localtime/LocalTime_Immutability.java LocalTime localTime = LocalTime.of(9, 31, 5); System.out.println(localTime); localTime.plusHours(1); // chamada perdida - a nova hora não foi armazenada em uma variável System.out.println(localTime); localTime = localTime.plusHours(1); // chamada útil - hora armazenada na variável System.out.println(localTime); Saída no console 09:31:05 09:31:05 10:31:05 8. É comum utilizar o encadeamento de chamadas com esses métodos. src/org/j6toj8/localization/datetime/localtime/LocalTime_Chaining.java LocalTime localTime = LocalTime.of(9, 32, 5); System.out.println(localTime); System.out.println(localTime.plusHours(1).plusMinutes(1).plusSeconds(1).plusNanos(1 000000)); Saída no console 09:32:05 10:33:06.001 51 9. Ao manipular a hora, o LocalTime irá manipular as horas, minutos e segundos conforme necessário. src/org/j6toj8/localization/datetime/localtime/LocalTime_AdjustDifferentUnit.java LocalTime localTime = LocalTime.of(9, 59, 59); System.out.println(localTime); System.out.println(localTime.plusSeconds(2)); // + 2 segundos, vira o minuto System.out.println(localTime.plusSeconds(62)); // + 62 segundos, vira a hora System.out.println(localTime.plusMinutes(2)); // + 2 minutos, vira a hora System.out.println(localTime.minusNanos(1000000000)); // - 1 segundo (em nanos), vira o minuto Saída no console 09:59:59 10:00:01 10:01:01 10:01:59 09:59:58 LocalDateTime Um LocalDateTime representa uma data com hora, mas sem fuso horário, como 2007-12- 03T10:15:30.125. As regras para o LocalDateTime são basicamente a junção daquelas para LocalDate e LocalTime. 1. O LocalDateTime é apresentado no formato ano-mes-diaThora:minuto:segundo.nano. 2. É possível criar um LocalDateTime através do método static chamado now. src/org/j6toj8/localization/datetime/localdatetime/LocalDateTime_Now.java System.out.println(LocalDateTime.now()); Saída no console 2019-05-24T10:13:58.370 A saída no console irá apresentar a data e hora atual. 3. Também é possível criar um LocalDateTime através do método static chamado of. 52 src/org/j6toj8/localization/datetime/localdatetime/LocalDateTime_Of.java System.out.println(LocalDateTime.of(LocalDate.of(2019, 5, 20), LocalTime.of(9, 20, 12))); System.out.println(LocalDateTime.of(2019, 5, 20, 9, 20)); System.out.println(LocalDateTime.of(2019, Month.MAY, 20, 9, 20)); System.out.println(LocalDateTime.of(2019, 5, 20, 9, 20, 12)); System.out.println(LocalDateTime.of(2019, Month.MAY, 20, 9, 20, 12)); System.out.println(LocalDateTime.of(2019, 5, 20, 9, 20, 12, 135)); System.out.println(LocalDateTime.of(2019, Month.MAY, 20, 9, 20, 12, 135)); Saída no console 2019-05-20T09:20:12 2019-05-20T09:20 2019-05-20T09:20 2019-05-20T09:20:12 2019-05-20T09:20:12 2019-05-20T09:20:12.000000135 2019-05-20T09:20:12.000000135 4. Assim como todas a novas classes de data e hora, não é possível criar uma instância de LocalDateTime utilizando o construtor. src/org/j6toj8/localization/datetime/localdatetime/LocalDateTime_Constructor.java LocalDateTime localDateTime = new LocalDateTime(); // NÃO COMPILA! - não possui construtor padrão System.out.println(localDateTime); 5. Será lançada a exceção DateTimeException ao tentar criar uma data ou hora inválida. src/org/j6toj8/localization/datetime/localdatetime/LocalDateTime_Invalid.java System.out.println(LocalDateTime.of(2019, 4, 31, 9, 20)); // lança exceção: não existe 31 de abril Saída no console Exception in thread "main" java.time.DateTimeException: Invalid date 'APRIL 31' at java.time.LocalDate.create(LocalDate.java:431) at java.time.LocalDate.of(LocalDate.java:269) at java.time.LocalDateTime.of(LocalDateTime.java:311) at org.j6toj8.localization.datetime.localdatetime.LocalDateTime_Invalid.main(LocalDate Time_Invalid.java:10) 6. Existem vários métodos para somar e subtrair de LocalDateTime. São basicamente todos os 53 disponíveis para LocalDate e LocalTime. src/org/j6toj8/localization/datetime/localdatetime/LocalDateTime_Manipulate.java LocalDateTime localDateTime = LocalDateTime.of(2019, 5, 20, 9, 20, 12); System.out.println(localDateTime); System.out.println("+2 horas: " + localDateTime.plusHours(2)); System.out.println("+2 minutos: " + localDateTime.plusMinutes(2)); System.out.println("+2 segundos: " + localDateTime.plusSeconds(2)); System.out.println("+2 nanosegundos: " + localDateTime.plusNanos(2)); System.out.println("+2 microssegundos: " + localDateTime.plus(2, ChronoUnit. MICROS)); System.out.println("+2 milissegundos: " + localDateTime.plus(2, ChronoUnit. MILLIS)); System.out.println("-2 horas: " + localDateTime.minusHours(2)); System.out.println("-2 minutos: " + localDateTime.minusMinutes(2)); System.out.println("-2 segundos: " + localDateTime.minusSeconds(2)); System.out.println("-2 nanosegundos: " + localDateTime.minusNanos(2)); System.out.println("-2 microssegundos: " + localDateTime.minus(2, ChronoUnit. MICROS)); System.out.println("-2 milissegundos: " + localDateTime.minus(2, ChronoUnit. MILLIS)); System.out.println("+2 dias: " + localDateTime.plusDays(2)); System.out.println("+2 semanas: " + localDateTime.plusWeeks(2)); System.out.println("+2 meses: " + localDateTime.plusMonths(2)); System.out.println("+2 anos: " + localDateTime.plusYears(2)); System.out.println("+2 décadas: " + localDateTime.plus(2, ChronoUnit.DECADES)); System.out.println("-2 dias: " + localDateTime.minusDays(2)); System.out.println("-2 semanas: " + localDateTime.minusWeeks(2)); System.out.println("-2 meses: " + localDateTime.minusMonths(2)); System.out.println("-2 anos: " + localDateTime.minusYears(2)); System.out.println("-2 décadas: " + localDateTime.minus(2, ChronoUnit.DECADES)); 54 Saída no console 2019-05-20T09:20:12 +2 horas: 2019-05-20T11:20:12 +2 minutos: 2019-05-20T09:22:12 +2 segundos: 2019-05-20T09:20:14 +2 nanosegundos: 2019-05-20T09:20:12.000000002 +2 microssegundos: 2019-05-20T09:20:12.000002 +2 milissegundos: 2019-05-20T09:20:12.002 -2 horas: 2019-05-20T07:20:12 -2 minutos: 2019-05-20T09:18:12 -2 segundos: 2019-05-20T09:20:10 -2 nanosegundos: 2019-05-20T09:20:11.999999998 -2 microssegundos: 2019-05-20T09:20:11.999998 -2 milissegundos: 2019-05-20T09:20:11.998 +2 dias: 2019-05-22T09:20:12 +2 semanas: 2019-06-03T09:20:12 +2 meses: 2019-07-20T09:20:12 +2 anos: 2021-05-20T09:20:12 +2 décadas: 2039-05-20T09:20:12 -2 dias: 2019-05-18T09:20:12 -2 semanas: 2019-05-06T09:20:12 -2 meses: 2019-03-20T09:20:12 -2 anos: 2017-05-20T09:20:12 -2 décadas: 1999-05-20T09:20:12 7. LocalDateTime é imutável, então é necessário armazenar o retorno de uma alteração em uma variável. src/org/j6toj8/localization/datetime/localdatetime/LocalDateTime_Immutability.java LocalDateTime localDateTime = LocalDateTime.of(2019, 5, 20, 9, 20); System.out.println(localDateTime); localDateTime.plusHours(1); // chamada perdida - a nova data/hora não foi armazenada em uma variável System.out.println(localDateTime); localDateTime = localDateTime.plusHours(1); // chamada útil - data/hora armazenada na variável System.out.println(localDateTime); Saída no console 2019-05-20T09:20 2019-05-20T09:20 2019-05-20T10:20 8. É comum utilizar o encadeamento de chamadas com esses métodos. 55 src/org/j6toj8/localization/datetime/localdatetime/LocalDateTime_Chaining.java LocalDateTime localDateTime = LocalDateTime.of(2019, 5, 20, 9, 20); System.out.println(localDateTime); System.out.println(localDateTime.plusDays(1).plusHours(1).plusYears(1)); Saída no console 2019-05-20T09:20 2020-05-21T10:20 9. Ao manipular a data ou hora, o LocalDateTime irá manipular os outros campos conforme necessário. src/org/j6toj8/localization/datetime/localdatetime/LocalDateTime_AdjustDifferentUnit.java LocalDateTime localDateTime = LocalDateTime.of(2019, 12, 31, 23, 59, 59); System.out.println(localDateTime); System.out.println(localDateTime.plusSeconds(2));
Compartilhar