Docker - Manipulando Imagens

Olá pessoal hoje iremos começar uma série de tutoriais falando dos principais comandos que utilizamos em ambientes com Docker, e para começar vamos falar sobre imagens.


Começando com Docker


Aqui não vamos entrar em detalhes de instalação do Docker, mas vou deixar abaixo links para tutoriais que explicam estes detalhes.


O Que são Imagens


As imagens são Templates para criação dos containers, nelas adicionamos informações sobre o SO, comandos de inicialização, entre outras configurações, para ficar mais claro oque são as imagens, podemos fazer uma analogia entre imagens x containers com classes x objetos em linguagens de programação orientadas a objetos como Java, Kotlin, etc.

Principais Comandos


Utilizando o help


O comando mais útil que teremos ao manipular Docker é o help, ele pode ser utilizando em vários níveis, sendo direto no image ou em um subcomando de image, ele irá fornecer detalhes sobre como o comando deve ser executado, atributos, sintaxe, etc:

docker image --help

docker image <comando> --help


docker image --help

docker image build --help

Criando uma imagem


A criação de uma imagem consiste na leitura de um arquivo descritor contendo toda a sequência de camadas, com Docker este arquivo é o Dockerfile, na execução do comando build é importante que o arquivo Dockerfile esteja presente no diretório.

docker image build -t <<name_image>> .

Listando imagens


Podemos listar as imagens de diferentes formas, abaixo temos os diferentes comandos que podem ser utilizados, como resultado teremos a lista de imagens presentes em seu ambiente:

docker images
 
docker image list
  
docker image ls

Resultado da execução do docker images.

Procurando novas imagens


Este comando é bem interessante porque ele retorna as imagens encontradas no repositório que coincidem com a palavra procurada.

docker search <<palavra chave>>

Abaixo executamos o search procurando por node:

Resultado da procura por node.

Download de novas imagens

O comando pull serve para baixar uma imagem do repositório para nosso ambiente local, aqui vale ressaltar que uma imagem pode conter diferentes tags, com isso devemos especificar no comando qual tag gostaríamos, caso a tag não seja especificada, o padrão será o download da tag latest.

docker pull <<nome_imagem:tag>>

Baixando a imagem do cassandra.

Removendo imagens


Para remover uma imagem do ambiente local podemos executar o comando abaixo:

docker image rm <ID ou nome_imagem>

Existem alguns momentos que podemos ter problemas com o rm, por exemplo:
  • Caso exista um container ativo criado a partir da imagem, não poderemos exclui-lá;
  • Caso tenhamos a mesma imagem no ambiente com versões diferentes, devemos passar a tag que gostaríamos de excluir: <ID ou nome_imagem>:<tag>



Informações sobre a imagem


Utilizamos este comando para exibir informações detalhadas sobre a imagem, o resultado será um JSON contendo um conjunto de informações, que podem ser utilizadas em ferramentas de gestão de ambiente, ou para detalhamento de como a imagem foi criada.

docker image inspect <ID ou nome_imagem>


Salvando uma imagem em arquivo TAR


Um recurso interessante mais pouco utilizado é a possibilidade de salvar a imagem em um arquivo TAR, dessa forma podemos levar nossa imagem para um outro ambiente como um arquivo compactado.

docker image save <ID ou nome_imagem> --output <destino do arquivo>

Ao executar: docker image save nginx:1.12-alpine --output c:\\nginx-1.12-alpine.tar, teremos a criação do arquivo nginx-1.12-alpine.tar


Importando uma imagem de um arquivo TAR


É possível importar um arquivo .TAR contendo uma imagem, aqui vamos executar a importação do nginx que geramos no exemplo anterior, teremos a criação da imagem no ambiente de acordo com o nome tag usadas no comando.


docker image import <caminho e nome_arquivo_tar> <nome_imagem:tag>

 Veja abaixo a listagem após executar o import com nginx:1.12-alpine

Listagem da imagem importada do arquivo TAR.


Conclusão


Existem uma porção de outros comandos que podemos utilizar para manipular imagens Docker, a grande vantagem de trabalhar com uma ferramenta completa como estaé sua vasta documentação, que contém praticamente todos os comandos e seus resultados muito bem detalhados.

Até a próxima.

Referências




Frameworks e Microframeworks para Java e Kotlin

Olá pessoal, hoje iremos ver alguns frameworks e microframeworks que ajudam no desenvolvimento ágil com Java e Kotlin.

A Evolução do Desenvolvimento para JVM


O desenvolvimento de software evoluiu muito nos últimos anos, e com isso a exigência por agilidade no desenvolvimento e na entrega aumentaram.

A Oracle esta desenvolvendo um trabalho interessante com a plataforma Java, tendo a cada 6 meses um novo release do Java SE (atualmente na versão 13), onde atualizações e novas features estão sendo adicionadas a plataforma.

O Java EE que agora é mantido pela Eclipse com o nome de Jakarta EE, também terá uma evolução muito mais ágil, voltados para arquiteturas modernas e com a evolução de várias especificações que são muito famosas no mundo Java Enterprise.

Temos também o Kotlin, que vem ganhando um espaço muito interessante no mercado, sendo uma linguagem com muitos recursos interessantes e fácil aprendizado, e além de possuir uma total interoperabilidade com Java, permitindo usar a linguagem em qualquer lugar onde rodamos Java.

A forma de desenvolver aplicações Enterprise mudou, as linguagens e as arquiteturas evoluíram, com isso os frameworks que utilizamos precisaram seguir o mesmo caminho, vamos ver uma lista de frameworks que trazem agilidade na criação de projetos para a JVM.


Os Frameworks e Microframeworks


O conceito de Microframeworks esta em alta, e isso se deve a adoção de modelos de arquiteturas onde os softwares são divididos em pequenas partes (Microservices), onde cada artefato é responsável por uma regra especifica, com isso não precisamos de grandes frameworks com muitos recursos para atender a esta demanda, podemos utilizar algo simples e que atenda aos requisitos daquela parte em questão.

Existem outros pontos que favorecem a adoção de frameworks considerados "micro", tais como:

  • Consumo de recursos
    • Por serem menores consumem menos recursos do ambiente (Memória, Processamento, etc);
  • Deployment
    • Os artefatos gerados são menores, pois os frameworks não possuem muitas dependências;
  • Curva de Aprendizado
    • Geralmente são simples de entender, pois a quantidade de código é reduzida, e eles resolvem um problema especifico.

Exemplos de Frameworks 


São tantos Fameworks e Microframeworks que temos disponíveis para JVM que a escolha acaba sendo complexa, onde temos que analisar prós e contras para conseguir tomar uma decisão adequada para a equipe e projeto.

Vamos listar abaixo alguns que são muito adotados pelo mercado, e são utilizados com Java ou Kotlin:


Como faço para escolher o framework correto?


A escolha de um framework para um projeto não á uma tarefa simples, pois envolve diversas situações, vamos criar uma lista de critérios para poder ajudar nessa decisão:

  • Necessidades do Projeto
    • Qual problema o projeto precisa resolver?
    • Quais são os requisitos funcionais e não funcionais que devo atender ?
  • Arquitetura utilizada
    • Utilizo uma arquitetura monolítica ou microservices ?
  • Recursos do Framework
    • O framework consegue atender a minha necessidade ? Por exemplo, irei utilizar programação reativa, websockets, etc.
  • Adoção pela comunidade e mercado
    • Analisar se o framework esta sendo adotado por outras empresas, quais cases já estão sendo resolvidos com a tecnologia, etc.
  • Evolução do framework
    • O framework tem uma evolução consistente, com novos releases, correção de bugs, etc.
  • Conhecimento da Equipe
    • Minha equipe possui conhecimento sobre o framework ?
  • Curva de aprendizado
    • Qual a curva de aprendizado para minha equipe ?

Estas são algumas das análises que podemos fazer para tomar uma decisão, mas vale lembra que cada empresa pode ter necessidades diferentes de acordo com os requisitos ou equipe.

Até a próxima.

Atualizando a lista de Timezone da JVM

Olá pessoal vamos falar sobre como atualizar a lista de Timezone da JVM.

O Problema da Mudança de Timezone


Devido uma mudança realizada pelo governo brasileiro, este ano não teremos o horário de verão, que mudava o GMT para -2 em algumas regiões do Pais, com isso, as configurações de Timezone dos servidores são ajustados para não realizar a mudança, mas alguns ambientes onde temos JVM podem acabar mudando e não seguindo o Timezone do S.O, pois a regra antiga ainda encontra-se configurada.

Ambiente Java 10 mudou com Timezone incorreto.

Acima instanciamos um objeto Date() a partir do JShell e notamos a diferença no horário, onde o correto seria exibir 11:05:31.


Lista de Timezone Atualizados


Como aconteceu aqui no Brasil, podem acontecer mudanças de Timezone em qualquer lugar (mesmo não sendo comum), quando ocorrem essas mudanças temos que recorrer a listas de Timezone atualizadas para que os ambientes possam funcionar corretamente.

No caso da JVM, a Oracle mantém a lista de Timezone baseada na IANA.

Para corrigir o nosso problema iremos utilizar a seguinte URL: https://www.iana.org/time-zones/repository/tzdata-latest.tar.gz, esta irá retornar a ultima lista atualizada de Timezones.

A Ferramenta TZUpdater


A Oracle disponibiliza uma ferramenta para atualizar a lista de Timezone chamada TZUpdater, esta é um arquivo jar que deve ser executado passando a lista de atualização como parâmetro.


Realizando a execução


Para executar o utilitário devemos executar o seguinte comando:

java -jar tzupdater.jar  -l https://www.iana.org/time-zones/repository/tzdata-latest.tar.gz


Se tudo ocorrer corretamente o resultado será o seguinte:


Descritivo da execução do comando.

Obs: Vale lembrar que caso você tenha mais de uma JVM no ambiente, ao executar o comando java, a lista que será atualizada é a que for sua JAVA_HOME e estiver configurada em seu PATH, caso sua necessidade seja alterar de outras JVM, use o caminho absoluto, por exemplo: /opt/path_java/bin/java


Após a atualização vamos criar novamente um objeto Date:


Ambiente Java 10 com o Timezone correto.

Após a execução do tzupdater a lista foi alterada e o Timezone esta de acordo com as configurações Locais.

Referências


Skipping Tests, Profiles e Debug com Maven

Olá pessoal, hoje iremos ver alguns comandos utilitários no processo de build do Maven.

O Processo de Build

O Maven é uma ferramenta que trás muitos benefícios ao ambiente de desenvolvimento, com ele gerenciamos dependências, versionamento e configurações dos projetos.

Uma parte muito importante que devemos nos atentar é com o processo de build, este processo é composto pela execução de todo o ciclo de vida do Maven, execução dos plugins presentes no pom.xml e a criação do artefato final.

É comum nos depararmos com builds que demoram vários minutos para completar, caso seja o seu caso, existem algumas métricas que dizem que "um processo de build não deve demorar mais que 5 minutos".

Maven Skip Tests

A execução dos testes é algo fundamental em projetos de softwares, mas as vezes nos deparamos com cenários onde precisamos executar o processo de build e não executar o pipeline de testes, com Maven temos 3 maneiras de executar tal tarefa, sendo:


Plugin


<plugin>        
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-surefire-plugin</artifactId>
 <version>2.12.4</version>
 <configuration>
    <skipTests>true</skipTests>
 </configuration>
</plugin>

Linha de Comando


mvn install -DskipTests

Linha de Comando, evitando a compilação dos Testes


mvn install -Dmaven.test.skip=true

Maven Profiles

Profiles é algo que praticamente todos ambientes de desenvolvimento necessitam, isso porque é comum termos particularidade entre os ambientes de desenvolvimento, testes, homologação e produção.

No Maven temos os profiles de build, estes permitem que de acordo com o profile configurado, diferentes processos e plugins sejam executados, para executarmos profile devemos fazer o seguinte:

<profiles>
   <profile>
      <id>dev</id>
       <!-- Código do build -->
   </profile>
   <profile>
      <id>homolog</id>
      <!-- Código do build -->
   </profile>
   <profile>
      <id>prod</id>
      <!-- Código do build -->
   </profile>
<profiles>

Após termos a configuração no pom.xml, podemos executar informando qual profile queremos executar:

mvn package -P dev

Aqui podemos ver a flag -P esta determina qual profile queremos que nosso build execute.

Maven Debug

Uma coisa muito comum é realizar o debug de um processo de build, esta operação nos permite verificar cada execução do processo, analisando qual o fluxo de cada parte do build.

No Maven, o padrão é executar todo o processo como INFO, ou seja, apesar informações essenciais serão exibidas no console, para executar o build em modo debug podemos passar a flag -X, como o abaixo:

mvn package -X

Todas essas pequenas configurações que realizamos ajudam no processo de build, tornando mais simples encontrar bugs, executar diferentes processos e encontrar problemas de performance.

Até a próxima.

Referências


Analisando na Prática o uso de Primitivos e Wrappers

O uso de tipos primitivos e Wrappers é um tema que traz diversas discussões, inclusive existem vários tutorias que mostram a aplicabilidade de cada uma das estratégias em diferentes cenários.

As Classes Wrappers


As classes Wrappers são aquelas que representam os tipos primitivos da linguagem Java, há algum tempo existiam autores que falavam que Java não era uma linguagem 100% OO por tratar os tipos básicos como primitivos, mas isso acabou quando adicionaram os tipos Wrappers a linguagem.

O Wrappers são classes imutáveis, e possuem vários métodos utilitários que facilitam conversões, parses, formatação, entre outras funcionalidades bem utilizadas no dia a dia.

Vamos analisar cada tipo primitivo e sua representação em classe Wrapper:
  • byte
    • Byte;
  • short
    • Short;
  • int
    • Integer;
  • long
    • Long;
  • boolean
    • Boolean;
  • char
    • Character;
  • float
    • Float;
  • double
    • Double;

Comparação entre Wrappers


Vamos entender como esses objetos funcionam no quesito comparação, já analisei casos onde uma comparação de valores iguais não resultavam em true, vamos analisar alguns motivos para isso ocorrer:

 Integer oneWrapper = 1; //Autoboxing do valor <1> para a variavel oneWrapper
 Integer twoWrapper = 1; //Autoboxing do valor <1> para a variavel twoWrapper
  
 System.out.println(" Comparação de Wrappers \n");
 System.out.println(oneWrapper == twoWrapper);
 System.out.println(oneWrapper != twoWrapper);
 System.out.println(oneWrapper.equals(twoWrapper));

O Resultado do nosso código será o seguinte:
oneWrapper == twoWrapper : true
oneWrapper != twoWrapper : false
oneWrapper.equals(twoWrapper) : true

Para entender os resultado, vamos lembrar que quando criamos as variáveis do tipo Wrapper realizando a atribuição direta de um valor, o compilador realiza o autoboxing, que é a conversão de um tipo primitivo em tipo Wrapper.

Na primeira condição temos oneWrapper == twoWrapper, quando comparamos objetos com == a comparação acontece entre as referências dos objetos, e neste caso como as variáveis foram criadas através de atribuição direta, o valor 1 será reaproveitado do pool de objetos, assim as variáveis apontaram para o mesmo objeto em memória.

Na segunda condição temos oneWrapper != twoWrapper, aqui a explicação é a mesma da primeira.

Na terceira condição temos oneWrapper.equals(twoWrapper), quando aprendemos manipulação de objetos com Java, analisamos o método equals(), que é o método que utilizamos para analisar se um objeto é igual ao outrolembrando que os Wrappers são objetos, portanto o equals é a melhor forma de realizar a comparação.


Integer oneWrapper = 1; //Autoboxing do valor <1> para a variavel oneWrapper
Integer twoWrapper = new Integer(1); //Criação sem reaproveitar o objeto do pool
  
System.out.println(" Comparação de Wrappers com Instância direta \n");
System.out.println(oneWrapper == twoWrapper);
System.out.println(oneWrapper != twoWrapper);
System.out.println(oneWrapper.equals(twoWrapper));

O resultado será o seguinte:

oneWrapper == twoWrapper        : false
oneWrapper != twoWrapper         : true
oneWrapper.equals(twoWrapper) : true

Vamos entender o resultado, no primeiro exemplo é feita uma comparação entre 2 Wrappers utilizando o operador ==, mas os objetos foram criados de forma diferente, na variável oneWrapper foi realizado a atribuição do valor diretamente onde irá ser realizado o autoboxing, já a variável twoWrapper foi criada utilizando o construtor de Integer.

Ao criar utilizando o construtor, não reaproveitamos objetos do pool de objetos, ou seja, foi criado outro objeto em memória, e como já sabemos o operador == realiza a comparação entre referências, portanto resultado da comparação é false.

No segundo exemplo utilizando o operador != aqui o conceito é o mesmo do exemplo anterior, o valor de ambas as variáveis é 1, mas lembrando que o operador irá comparar referências que são diferentes portanto o resultado é true.

Já no terceiro exemplo utilizamos o método equals() para realizar a comparação, neste caso o que será avaliado é o valor das variáveis, portanto o resultado é true.

Analisando a Performance


Um ponto importante é analisarmos a performance das operações de boxing dentro de estruturas de repetição, estas operações são custosas pois exigem  muitas transformação em laços.

Vamos analisar alguns códigos para entendermos os casos.

long init = System.currentTimeMillis();
  
long result = 0;
  
for (long i = 0; i < 1000000000; i++) {
     result += i;
}
  
long end = System.currentTimeMillis();
  
System.out.println(" Tempo: "+(end - init)); 

O Resultado da execução é:  Tempo: 460

Esse é um código onde apenas executamos um soma entre as variáveis result e i utilizando o operador += , perceba que como estamos usando o tipo long a soma acontece sem maiores problemas.


long init = System.currentTimeMillis();
  
Long result = 0L;
  
for (long i = 0; i < 1000000000; i++) {
     result += i;
}
  
long end = System.currentTimeMillis();
  
System.out.println(" Tempo: "+(end - init));

O Resultado da execução é:  Tempo: 5043

Este exemplo é quase igual ao anterior, a unica diferença que a variável result agora é do tipo Wrapper Long e não long primitiva, após a execução notamos um tempo superior ao do primeiro exemplo.

Acontece que o operador += só pode ser usado em operações de tipos primitivos, e em nosso exemplo a variável result é uma Wrapper, e neste caso a JVM é obrigada a realizar a operação de Autoboxing, deixando o laço mais lento.

Conclusão


O uso de Wrapper e Primitivos deve ser analisado em cada cenário, levando em consideração as operações que serão executadas, performance, cálculos, entre outros fatores.

Os recursos de Autoboxing e Unboxing são muito bons e deixaram a criação e manipulação de objetos mais produtiva, mas sempre devemos nos atentar para não utilizar em lugares onde poderemos ter problemas de performance.

Até mais.

Código Fonte

Referências


Ferramentas Gráficas para MongoDB

Olá pessoal, hoje iremos analisar algumas ferramentas gráficas para utilização do banco de dados MongoDB.

As Ferramentas

Em banco de dados relacionais é comum interagirmos com os databases por meio de alguma ferramenta gráfica, por exemplo, com PostgreSQL podemos usar o pgadmin, com Oracle temos o SQL Developer, entre outras.

Com MongoDB, além do tradicional console, temos várias opções no mercado, sendo elas open source ou pagas, vou listar 2 que venho utilizando:
  • Robo3T (conhecido como Robomongo);
  • NoSQLBooster for MongoDB.


Robo3T

Esta foi a primeira ferramenta na qual tive contato ao entrar no mundo do MongoDB, anteriormente era conhecida como RoboMongo, ela possui uma interface simples e de fácil utilização e está disponível para Linux. Mac e Windows.


Interface inicial do Robo3T.

Uma das grandes vantagens que vejo nesta ferramenta é a facilidade de realizar consulta e visualizar os dados, para isso basta clicar sobre uma coleção e a consulta já será realizada fornecendo diferentes opções de visualização, sendo em tree, table ou json. 

Visualização de dados de uma coleção.

Esta é uma ferramenta que venho utilizo bastante, e que também possui uma boa aceitação pelo comunidade de desenvolvimento.

NoSQLBooster for MongoDB

Esta ferramenta é mais robusta e com vários recursos, sua interface lembra uma IDE, onde temos vários recursos interessantes mesmo utilizando a versão free, esta disponível para Linux, Mac e Windows.



Interface inicial do NoSQL Booster for MongoDB.

Até o momento possui uma edição free para uso pessoal/comercial mas com funções limitadas, para detalhes sobre licença e termos de uso, consulte o site oficial da ferramenta.

Detalhes sobre versão e descrição de licença.

No site existe listas de comparação de features disponíveis em cada versão, vale a pena analisar e definir qual versão se adapta melhor a sua necessidade:


A visualização dos dados é bem detalhada, possuindo recursos bem interessantes como exportação, manipulação de dados direto no grid, entre outras. 

Visualização de dados de uma coleção.

A ferramenta possui um recurso bem interessante, ao clicar sobre uma coleção ou index será exibido informações administrativas, como tamanho em disco, engine, etc, isso ajuda bastante quando temos que analisar recursos utilizados pelo database.

Visualizando detalhes da coleção.

Conclusão

Existem várias outras ferramentas disponíveis no mercado, listei as 2 que tenho experiência, e atualmente tenho utilizado, acredito que vale a pena realizar testes e ter ambas em seu ambiente, dessa forma será aproveitado o melhor de cada uma delas.


Referências



Utilizando LocalDate, LocalDateTime e LocalTime na Prática

Tudo bem pessoal, hoje iremos avaliar e analisar operações de manipulação de Datas envolvendo a JavaTime API introduzida no Java 8.

Exemplos da java.time API


Já se passaram alguns anos desde o lançamento do Java 8 e mesmo após este período, há empresas que desconhecem o poder da java.time API, esta foi uma nova API de datas introduzida no Java 8 visando resolver problemas que tínhamos com as velhas classes Date e Calendar.

Vamos mostrar vários exemplos práticos do uso da API:

Criação de objetos

No exemplo abaixo, estamos criando os objetos para manipulação de datas, perceba que temos 3 tipos, sendo LocalDate para manipular datas, LocalDateTime para manipular data/hora e LocalTime para horas:

LocalDate localDate      = LocalDate.now();
LocalDateTime localDateTime = LocalDateTime.now();
LocalTime localTime      = LocalTime.now();

Utilizando formatação

Aqui realizamos a operação de formatação, perceba que não foi necessário utilizar a classe SimpleDateFormat, que usaríamos em conjunto com Date ou Calendar, aqui utilizamos a DateTimeFormatter passando o formato desejado:

String strLocalDate2   = LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
String strLocalDateTime2 = LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"));
String strLocalTime2   = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));

Adicionando dias, meses e horas

Um recurso muito interessante são os métodos de adicionar períodos, quem já trabalhou com Calendar sabe como essa tarefa era complexa, onde era necessário manipular métodos void e passar constantes para determinar  qual parte gostaríamos de alterar, aqui basta chamar o método plus desejado de forma fluente, veja o exemplo:

LocalDate localDate3         = LocalDate.now().plusDays(1).plusMonths(1);
LocalDateTime localDateTime3 = LocalDateTime.now().plusDays(1).plusMonths(1).plusHours(2);

Subtraindo dias, meses e horas

Da mesma forma que acontece a adição de valores,  podemos também subtrair dados de diferentes parte do período:

LocalDate localDate4       = LocalDate.now().minusDays(1).plusMonths(1);
LocalDateTime localDateTime4 = LocalDateTime.now().minusDays(1).minusMonths(1).minusHours(2);
LocalTime localTime4       = LocalTime.now().minusHours(1);

Criando objetos específicos

Um recurso interessante é quando criamos uma data com valores específicos, onde cada tipo possui métodos fábricas para construção dos objetos:

LocalDate localDate5       = LocalDate.of(2018, 07, 22);
LocalDateTime localDateTime5 = LocalDateTime.of(2018, 07, 22, 10, 15, 30);
LocalTime localTime5       = LocalTime.of(10, 35, 12);

Realizando parse de String em Datas

Uma das situações mais comuns é a operação de parse, que consiste em pegar uma data como String e transformar para a classe de Período correspondente:

LocalDate localDate6       = LocalDate.parse("2018-07-22", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDateTime localDateTime6 = LocalDateTime.parse("2018-07-22 10:35:10", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
LocalTime localTime6       = LocalTime.parse("11:40:02", DateTimeFormatter.ofPattern("HH:mm:ss"));

Recuperando partes especificas de um objeto

Outro recurso interessante e muito utilizando é quando temos que recuperar uma parte especifica do objeto, podendo ser ano, mês, dia, hora, minuto, segundo:

int year    = LocalDate.now().getYear();
Month month = LocalDateTime.now().getMonth();
int hour    = LocalTime.now().getHour();

Comparando com os métodos isAfter, isBefore e isEqual

Com frequência temos que comparar objetos Data, analisando se um período é maior, menor ou igual ao outro, para isto temos métodos utilitários que facilitam esse tipo de ação, veja abaixo:

LocalDate localDate8 = LocalDate.now();
LocalDate localDate9 = LocalDate.now().minusDays(1);
  
boolean isAfter  = localDate8.isAfter(localDate9);   //true
boolean isBefore = localDate8.isBefore(localDate9); //false
boolean isEqual  = localDate8.isEqual(localDate9); //false

Capturando Diferenças entre LocalDate com classe Period

É comum precisar saber a diferença entre dois objetos Data, aqui temos a classe Period que possui vários métodos utilitários para esta finalidade, esta classe representa o tempo em anos, meses e dias, vamos testar o método between que recupera a diferença entre dois objetos LocalDate, veja abaixo:

LocalDate localDate10 = LocalDate.now();
LocalDate localDate11 = LocalDate.now().plusDays(2);
  
Period period1 = Period.between(localDate10, localDate11); 

Capturando Diferenças com a Enum ChronoUnit

A Enum ChronoUnit é utilizada para manipular Tempos, com ela podemos manipular tempos de  diferentes formas, podemos utiliza-la em conjunto com LocalDate, LocalDateTime e LocalTime, segue o exemplo:


LocalDateTime localDateTime12 = LocalDateTime.now();
LocalDateTime localDateTime13 = LocalDateTime.now().plusDays(2);
  
long periodAsMinutes = ChronoUnit.MINUTES.between(localDateTime12, localDateTime13);
long periodAsHours  = ChronoUnit.HOURS.between(localDateTime12, localDateTime13);
long periodAsDays = ChronoUnit.DAYS.between(localDateTime12, localDateTime13);

A API java.time possui uma porção de outros métodos e classes que podemos utilizar no decorrer dos projetos, trabalhar com datas, períodos, tempos, é praticamente obrigatórios em 90% dos sistemas.

A maioria dos frameworks do Mundo Java como Spring, Hibernate, JSF, já fornecem suporte full para o uso da API.

Até mais.

Código fonte

Referências