Un'introduzione ad Apache Commons Lang 3

1. Panoramica

La libreria Apache Commons Lang 3 è un popolare pacchetto completo di classi di utilità, volto a estendere la funzionalità dell'API Java .

Il repertorio della libreria è piuttosto ricco, e va dalla manipolazione di stringhe, array e numeri, riflessione e concorrenza, all'implementazione di diverse strutture di dati ordinate, come coppie e triple (genericamente note come tuple).

In questo tutorial, approfondiremo le classi di utilità più utili della libreria .

2. La dipendenza da Maven

Come al solito, per iniziare a utilizzare Apache Commons Lang 3, dobbiamo prima aggiungere la dipendenza Maven:

 org.apache.commons commons-lang3 3.8 

3. La classe StringUtils

La prima classe di utilità che tratteremo in questo riepilogo introduttivo è StringUtils.

Come suggerisce il nome, StringUtils ci consente di eseguire una serie di operazioni trings null-safe che completano / estendono quelle che java.lang.String fornisce immediatamente .

Cominciamo a mostrare l'insieme di metodi di utilità che eseguono diversi controlli su una determinata stringa , come determinare se la stringa è vuota, vuota, minuscola, maiuscola, alfanumerica e così via:

@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(); } 

Ovviamente, la classe StringUtils implementa molti altri metodi, che abbiamo omesso qui per semplicità.

Per altri metodi aggiuntivi che controllano o applicano un tipo di algoritmo di conversione a una determinata stringa , consultare questo tutorial.

Quelli che abbiamo trattato sopra sono davvero semplici, quindi i test unitari dovrebbero essere autoesplicativi.

4. La classe ArrayUtils

La classe ArrayUtils implementa un batch di metodi di utilità che ci consentono di elaborare e controllare array in molte forme e forme diverse .

Cominciamo con le due implementazioni sovraccaricate del metodo toString () , che restituisce una rappresentazione di stringa dell'array dato e una stringa specifica quando l' array è null:

@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"); } 

Successivamente, abbiamo i metodi hasCode () e toMap () .

Il primo genera un'implementazione hashCode personalizzata per un array, mentre il secondo converte un array in una mappa :

@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); }

Infine, diamo un'occhiata ai metodi isSameLength () e indexOf () .

Il primo viene utilizzato per verificare se due array hanno la stessa lunghezza e il secondo per ottenere l'indice di un dato 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); } 

Come con la classe StringUtils , ArrayUtils implementa molti più metodi aggiuntivi. Puoi saperne di più su di loro in questo tutorial.

In questo caso, abbiamo mostrato solo quelli più rappresentativi.

5. La classe NumberUtils

Un altro componente chiave di Apache Commons Lang 3 è la classe NumberUtils.

Come previsto, la classe fornisce un ampio numero di metodi di utilità, finalizzati all'elaborazione e alla manipolazione di tipi numerici .

Diamo un'occhiata alle implementazioni sovraccaricate del metodo compare () , che confronta l'uguaglianza di diverse primitive, come 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); }

Inoltre, esistono implementazioni di compare () che operano su byte e short , che funzionano in modo molto simile agli esempi precedenti.

Successivamente in questa recensione sono i metodi createNumber () e isDigit () .

Il primo ci permette di creare una rappresentazione numerica di una stringa , mentre il secondo controlla se una stringa è composta solo da cifre:

@Test public void whenCalledcreateNumber_thenCorrect() { assertThat(NumberUtils.createNumber("123456")) .isEqualTo(123456); } @Test public void whenCalledisDigits_thenCorrect() { assertThat(NumberUtils.isDigits("123456")).isTrue(); } 

Quando si tratta di trovare i valori mix e max di un array fornito, la classe NumberUtils fornisce un forte supporto per queste operazioni attraverso le implementazioni sovraccaricate dei metodi 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. La classe delle frazioni

Lavorare con le frazioni va bene e va bene quando usiamo una penna e un pezzo di carta. Ma dobbiamo affrontare le complessità di questo processo durante la scrittura del codice? Non proprio.

La classe Fraction semplifica l'aggiunta, la sottrazione e la moltiplicazione di frazioni :

@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"); }

Sebbene le operazioni con le frazioni non siano certamente l'attività più frequente che dovremo affrontare nel nostro lavoro di sviluppo quotidiano, la classe Fraction fornisce un valido supporto per eseguire queste operazioni in modo diretto.

7. La classe SystemUtils

A volte, abbiamo bisogno di ottenere alcune informazioni dinamiche su diverse proprietà e variabili della piattaforma Java sottostante o del sistema operativo.

Apache Commons Lang 3 fornisce la classe SystemUtils per eseguire ciò in modo indolore .

Consideriamo, ad esempio, i metodi 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(); }

There are a few additional utility methods that the SystemUtils class implements. We've omitted them to keep the examples short.

8. The Lazy Initialization and Builder Classes

One of Apache Commons Lang 3's most appealing facet is the implementation of some well-known design patterns, including the lazy-initialization and builder patterns.

For instance, let's say that we have created an expensive User class (not shown for brevity), and want to defer its instantiation until it's really needed.

In such a case, all that we need to do is to extend the parameterized LazyInitializer abstract class and override its initialize() method:

public class UserInitializer extends LazyInitializer { @Override protected User initialize() { return new User("John", "[email protected]"); } }

Now, if we want to get our costly User object when it's required, we just call the UserInitializer's get() method:

@Test public void whenCalledget_thenCorrect() throws ConcurrentException { UserInitializer userInitializer = new UserInitializer(); assertThat(userInitializer.get()).isInstanceOf(User.class); }

The get() method is an implementation of the double-check idiom (thread-safe) for an instance field, as specified in Joshua Bloch's “Effective Java”, item 71:

private volatile User instance; User get() { if (instance == null) { synchronized(this) { if (instance == null) instance = new User("John", "[email protected]"); } } } return instance; }

In addition, Apache Commons Lang 3 implements the HashCodeBuilder class, which allows us to generate hashCode() implementations by supplying the builder with different parameters, based on a typical fluent API:

@Test public void whenCalledtoHashCode_thenCorrect() { int hashcode = new HashCodeBuilder(17, 37) .append("John") .append("[email protected]") .toHashCode(); assertThat(hashcode).isEqualTo(1269178828); }

We can do something similar with the BasicThreadFactory class, and create daemon threads with a naming pattern and a priority:

@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. The ConstructorUtils Class

Reflection is a first-class citizen in Apache Commons Lang 3.

The library includes several reflection classes, which allows us to reflectively access and manipulate class fields and methods.

For example, let's say that we've implemented a naive User domain class:

public class User { private String name; private String email; // standard constructors / getters / setters / toString }

Assuming that its parameterized constructor is public, we can easily access it with the ConstructorUtils class:

@Test public void whenCalledgetAccessibleConstructor_thenCorrect() { assertThat(ConstructorUtils .getAccessibleConstructor(User.class, String.class, String.class)) .isInstanceOf(Constructor.class); } 

Alternatively to standard class instantiation via constructors, we can reflectively create User instances by just calling the invokeConstructor() and invokeExactConstructor() methods:

@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. The FieldUtils Class

Similarly, we can use the methods of the FieldUtils class for reflectively reading/writing class fields.

Let's suppose that we want to get a field of the User class, or eventually a field that the class is inheriting from a superclass.

In such a case, we can invoke the getField() method:

@Test public void whenCalledgetField_thenCorrect() { assertThat(FieldUtils.getField(User.class, "name", true).getName()) .isEqualTo("name"); } 

Alternatively, if we'd want to use a more restrictive reflection scope, and only get a field declared in the User class, and not inherited from a superclass, we'd just use the getDeclaredField() method:

@Test public void whenCalledgetDeclaredFieldForceAccess_thenCorrect() { assertThat(FieldUtils.getDeclaredField(User.class, "name", true).getName()) .isEqualTo("name"); }

In addition, we can use the getAllFields() method for getting the number of fields of the reflected class, and write a value to a declared field or a field defined up in a hierarchy with the writeField() and writeDeclaredField() methods:

@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. The MethodUtils Class

Along the same lines, we can use reflection on class methods with the MethodUtils class.

In this case, the visibility of the User class' getName() method is public. So, we can access it with the getAccessibleMethod() method:

@Test public void whenCalledgetAccessibleMethod_thenCorrect() { assertThat(MethodUtils.getAccessibleMethod(User.class, "getName")) .isInstanceOf(Method.class); } 

When it comes to reflectively invoking methods, we can use the invokeExactMethod() and invokeMethod() methods:

@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. The MutableObject Class

While immutability is a key feature of good object-oriented software that we should default to in every possible case, unfortunately sometimes we need to deal with mutable objects.

Moreover, creating mutable classes requires a lot of boilerplate code, which can be generated by most IDEs through auto-generated setters.

To this end, Apache Commons Lang 3 provides the MutableObject class, a simple wrapper class for creating mutable objects with minimal fuss:

@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"); } 

Of course, this is just an example of how to use the MutableObject class.

As rule of thumb, we should always strive to create immutable classes, or in the worst case, provide only the required level of mutability.

13. The MutablePair Class

Interestingly enough, Apache Commons Lang 3 provides strong support for tuples, in the form of pairs and triples.

So, let's suppose that we need to create a mutable pair of ordered elements.

In such a case, we'd use the MutablePair class:

private static MutablePair 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"); } 

The most relevant detail worth stressing here is the class' clean API.

It allows us to set and access the left and right objects wrapped by the pair through the standard setters/getters.

14. The ImmutablePair Class

Unsurprisingly, there's also an immutable counterpart implementation of the MutablePair class, called ImmutablePair:

private static ImmutablePair 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"); } 

As we might expect from an immutable class, any attempt to change the pair's internal state through the setValue() method will result in throwing an UnsupportedOperationException exception.

15. The Triple Class

The last utility class that will look at here is Triple.

As the class is abstract, we can create Triple instances by using the of() static factory method:

@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"); }

There are also concrete implementations for both mutable and immutable triples, through the MutableTriple and ImmutableTriple classes.

We can create their instances via parameterized constructors, rather than with a static factory method.

In this case, we'll just skip them, as their APIs look very similar to the ones of the MutablePair and ImmutablePair classes.

16. Conclusion

In this tutorial, we took an in-depth look at some of the most useful utility classes that Apache Commons Lang 3 provides off the shelf .

La libreria implementa molte altre classi di utilità degne di nota . Qui, abbiamo appena mostrato i più utili, basati su un criterio piuttosto supponente.

Per l'API della libreria completa, controlla i Javadoc ufficiali.

Come al solito, tutti gli esempi di codice mostrati in questo tutorial sono disponibili su GitHub.