De acordo com as Leis 12.965/2014 e 13.709/2018, que regulam o uso da Internet e o tratamento de dados pessoais no Brasil, ao me inscrever na newsletter do portal DICAS-L, autorizo o envio de notificações por e-mail ou outros meios e declaro estar ciente e concordar com seus Termos de Uso e Política de Privacidade.


A Apache Commons Lang API

Colaboração: Carlos Tosin

Data de Publicação: 06 de agosto de 2010

Ao programar em Java, você já deve ter se deparado com situações onde precisou escrever alguma classe utilitária com métodos para trabalhar com arrays ou strings, por exemplo. A vantagem de criar estas classes é que você pode reaproveitá-las em vários lugares do seu código e até em diversos projetos.

Pensando nisso, a Apache criou um projeto chamado Commons. Este projeto visa oferecer diversas funcionalidades utilitárias que são comuns a diversos projetos. Dentro deste projeto existem outros projetos, os quais são categorizados de acordo com o tipo de funcionalidade que oferecem. Alguns exemplos de projetos que fazem parte do Apache Commons são:

  • I/O: funcionalidades de I/O
  • Email: funcionalidades para envio de e-mails
  • DbUtils: funcionalidades para auxiliar a programação com JDBC
  • Net: funcionalidades para uso de programação em rede e implementação de protocolos
  • etc...

Assim como todos os projetos da Apache, o Commons é gratuito e open-source.

Dentre esses projetos, um que se destaca é o Apache Commons Lang. O objetivo deste projeto é prover funcionalidades que são bastante úteis e resolvem problemas que a maioria dos desenvolvedores encontram ao programar aplicações Java. Utilizar uma API como a Apache Commons Lang significa usar um código funcional, estável e testado para resolver problemas que não estão diretamente ligados à regra de negócio da aplicação. O que é melhor: perder tempo escrevendo um método que verifica se uma string é apenas composta por números ou utilizar um método pronto que faz isso? Lembre-se da regra básica: não é necessário reinventar a roda. O projeto Apache Commons Lang é o tema abordado neste artigo.

Configurando sua Aplicação

Para usar o Apache Commons Lang, vá até o site do projeto (http://commons.apache.org/lang) e, na área de downloads, baixe a última versão do arquivo binário. Você pode escolher entre ZIP ou TAR. Depois disso, descompacte este arquivo e você vai encontrar o arquivo commons-lang-2.5.jar (que corresponde à versão 2.5 da API, versão mais atual até a data da escrita deste artigo). Agora basta incorporar este JAR ao classpath da sua aplicação e pronto! Você já pode usar todas as funcionalidades que a API disponibiliza.

Utilitários e Mais Utilitários...

O projeto Commons Lang conta com uma grande quantidade de utilitários para simplificar as mais diversas tarefas. Este artigo descreve apenas alguns deles. A ideia é abordar as classes e métodos que, na minha opinião, são as mais úteis aos mais diversos tipos de projetos. Para uma lista completa de funcionalidades, consulte o javadoc da API neste endereço: http://commons.apache.org/lang/api-release/index.html.

É hora de partirmos para a parte prática! A partir de agora vou abordar os aspectos que considero mais relevantes desta API, e mostrarei exemplos de uso para cada um deles.

A Classe StringUtils

A classe StringUtils possui os mais diversos utilitários para trabalhar com strings.

equals() e isEmpty() O método equals() verifica se as duas strings passadas como parâmetro são iguais. A grande vantagem deste método sobre o método equals() da API do Java é que é possível usá-lo mesmo que as strings sejam nulas. Observe:

  String s1 = null;
  String s2 = "exemplo";	
  boolean e = StringUtils.equals(s1, s2);

O retorno da chamada é false uma vez uma string é nula e a outra possui conteúdo. Usando a API do Java, seria necessário primeiro checar se a string não é nula para depois invocar o método equals() (caso contrário, seria lançada uma NullPointerException).

Já o método isEmpty() retorna um booleano indicando se a string está vazia ou não. De novo, a sua diferença com relação ao método isEmpty() da classe String é o fato de que ele pode ser invocado para strings nulas. Observe:

  String s = null;
  boolean e = StringUtils.isEmpty(s);

O retorno desta chamada é true, uma vez que uma string nula ou com tamanho 0 é considerada vazia.

isNumeric() e isAlphanumeric() O método isNumeric() verifica se a string passada como parâmetro é composta apenas por números. Observe:

  boolean n = StringUtils.isNumeric("1234");

O retorno desta chamada é true, uma vez que apenas números compõem a string. O método isAlphanumeric() é similar, mas verifica se a string passada como parâmetro contém apenas letras ou números. Observe:

  boolean r1 = StringUtils.isAlphanumeric("a1b2c3");
  boolean r2 = StringUtils.isAlphanumeric("aa-bb");

Neste exemplo, r1 é true, já que a string possui apenas letras e números. Já r2 é false, devido à presença do hífen.

leftPad() e rightPad() Os métodos leftPad() e rightPad() permitem preencher uma string com um determinado caractere, até que ela fique de um tamanho determinado. Observe:

  String s1 = StringUtils.leftPad("3245", 10, "0");
  String s2 = StringUtils.rightPad("abcd", 10, "?");

Neste exemplo, o resultado de s1 é 0000003245 (houve o preenchimento de 0's à esquerda até a string ficar com tamanho 10). E o resultado de s2 é abcd?????? (houve o preenchimento de ?'s à direita até a string ficar com tamanho 10).

repeat() O método repeat() permite gerar uma nova string através da repetição de uma string de acordo com um número de vezes. Observe:

  String s = StringUtils.repeat("ab", 4);

A string s resultante é abababab, isto é, a string ab repetida 4 vezes.

A Classe StringEscapeUtils

A classe StringEscapeUtils possui utilitários para trabalhar com caracteres de escape em strings. Existem métodos para diversos tipos de formatos, como HTML, CSV, Java, JavaScript, SQL e XML.

Os métodos escapeHtml() e unescapeHtml() permitem colocar os caracteres de escape e tirar os caracteres de escape para textos no formato HTML, respectivamente. São utilitários bastante úteis no desenvolvimento de aplicações web. Observe:

  String s1 = StringEscapeUtils.escapeHtml("A tag raiz de um documento é a <HTML>");
  String s2 = StringEscapeUtils.unescapeHtml("A tag raiz de um documento é a <HTML>");

Neste exemplo, s1 terá os caracteres de escape para a linguagem HTML, e o resultado será A tag raiz de um documento é a <HTML>. Já s2 é o resultado do caminho inverso, isto é, os caracteres de escape do HTML são removidos. O resultado é a string A tag raiz de um documento é a <HTML>.

A Classe ArrayUtils

É sabido que diversos problemas surgem quando você utiliza arrays na programação. Arrays não mudam de tamanho depois de criados. Elementos removidos de arrays deixam "buracos". Estes são dois problemas que a classe ArrayUtils procura gerenciar, para que você não precise escrever código que faça este gerenciamento de forma automática.

add() O método add() permite adicionar um elemento em uma determinada posição do array. A grande vantagem é que o método add() é capaz de redimensionar o array caso seja necessário e também desloca os elementos para a direita. Observe:

  int[] a = { 5, 10, 20 };
  a = ArrayUtils.add(a, 2, 15);

O array a é criado com três elementos (possui tamanho 3). Ao utilizar o método add(), estou tentando adicionar o número 15 na posição 2 do array a. O resultado é exatamente o esperado: [5, 10, 15, 20]. Perceba que o array foi redimensionado para receber mais um elemento, ao mesmo tempo que o número 20 foi deslocado uma posição para a direita. O método add() cuidou de todo o processo! Lembre-se: o método add() retorna um novo array, portanto é necessário atribuí-lo a uma variável.

remove() O método remove() é similar ao add(), mas remove um elemento do array. Observe:

  int[] a = { 5, 10, 20 };
  a = ArrayUtils.remove(a, 1);

O resultado desta chamada ao remove() é um array de 2 posições contendo [5, 20]. Veja que além de ter havido o redimensionamento do array, o elemento 20 foi deslocado uma posição para a esquerda.

reverse() Já pensou em inverter as posições dos elementos de um array? O método reverse() faz isto de forma bastante fácil. Observe:

  int[] a = { 1, 2, 3, 4, 5 };
  ArrayUtils.reverse(a);

O resultado desta chamada é o reposicionamento dos elementos de forma inversa, isto é: [5, 4, 3, 2, 1]. Veja que este método retorna void, uma vez que é o próprio array passado como parâmetro que é modificado.

toMap() Este método é bastante útil quando você tem um array bidimensional e quer transformá-lo em um map. Observe:

  String[][] palavras = new String[][] {
  	{ "ESQUERDA", "LEFT" },
  	{ "DIREITA", "RIGHT" },
  	{ "CIMA", "UP" },
  	{ "BAIXO", "DOWN" },
  };
  
  Map map = ArrayUtils.toMap(palavras);
  String d = (String) map.get("DIREITA");

A variável palavras é um array bidimensional de strings. Perceba que ele faz um mapeamento entre duas strings. Ao invocar o método toMap(), um objeto Map é retornado, de forma que este objeto reflete o mapeamento. Observe a chamada map.get() na linha 9. O retorno desta invocação é RIGHT, que é exatamente a string mapeada à string DIREITA.

As Classes EqualsBuilder e HashcodeBuilder

Os métodos equals() e hashCode() devem ser implementados sempre que é necessário dizer ao Java quais objetos de uma classe são iguais ou diferentes em termos de significado (e não em termos de posição na memória). Mas implementar estes métodos nem sempre é uma tarefa fácil, já que eles devem seguir um conjunto de regras. É aí que entram as classes EqualsBuilder e HashcodeBuilder. Elas fazem o trabalho complicado de implementação, de forma que você só deve dizer os atributos da sua classe que devem ser utilizados no algoritmo de comparação.

Imagine que você tem uma classe Endereço que tem os atributos definidos da seguinte forma:

  public class Endereco {
  	private String rua;
  	private int numero;
  	private String complemento;
  }

Para a sua aplicação, dois endereços são considerados iguais se eles possuem a mesma rua, número e complemento. Portanto, ao implementar os métodosequals() e hashCode(), você deve utilizar estes 3 atributos na comparação. Aliás, você não fará isto. Esta tarefa fica a cargo das classes utilitárias da API Commons Lang. Observe a implementação do método equals():

  public boolean equals(Object obj) {
  	if (obj == null) {
  		return false;
  	}
  	if (obj == this) {
  		return true;
  	}
  	if (obj.getClass() != getClass()) {
  		return false;
  	}
  	Endereco e = (Endereco) obj;
  	return new EqualsBuilder()
  		.appendSuper(super.equals(obj))
  		.append(rua, e.rua)
  		.append(numero, e.numero)
  		.append(complemento, e.complemento)
  		.isEquals();
  }

Primeiramente são feitas algumas verificações: se o objeto é nulo, se o objeto fornecido é o próprio objeto onde o equals() está sendo invocado e se a classe dos objetos é a mesma. Depois disso a classe EqualsBuilder entra em ação. Basta você criar um objeto dela e invocar o método append(), fornecendo os dados a serem comparados. O método appendSuper() é usado para incorporar o resultado do método equals() da superclasse. No final, basta chamar o método isEquals(), que vai retornar true se os objetos forem iguais ou false se forem diferentes.

Para a implementação do método hashCode() o processo é semelhante. Basta utilizar a classe HashcodeBuilder. Observe como ficaria a implementação do método para a classe Endereço:

  public int hashCode() {
  	return new HashCodeBuilder()
  	   .appendSuper(super.hashCode())
  	   .append(rua)
  	   .append(numero)
  	   .append(complemento)
  	   .toHashCode();
  }

Basta usar o método append() da classe HashcodeBuilder para incluir os campos que devem ser utilizados na criação do hash code. Lembre-se de que os atributos fornecidos nos métodos equals() e hashCode() devem ser os mesmos. O método appendSuper() é usado para incluir no cálculo o hash code da super classe. No final, basta invocar o método toHashCode(), que vai retornar o hash code calculado.

A Classe ToStringBuilder

A implementação do método toString() permite que você dê aos seus objetos uma representação em forma de string que tenha informações úteis. A classe ToStringBuilder tem por objetivo auxiliar neste processo.

Imagine que você tem uma classe Pessoa com os seguintes atributos definidos:

  public class Pessoa {
  	private String nome;
  	private int idade;
  	private char sexo;
  }

Agora imagine que você quer implementar o método toString() na classe para fornecer o valor dos atributos na string gerada. A classe ToStringBuilder pode te auxiliar no processo. Observe como ela poderia ser usada na implementação do toString():

  public String toString() {
  	return new ToStringBuilder(this)
  		.append("nome", nome)
  		.append("idade", idade)
  		.append("sexo", sexo)
  		.toString();
  }

Basta criar uma instância de ToStringBuilder fornecendo o objeto para o qual o builder será construído (no caso, o this). Depois é só invocar o método append() informando o nome e valor de cada campo que você deseja que seja gerado na saída. No final, a invocação do método toString() retorna a string pronta. O resultado obtido com a implementação acima seria mais ou menos assim: Pessoa@1fb8ee3[nome=Carlos,idade=28,sexo=M], considerando que o objeto é criado da seguinte forma:

  Pessoa p = new Pessoa();
  p.setNome("Carlos");
  p.setIdade(28);
  p.setSexo('M');

Para conhecer mais, consulte no javadoc a classe ToStringStyle. Ela pode ser utilizada em conjunto com a ToStringBuilder e permite formatar string de saída.

A Classe NumberRange

A classe NumberRange é bastante interessante quando você deseja representar um intervalo de números. Você pode definir o limite inferior e superior do intervalo e utilizar o método containsNumber() para checar se determinado número pertence ao intervalo. Observe:

  NumberRange range = new NumberRange(1, 10);
  boolean b = range.containsNumber(5);

Neste exemplo foi criado um intervalo numérico de 1 a 10. A invocação de containsNumber() verifica se o número 5 está dentro deste intervalo (neste caso o resultado é verdadeiro).

Existem outras classes mais especializadas para criação de intervalos numéricos na API Commons Lang. São elas: IntRange, LongRange, FloatRange e DoubleRange. Consulte o javadoc da API para maiores informações.

A Classe DateUtils

Fazer manipulação de datas em Java significa trabalhar com a classe Calendar. A classe DateUtils abstrai o uso do Calendar, facilitando a manipulação de datas no seu código. Observe:

  Date now = new Date();
  Date nextWeek = DateUtils.addDays(now, 7);

Na linha 1, a data atual do sistema é buscada. E na linha 2 são somados 7 dias à data atual, retornando uma nova data. Bastante simples, não? Além do método addDays(), você vai encontrar métodos como addMonths(), addHours(), addSeconds(), etc.

É importante destacar também os métodos de comparação de datas desta classe, como o isSameDay() e o isSameInstant(). O primeiro verifica se duas datas representam o mesmo dia, independente da hora. Já o segundo verifica se duas datas representam exatamente o mesmo instante no tempo. Observe:

  Date d1 = ... //primeira data
  Date d2 = ... //segunda data
  		
  boolean sameDay = DateUtils.isSameDay(d1, d2); //mesmo dia?
  boolean sameInstance = DateUtils.isSameInstant(d1, d2); //mesmo milissegundo?

Outro método que vale a pena mencionar é o parseDate(), que permite fazer o parse de uma string de acordo com um padrão e criar um objeto Date. Este método aceita que um array de padrões seja fornecido, e o código vai tentando padrão por padrão, até conseguir fazer o parse. Caso a string fornecida não esteja de acordo com nenhum padrão, a exceção ParseException é lançada. Observe:

  String[] patterns = {
  	"dd/MM/yyyy",
  	"dd-MM-yyyy",
  	"ddMMyyyy"
  };
  
  Date d1 = DateUtils.parseDate("01/09/2010", patterns);
  Date d2 = DateUtils.parseDate("01-09-2010", patterns);
  Date d3 = DateUtils.parseDate("01092010", patterns);

O array patterns define diversos padrões que são válidos para representar uma data. Veja que cada chamada ao método parseDate() utiliza um padrão diferente. No final, d1, d2 e d3 representarão as mesmas datas.

A Classe StopWatch

É bastante comum, principalmente durante a fase de desenvolvimento e testes de aplicações, que precisemos escrever código para verificar quanto tempo determinada porção de código demorou para executar. O objetivo da classe StopWatch é auxiliar neste processo. Um objeto desta classe representa um cronômetro, que pode ser iniciado e parado de forma bastante simples. Observe:

  StopWatch sw = new StopWatch();
  sw.start();
  
  //aqui vai o código cujo tempo de execução será medido
  
  sw.stop();
  long elapsedTime = sw.getTime();

O primeiro passo é criar um objeto da classe StopWatch. Depois, para iniciar o cronômetro, é chamado o método start(). Para parar o cronômetro, o método stop(). O tempo decorrido é obtido através da invocação do método getTime() (o resultado é em milissegundos).

Outros métodos importantes desta classe são o reset(), que reinicia o cronômetro, e os métodos suspend() e resume(), que permitem, respectivamente, parar a contagem do tempo momentaneamente e retornar a contagem no futuro.

Conclusão

Este artigo buscou introduzir você à Apache Commons Lang API. Ela implementa diversos códigos utilitários que possuem um alto grau de reaproveitamento em grande parte dos projetos Java. Além de ser bastante simples de usar, economiza tempo de desenvolvimento, já que o programador pode focar em escrever código relativo apenas à lógica de negócio da aplicação e não se preocupar com classes utilitárias, as quais podem ser reaproveitadas.

Carlos Tosin é instrutor oficial dos Cursos On-Line de Java (assista uma vídeo-aula grátis) da Softblue, formado em Ciência da Computação pela PUC-PR, pós-graduado em Desenvolvimento de Jogos para Computador pela Universidade Positivo e Mestre em Informática na área de Sistemas Distribuídos, também pela PUC-PR. Trabalha profissionalmente com Java há 7 anos e possui 4 anos de experiência no desenvolvimento de sistemas para a IBM dos Estados Unidos, utilizados a nível mundial. Atua há mais de 2 anos com cursos e treinamentos de profissionais em grandes empresas. Possui as certificações da Sun SCJP, SCJD, SCWCD, SCBCD, SCEA, IBM SOA e ITIL Foundation.

Adicionar comentário

* Campos obrigatórios
5000
Powered by Commentics

Comentários

Nenhum comentário ainda. Seja o primeiro!


Veja a relação completa dos artigos de Carlos Tosin