Java e OO

Introdução à nova API de Datas do Java 8

Já percebeu que precisamos escrever muito código para trabalhar com datas em Java, com as classes java.util.Date e java.util.Calendar?

Já tem um tempo que esta API precisava ser atualizada, ganhar novidades realmente importantes e que adicionassem melhorias significativas a ela. Bem, esse dia chegou! Na nova API de datas do Java 8, muitas coisas boas chegaram e ficou muito mais fácil trabalhar.

A nova API de datas (JSR 310) foi adicionada no Java 8 e era uma das novidades mais aguardadas dessa versão.

São várias classes e interfaces. Neste post vou te mostrar sobre a java.time.LocalDateTime que representa uma data com informações de tempo. Também veremos a java.time.LocalDate e java.time.LocalTime que, como você pode deduzir, a primeira tem informações apenas relacionadas a datas e a segunda com tempo.

Você pode usar qualquer IDE para executar o código, desde que ele já tenha suporte ao Java 8. O Eclipse já tem uma versão com suporte, assim como o NetBeans.

Vou criar um sistema simples de locadora de filmes, que demonstrará algumas das facilidades dessas classes fantásticas.

Para representar um filme, criei a classe abaixo com um atributo dataLancamento do tipo java.time.LocalDate. Essa classe representa apenas a data, pois não preciso armazenar a hora que o filme foi lançado.

package com.algaworks.model;

import java.math.BigDecimal;
import java.time.LocalDate;

public class Filme {

  private String nome;
  private LocalDate dataLancamento;
  private BigDecimal valor;

  public Filme(String nome, LocalDate dataLancamento, BigDecimal valor) {
    this.nome = nome;
    this.dataLancamento = dataLancamento;
    this.valor = valor;
  }

  //getters e setters
}

Para o post ficar mais simples e focar apenas na nova API de datas, não vou buscar essas informações de um banco de dados, mas vamos simular isso deixando em um array de uma classe repositório.

package com.algaworks.repository;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

import com.algaworks.model.Filme;

public class Filmes {

  private static Filme[] filmes = {
    new Filme("Jogos Vorazes: Em Chamas", LocalDate.of(2014, Month.MARCH, 5), new BigDecimal(6)),
      new Filme("Rush - No Limite da Emoção", LocalDate.of(2014, Month.MARCH, 12), new BigDecimal(6)),
      new Filme("Jobs", LocalDate.of(2014, Month.MARCH, 19), new BigDecimal(6)),
      new Filme("Elysium", LocalDate.of(2014, Month.APRIL, 2), new BigDecimal(6)),
      new Filme("12 Anos de Escravidão", LocalDate.of(2014, Month.MAY, 14), new BigDecimal(6))
  };
  
  public List<Filme> todos() {
    return Arrays.asList(filmes);
  }
}

Repare a criação da instância de LocalDate. É utilizado o método estático of(ano, mês, dia). Veja também a existência da enumeração Month, agora você não precisa lembrar mais se precisa começar com 0 ou 1 no mês de Janeiro.

Para imprimir a lista de filmes para que o cliente possa escolher, vamos criar uma classe de exemplo com um método main e imprimir utilizando o lambda.

package com.algaworks.exemplo;

import java.time.format.DateTimeFormatter;

import com.algaworks.repository.Filmes;

public class ListaTodosFilmes {

  public static void main(String[] args) {
    System.out.printf("%-30s %s\n", "Nome:", "Data de lançamento:");
    
    Filmes filmes = new Filmes();
    filmes.todos().forEach(f -> {
      System.out.printf("%-30s %s\n", f.getNome(),
        f.getDataLancamento().format(DateTimeFormatter.ofPattern("dd/MM/yyyy")));
    });
  }
}

Veja a saída abaixo:

Nome:                          Data de lançamento:
Jogos Vorazes: Em Chamas       05/03/2014
Rush - No Limite da Emoção     12/03/2014
Jobs                           19/03/2014
Elysium                        02/04/2014
12 Anos de Escravidão          14/05/2014

Como eu formatei a data? Simples, chame o método format passando um DateTimeFormatter. Existem várias opções de padrões de formatação já prontas, ou você pode criar a sua utilizando o método ofPattern.

Ok. Até agora muito simples, não é verdade? Vamos ver mais alguns detalhes criando uma locação para um cliente. Veja a primeira versão dela abaixo:

public class Locacao {

  private List<Filme> filmes;
  private Cliente cliente;
  private LocalDateTime data;
  private LocalDateTime dataPrevistaDevolucao;
  private LocalDateTime dataRealDevolucao;
  private BigDecimal valorDevolucao;

}

Quando terminei de escrever isso, pensei: será que esses últimos três atributos não deveriam virar uma nova entidade, chamada de Devolucao? Então foi o que eu fiz.

package com.algaworks.model;

import java.math.BigDecimal;
import java.time.LocalDateTime;

public class Devolucao {

  private LocalDateTime dataPrevista;
  private LocalDateTime dataReal;
  private BigDecimal valor;

  public Devolucao(LocalDateTime dataPrevista) {
    this.dataPrevista = dataPrevista;
  }

  //getters e setters

}
public class Locacao {

  private List<Filme> filmes;
  private Cliente cliente;
  private LocalDateTime data;
  private Devolucao devolucao;

  public Locacao(List<Filme> filmes, Cliente cliente) {
    this.filmes = filmes;
    this.cliente = cliente;
    this.data = LocalDateTime.now();
    this.gerarDevolucao();
  }

Reparou como foi inicializado a data da locação? A data e hora do momento da locação são criadas chamando o método now() em LocalDateTime.

Mas e esse método gerarDevolucao()? Deixa eu te contar como é a regra do nosso sistema.

  • A devolução deve ser feita até as 19 horas.
  • A data de devolução é definida somando-se a data atual, mais a quantidade de filmes alugados.

Baseado nisso, veja o código do método gerarDevolucao():

private void gerarDevolucao() {
  this.devolucao = new Devolucao(LocalDateTime.of(calcularDataPrevista(),
      LocalTime.of(19, 0)));
}

private LocalDate calcularDataPrevista() {
  return this.data.plusDays(this.filmes.size()).toLocalDate();
}

Duas coisas importantes aconteceram ai. A primeira delas é que criamos um LocalDateTime usando um LocalDate e um LocalTime, o que faz todo sentido, pois um é a união dos outros dois.

A segunda delas é a chamada do método plusDays. Ele faz exatamente isso que diz, soma dias a uma data. E importante notar que: ele não altera o objeto que está sendo utilizado para chamar o método, mas retorna uma nova instância.

Estamos quase prontos. Falta agora criar um método para imprimir o recibo dessa locação.

public void imprimirRecibo() {
  System.out.printf("Obrigado %s.\n", this.cliente.getNome());
  System.out.println("Filme(s):");
    
  BigDecimal total = BigDecimal.ZERO;
  for (Filme filme : this.getFilmes()) {
    System.out.println(filme.getNome());
    total = total.add(filme.getValor());
  }
  System.out.printf("Valor total: R$%s\n", total);
  System.out.printf("Data devolução: %s", this.getDevolucao().getDataPrevista()
                                .format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm")));
  }

Repare que a formatação é bem parecida com o que fizemos antes, com a diferença que agora também passo informações para formatar a hora.

E criar um método para recuperar um filme pelo código no repositório Filmes, que no caso será o índice do array.

public Filme porCodigo(int codigo) {
  return filmes[codigo];
}

Para finalizar, vamos criar a classe que irá simular uma nova locação.

package com.algaworks.exemplo;

import java.util.Arrays;
import java.util.List;

import com.algaworks.model.Cliente;
import com.algaworks.model.Filme;
import com.algaworks.model.Locacao;
import com.algaworks.repository.Filmes;

public class NovaLocacao {

  public static void main(String[] args) {
    Filmes filmes = new Filmes();
    List<Filme> filmesAlugados = Arrays.asList(filmes.porCodigo(0), filmes.porCodigo(2));
    Locacao locacao = new Locacao(filmesAlugados, new Cliente("João Souza"));
    
    locacao.imprimirRecibo();
  }
}

Veja a saída:

Obrigado João Souza.
Filme(s):
Jogos Vorazes: Em Chamas
Jobs
Valor total: R$12
Data devolução: 06/06/2014 19:00

Deixe seu comentário do que você achou da API. Achou mais simples mesmo?

Acesse ou baixe o código-fonte completo deste artigo no GitHub.

Para aprender mais sobre Java 8, conheça nosso curso online de Java e Orientação a Objetos, que é completo e substitui a necessidade de cursos presenciais.

Graduado em Engenharia Elétrica pela Universidade Federal de Uberlândia e detentor das certificações LPIC-1, SCJP e SCWCD.

Olá,

o que você achou deste conteúdo? Conte nos comentários.

Junte-se a mais de 100.000 pessoas

Entre para nossa lista e receba conteúdos exclusivos e com prioridade

Você se Inscreveu com Sucesso!