Uma introdução ao Apache Commons Lang 3

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