Uma introdução ao Apache Commons Lang 3
*1. Visão geral *
A biblioteca Apache Commons Lang 3* é um pacote popular e completo de classes de utilitários, cujo objetivo é estender a funcionalidade da API Java *.
O repertório da biblioteca é bastante rico, variando de manipulação de string, array e número, reflexão e simultaneidade, até a implementação de várias estruturas de dados ordenadas, como pares e triplos (geralmente conhecidos como https://en.wikipedia.org/wiki/Tuple [tuplas]).
Neste tutorial, vamos mergulhar fundo nas classes de utilidade mais úteis da biblioteca .
*2. A dependência do Maven *
Como de costume, para começar a usar o Apache Commons Lang 3, primeiro precisamos adicionar o https://search.maven.org/search?q=g:org.apache.commons%20AND%20a:commons-lang3&core=gav [ Dependência do Maven]:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8</version>
</dependency>
===* 3. A classe StringUtils *
A primeira classe de utilitário que abordaremos neste resumo introdutório é https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html [StringUtils] .
Como o próprio nome sugere,* StringUtils nos permite executar várias operações strings com segurança nula que complementam/estendem as que _https://docs.oracle.com/javase/7/docs/api/java/lang/String. html [java.lang.String] _ fornece imediatamente *.
Vamos começar a mostrar o conjunto de métodos utilitários que executam várias verificações em uma determinada string, como determinar se a string está em branco, vazia, em minúsculas, em maiúsculas, alfanumérica e assim por diante:
@Test
public void whenCalledisBlank_thenCorrect() {
assertThat(StringUtils.isBlank(" ")).isTrue();
}
@Test
public void whenCalledisEmpty_thenCorrect() {
assertThat(StringUtils.isEmpty("")).isTrue();
}
@Test
public void whenCalledisAllLowerCase_thenCorrect() {
assertThat(StringUtils.isAllLowerCase("abd")).isTrue();
}
@Test
public void whenCalledisAllUpperCase_thenCorrect() {
assertThat(StringUtils.isAllUpperCase("ABC")).isTrue();
}
@Test
public void whenCalledisMixedCase_thenCorrect() {
assertThat(StringUtils.isMixedCase("abC")).isTrue();
}
@Test
public void whenCalledisAlpha_thenCorrect() {
assertThat(StringUtils.isAlpha("abc")).isTrue();
}
@Test
public void whenCalledisAlphanumeric_thenCorrect() {
assertThat(StringUtils.isAlphanumeric("abc123")).isTrue();
}
Obviamente, a classe StringUtils implementa muitos outros métodos, que foram omitidos aqui por uma questão de simplicidade.
Para outros métodos adicionais que verificam ou aplicam algum tipo de algoritmo de conversão a uma determinada string, https://www..com/string-processing-commons-lang [consulte este tutorial].
Os que abordamos acima são realmente simples, portanto os testes de unidade devem ser auto-explicativos.
*4. A classe ArrayUtils *
*A classe https://commons.apache.org/proper/commons-lang/javadocs/api-3.6/index.html?org/apache/commons/lang3/ArrayUtils.html[_ArrayUtils_] classe implementa um lote de métodos utilitários que nos permitem processar e verificar matrizes de várias formas* .
Vamos começar com as duas implementações sobrecarregadas do método String () _, que retornam uma representação _string do array especificado e uma _string específica quando o array for nulo:
@Test
public void whenCalledtoString_thenCorrect() {
String[] array = {"a", "b", "c"};
assertThat(ArrayUtils.toString(array))
.isEqualTo("{a,b,c}");
}
@Test
public void whenCalledtoStringIfArrayisNull_thenCorrect() {
assertThat(ArrayUtils.toString(null, "Array is null"))
.isEqualTo("Array is null");
}
Em seguida, temos os métodos _hasCode () _ e _toMap () _.
O primeiro gera uma implementação https://www..com/java-hashcode [hashCode] personalizada para um array, _ enquanto o último converte um _array em um _https://docs.oracle.com/javase/7/docs/api/java/util/Map.html [Mapa] _:
@Test
public void whenCalledhashCode_thenCorrect() {
String[] array = {"a", "b", "c"};
assertThat(ArrayUtils.hashCode(array))
.isEqualTo(997619);
}
@Test
public void whenCalledtoMap_thenCorrect() {
String[][] array = {{"1", "one", }, {"2", "two", }, {"3", "three"}};
Map map = new HashMap();
map.put("1", "one");
map.put("2", "two");
map.put("3", "three");
assertThat(ArrayUtils.toMap(array))
.isEqualTo(map);
}
Por fim, vejamos os métodos _isSameLength () _ e _indexOf () _.
O primeiro é usado para verificar se duas matrizes têm o mesmo comprimento e o último para obter o índice de um determinado elemento:
@Test
public void whenCalledisSameLength_thenCorrect() {
int[] array1 = {1, 2, 3};
int[] array2 = {1, 2, 3};
assertThat(ArrayUtils.isSameLength(array1, array2))
.isTrue();
}
@Test
public void whenCalledIndexOf_thenCorrect() {
int[] array = {1, 2, 3};
assertThat(ArrayUtils.indexOf(array, 1, 0))
.isEqualTo(0);
}
Como na classe StringUtils, ArrayUtils implementa muito mais métodos adicionais. Você pode aprender mais sobre eles em https://www..com/array-processing-commons-lang [este tutorial].
Nesse caso, mostramos apenas os mais representativos.
*5. A classe NumberUtils *
Outro componente importante do Apache Commons Lang 3 é a classe NumberUtils.
Como esperado,* a classe fornece um grande número de métodos utilitários, destinados ao processamento e manipulação de tipos numéricos *.
Vejamos as implementações sobrecarregadas do método compare () _, que compara a igualdade de diferentes primitivas, como _int e long:
@Test
public void whenCalledcompareWithIntegers_thenCorrect() {
assertThat(NumberUtils.compare(1, 1))
.isEqualTo(0);
}
@Test
public void whenCalledcompareWithLongs_thenCorrect() {
assertThat(NumberUtils.compare(1L, 1L))
.isEqualTo(0);
}
Além disso, existem implementações de compare () _ que operam em _byte e short, que funcionam de maneira muito semelhante aos exemplos acima.
Em seguida nesta revisão estão os métodos _createNumber () _ e _isDigit () _.
O primeiro permite criar uma representação numérica de uma string, enquanto o segundo verifica se uma string é composta apenas por dígitos:
@Test
public void whenCalledcreateNumber_thenCorrect() {
assertThat(NumberUtils.createNumber("123456"))
.isEqualTo(123456);
}
@Test
public void whenCalledisDigits_thenCorrect() {
assertThat(NumberUtils.isDigits("123456")).isTrue();
}
Quando se trata de encontrar os valores mix e max de uma matriz fornecida, a classe NumberUtils fornece forte suporte para essas operações através das implementações sobrecarregadas dos métodos _min () _ e _max () _:
@Test
public void whenCalledmaxwithIntegerArray_thenCorrect() {
int[] array = {1, 2, 3, 4, 5, 6};
assertThat(NumberUtils.max(array))
.isEqualTo(6);
}
@Test
public void whenCalledminwithIntegerArray_thenCorrect() {
int[] array = {1, 2, 3, 4, 5, 6};
assertThat(NumberUtils.min(array)).isEqualTo(1);
}
@Test
public void whenCalledminwithByteArray_thenCorrect() {
byte[] array = {1, 2, 3, 4, 5, 6};
assertThat(NumberUtils.min(array))
.isEqualTo((byte) 1);
}
6. A Fraction Class
Trabalhar com frações é bom quando usamos uma caneta e um pedaço de papel. Mas, temos que passar pelas complexidades desse processo ao escrever código? Na verdade não.
*A classe _https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/math/Fraction.html [Fraction] _ class faz a adição, subtração e multiplicação de frações em uma brisa* :
@Test
public void whenCalledgetFraction_thenCorrect() {
assertThat(Fraction.getFraction(5, 6)).isInstanceOf(Fraction.class);
}
@Test
public void givenTwoFractionInstances_whenCalledadd_thenCorrect() {
Fraction fraction1 = Fraction.getFraction(1, 4);
Fraction fraction2 = Fraction.getFraction(3, 4);
assertThat(fraction1.add(fraction2).toString()).isEqualTo("1/1");
}
@Test
public void givenTwoFractionInstances_whenCalledsubstract_thenCorrect() {
Fraction fraction1 = Fraction.getFraction(3, 4);
Fraction fraction2 = Fraction.getFraction(1, 4);
assertThat(fraction1.subtract(fraction2).toString()).isEqualTo("1/2");
}
@Test
public void givenTwoFractionInstances_whenCalledmultiply_thenCorrect() {
Fraction fraction1 = Fraction.getFraction(3, 4);
Fraction fraction2 = Fraction.getFraction(1, 4);
assertThat(fraction1.multiplyBy(fraction2).toString()).isEqualTo("3/16");
}
Embora operações com frações não sejam certamente a tarefa mais frequente que teremos que enfrentar em nosso trabalho diário de desenvolvimento, a classe Fraction fornece um suporte valioso para executar essas operações de maneira direta.
*7. A classe SystemUtils *
Às vezes, precisamos obter algumas informações dinâmicas sobre diferentes propriedades e variáveis da plataforma Java subjacente ou do sistema operacional.
*O Apache Commons Lang 3 fornece a _https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/SystemUtils.html [SystemUtils] class_ para realizar isso de uma maneira indolor* .
Vamos considerar, por exemplo, os métodos _getJavaHome () _, _getUserHome () _ e _isJavaVersionAtLeast () _:
@Test
public void whenCalledgetJavaHome_thenCorrect() {
assertThat(SystemUtils.getJavaHome())
.isEqualTo(new File("path/to/java/jdk"));
}
@Test
public void whenCalledgetUserHome_thenCorrect() {
assertThat(SystemUtils.getUserHome())
.isEqualTo(new File("path/to/user/home"));
}
@Test
public void whenCalledisJavaVersionAtLeast_thenCorrect() {
assertThat(SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_RECENT)).isTrue();
}
Existem alguns métodos de utilitário adicionais que a classe SystemUtils implementa. Nós os omitimos para manter os exemplos curtos.
*8. As classes Lazy Initialization and Builder *
*Uma das facetas mais atraentes do Apache Commons Lang 3 é a implementação de alguns padrões de design conhecidos, incluindo os https://en.wikipedia.org/wiki/Lazy_initialization[lazy-initialization] e https://en.wikipedia. padrões org/wiki/Builder_pattern [construtor]* .
Por exemplo, digamos que criamos uma classe User cara (não mostrada por questões de brevidade) e queremos adiar sua instanciação até que seja realmente necessário.
Nesse caso, tudo o que precisamos fazer é estender o https://commons.apache.org/proper/commons-lang/apidocs/index.html?org/apache/commons/lang3/concurrent/LazyInitializer. classe abstrata html [LazyInitializer] e substitua seu método _initialize () _:
public class UserInitializer extends LazyInitializer<User> {
@Override
protected User initialize() {
return new User("John", "[email protected]");
}
}
Agora, se quisermos obter nosso caro objeto User quando necessário, basta chamar o método get () _ do _UserInitializer:
@Test
public void whenCalledget_thenCorrect()
throws ConcurrentException {
UserInitializer userInitializer = new UserInitializer();
assertThat(userInitializer.get()).isInstanceOf(User.class);
}
*O método _get () _ é uma implementação do idioma de verificação dupla (thread-safe) para um campo de instância, conforme especificado em* https://www.pearson.com/us/higher-education/program/Bloch- Effective-Java-3rd-Edition/PGM1763855.html [ *“Effective Java” de Joshua Bloch, item 71* ]:
private volatile User instance;
User get() {
if (instance == null) {
synchronized(this) {
if (instance == null)
instance = new User("John", "[email protected]");
}
}
}
return instance;
}
Além disso, o Apache Commons Lang 3 implementa a classe HashCodeBuilder, que nos permite gerar implementações _hashCode () _ fornecendo ao construtor parâmetros diferentes, com base em uma API fluente típica:
@Test
public void whenCalledtoHashCode_thenCorrect() {
int hashcode = new HashCodeBuilder(17, 37)
.append("John")
.append("[email protected]")
.toHashCode();
assertThat(hashcode).isEqualTo(1269178828);
}
Podemos fazer algo semelhante com a classe BasicThreadFactory e criar daemon threads com um padrão de nomenclatura e uma prioridade:
@Test
public void whenCalledBuilder_thenCorrect() {
BasicThreadFactory factory = new BasicThreadFactory.Builder()
.namingPattern("workerthread-%d")
.daemon(true)
.priority(Thread.MAX_PRIORITY)
.build();
assertThat(factory).isInstanceOf(BasicThreadFactory.class);
}
*9. A classe ConstructorUtils *
*A reflexão é um cidadão de primeira classe no Apache Commons Lang 3.*
A biblioteca inclui várias classes de reflexão, o que nos permite acessar e manipular reflexivamente os campos e métodos da classe.
Por exemplo, digamos que implementamos uma classe de domínio User ingênua:
public class User {
private String name;
private String email;
//standard constructors/getters/setters/toString
}
Supondo que seu construtor parametrizado seja public, podemos acessá-lo facilmente com os _https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/reflect/ConstructorUtils.html [ConstructorUtils] _ classe:
@Test
public void whenCalledgetAccessibleConstructor_thenCorrect() {
assertThat(ConstructorUtils
.getAccessibleConstructor(User.class, String.class, String.class))
.isInstanceOf(Constructor.class);
}
Como alternativa à instanciação de classe padrão por meio de construtores, podemos criar reflexivamente instâncias de User chamando os métodos _invokeConstructor () _ e _invokeExactConstructor () _:
@Test
public void whenCalledinvokeConstructor_thenCorrect()
throws Exception {
assertThat(ConstructorUtils.invokeConstructor(User.class, "name", "email"))
.isInstanceOf(User.class);
}
@Test
public void whenCalledinvokeExactConstructor_thenCorrect()
throws Exception {
String[] args = {"name", "email"};
Class[] parameterTypes= {String.class, String.class};
assertThat(ConstructorUtils.invokeExactConstructor(User.class, args, parameterTypes))
.isInstanceOf(User.class);
}
*10. A classe FieldUtils *
Da mesma forma,* podemos usar os métodos da classe FieldUtils para leitura/gravação reflexiva campos de classe *.
Vamos supor que queremos obter um campo da classe User ou, eventualmente, um campo que a classe está herdando de uma superclasse.
Nesse caso, podemos chamar o método _getField () _:
@Test
public void whenCalledgetField_thenCorrect() {
assertThat(FieldUtils.getField(User.class, "name", true).getName())
.isEqualTo("name");
}
Como alternativa, se desejarmos usar um escopo de reflexão mais restritivo e obter apenas um campo declarado na classe User, e não herdado de uma superclasse , usaremos o método _getDeclaredField () _:
@Test
public void whenCalledgetDeclaredFieldForceAccess_thenCorrect() {
assertThat(FieldUtils.getDeclaredField(User.class, "name", true).getName())
.isEqualTo("name");
}
Além disso, podemos usar o método _getAllFields () _ para obter o número de campos da classe refletida e gravar um valor em um campo declarado ou em um campo definido em uma hierarquia com os _writeField () _ e _writeDeclaredField () _ métodos:
@Test
public void whenCalledgetAllFields_thenCorrect() {
assertThat(FieldUtils.getAllFields(User.class).length)
.isEqualTo(2);
}
@Test
public void whenCalledwriteField_thenCorrect()
throws IllegalAccessException {
FieldUtils.writeField(user, "name", "Julie", true);
assertThat(FieldUtils.readField(user, "name", true))
.isEqualTo("Julie");
}
@Test
public void givenFieldUtilsClass_whenCalledwriteDeclaredField_thenCorrect() throws IllegalAccessException {
FieldUtils.writeDeclaredField(user, "name", "Julie", true);
assertThat(FieldUtils.readField(user, "name", true))
.isEqualTo("Julie");
}
*11. A classe MethodUtils *
Na mesma linha, podemos usar a reflexão sobre métodos de classe com a classe _https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/reflect/MethodUtils.html [MethodUtils] _ class .
Nesse caso, a visibilidade do método User class 'getName () _ é _public. Portanto, podemos acessá-lo com o método _getAccessibleMethod () _:
@Test
public void whenCalledgetAccessibleMethod_thenCorrect() {
assertThat(MethodUtils.getAccessibleMethod(User.class, "getName"))
.isInstanceOf(Method.class);
}
Quando se trata de invocar métodos de maneira reflexiva, podemos usar os métodos _invokeExactMethod () _ e _invokeMethod () _:
@Test
public
void whenCalledinvokeExactMethod_thenCorrect()
throws Exception {
assertThat(MethodUtils.invokeExactMethod(new User("John", "[email protected]"), "getName"))
.isEqualTo("John");
}
@Test
public void whenCalledinvokeMethod_thenCorrect()
throws Exception {
User user = new User("John", "[email protected]");
Object method = MethodUtils.invokeMethod(user, true, "setName", "John");
assertThat(user.getName()).isEqualTo("John");
}
===* 12. A classe MutableObject *
*Embora https://en.wikipedia.org/wiki/Immutable_object[immutability] seja um recurso essencial do bom software orientado a objetos que devemos usar como padrão em todos os casos possíveis* , infelizmente, às vezes, precisamos lidar com objetos mutáveis.
Além disso, a criação de classes mutáveis requer muito código padrão, que pode ser gerado pela maioria dos IDEs por meio de setters gerados automaticamente.
Para esse fim, o Apache Commons Lang 3 fornece a classe _https://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/mutable/MutableObject.html [MutableObject] _ , uma classe de wrapper simples para criar objetos mutáveis com o mínimo de confusão:
@BeforeClass
public static void setUpMutableObject() {
mutableObject = new MutableObject("Initial value");
}
@Test
public void whenCalledgetValue_thenCorrect() {
assertThat(mutableObject.getValue()).isInstanceOf(String.class);
}
@Test
public void whenCalledsetValue_thenCorrect() {
mutableObject.setValue("Another value");
assertThat(mutableObject.getValue()).isEqualTo("Another value");
}
@Test
public void whenCalledtoString_thenCorrect() {
assertThat(mutableObject.toString()).isEqualTo("Another value");
}
Obviamente, este é apenas um exemplo de como usar a classe MutableObject.
Como regra geral, devemos sempre nos esforçar para criar classes imutáveis, ou, na pior das hipóteses, fornecer apenas o nível necessário de mutabilidade .
*13. A classe MutablePair *
Curiosamente, o Apache Commons Lang 3 fornece forte suporte para tuplas, na forma de pares e triplos.
Então, vamos supor que precisamos criar um par mutável de elementos ordenados.
Nesse caso, usaríamos a classe _https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/MutablePair.html [MutablePair] _ class:
private static MutablePair<String, String> mutablePair;
@BeforeClass
public static void setUpMutablePairInstance() {
mutablePair = new MutablePair<>("leftElement", "rightElement");
}
@Test
public void whenCalledgetLeft_thenCorrect() {
assertThat(mutablePair.getLeft()).isEqualTo("leftElement");
}
@Test
public void whenCalledgetRight_thenCorrect() {
assertThat(mutablePair.getRight()).isEqualTo("rightElement");
}
@Test
public void whenCalledsetLeft_thenCorrect() {
mutablePair.setLeft("newLeftElement");
assertThat(mutablePair.getLeft()).isEqualTo("newLeftElement");
}
O detalhe mais relevante a ser destacado aqui é a API limpa da classe.
Ele nos permite definir e acessar os objetos esquerdo e direito envolvidos pelo par através dos setters/getters padrão.
===* 14. A classe ImmutablePair *
Sem surpresa, também existe uma implementação imutável da classe MutablePair, chamada _https://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/tuple/ImmutablePair.html [ ImmutablePair] _:
private static ImmutablePair<String, String> immutablePair = new ImmutablePair<>("leftElement", "rightElement");
@Test
public void whenCalledgetLeft_thenCorrect() {
assertThat(immutablePair.getLeft()).isEqualTo("leftElement");
}
@Test
public void whenCalledgetRight_thenCorrect() {
assertThat(immutablePair.getRight()).isEqualTo("rightElement");
}
@Test
public void whenCalledof_thenCorrect() {
assertThat(ImmutablePair.of("leftElement", "rightElement"))
.isInstanceOf(ImmutablePair.class);
}
@Test(expected = UnsupportedOperationException.class)
public void whenCalledSetValue_thenThrowUnsupportedOperationException() {
immutablePair.setValue("newValue");
}
Como podemos esperar de uma classe imutável, qualquer tentativa de alterar o estado interno do par através do método setValue () _ resultará no lançamento de uma exceção _UnsupportedOperationException.
15.* A classe Triple *
A última classe de utilitário que será analisada aqui é _https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/Triple.html [Triplo] _.
Como a classe é abstrata, podemos criar Triple instâncias usando o https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/Triple.html#of-LMR- [_of () _] método estático de fábrica:
@BeforeClass
public static void setUpTripleInstance() {
triple = Triple.of("leftElement", "middleElement", "rightElement");
}
@Test
public void whenCalledgetLeft_thenCorrect() {
assertThat(triple.getLeft()).isEqualTo("leftElement");
}
@Test
public void whenCalledgetMiddle_thenCorrect() {
assertThat(triple.getMiddle()).isEqualTo("middleElement");
}
@Test
public void whenCalledgetRight_thenCorrect() {
assertThat(triple.getRight()).isEqualTo("rightElement");
}
Também existem implementações concretas para triplos mutáveis e imutáveis, através dos https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/ImmutableTriple.html [MutableTriple] _ e _ImmutableTriple