Eine Einführung in Apache Commons Lang 3

1. Übersicht

Die Apache Commons Lang 3-Bibliothek ist ein beliebtes Paket von Dienstprogrammklassen mit vollem Funktionsumfang, mit dem die Funktionalität der Java-API erweitert werden soll .

Das Repertoire der Bibliothek ist ziemlich umfangreich und reicht von der Manipulation von Strings, Arrays und Zahlen über Reflexion und Parallelität bis hin zur Implementierung mehrerer geordneter Datenstrukturen wie Paare und Tripel (allgemein als Tupel bekannt).

In diesem Tutorial werden wir uns eingehend mit den nützlichsten Utility-Klassen der Bibliothek befassen .

2. Die Maven-Abhängigkeit

Wie üblich müssen wir zunächst die Maven-Abhängigkeit hinzufügen, um mit Apache Commons Lang 3 arbeiten zu können:

 org.apache.commons commons-lang3 3.8 

3. Die StringUtils- Klasse

Die erste Utility-Klasse, die wir in dieser Einführung behandeln werden, ist StringUtils.

Wie der Name schon sagt, StringUtils ermöglicht es uns , eine Reihe von Null-safe s auszuführen Trings Operationen , die Ergänzung / diejenigen erweitern , dass java.lang.String der Box sieht aus .

Beginnen wir mit der Darstellung der Dienstprogrammmethoden, mit denen mehrere Überprüfungen für eine bestimmte Zeichenfolge durchgeführt werden , z. B. um festzustellen, ob die Zeichenfolge leer, leer, in Kleinbuchstaben, Großbuchstaben, alphanumerisch usw. ist:

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

Natürlich implementiert die StringUtils- Klasse viele andere Methoden, die wir hier der Einfachheit halber weggelassen haben.

Weitere zusätzliche Methoden zum Überprüfen oder Anwenden eines Konvertierungsalgorithmus auf eine bestimmte Zeichenfolge finden Sie in diesem Lernprogramm.

Die oben beschriebenen sind sehr einfach, daher sollten die Komponententests selbsterklärend sein.

4. Die ArrayUtils- Klasse

Die ArrayUtils- Klasse implementiert eine Reihe von Dienstprogrammmethoden, mit denen wir Arrays in vielen verschiedenen Formen und Formen verarbeiten und überprüfen können .

Beginnen wir mit den beiden überladenen Implementierungen der toString () -Methode, die eine Zeichenfolgendarstellung des angegebenen Arrays und eine bestimmte Zeichenfolge zurückgibt, wenn das Array null ist:

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

Als nächstes haben wir die Methoden hasCode () und toMap () .

Ersteres generiert eine benutzerdefinierte HashCode-Implementierung für ein Array, während letzteres ein Array in eine Map konvertiert :

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

Zuletzt schauen wir uns die Methoden isSameLength () und indexOf () an.

Ersteres wird verwendet, um zu überprüfen, ob zwei Arrays dieselbe Länge haben, und letzteres, um den Index eines bestimmten Elements abzurufen:

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

Wie bei der StringUtils- Klasse implementieren ArrayUtils viel mehr zusätzliche Methoden. In diesem Tutorial erfahren Sie mehr darüber.

In diesem Fall haben wir nur die repräsentativsten vorgestellt.

5. Die NumberUtils- Klasse

Eine weitere Schlüsselkomponente von Apache Commons Lang 3 ist die NumberUtils-Klasse.

Wie erwartet bietet die Klasse eine Vielzahl von Dienstprogrammmethoden, mit denen numerische Typen verarbeitet und bearbeitet werden können .

Schauen wir uns die überladenen Implementierungen der compare () -Methode an, die die Gleichheit verschiedener Grundelemente wie int und long vergleicht :

@Test public void whenCalledcompareWithIntegers_thenCorrect() { assertThat(NumberUtils.compare(1, 1)) .isEqualTo(0); } @Test public void whenCalledcompareWithLongs_thenCorrect() { assertThat(NumberUtils.compare(1L, 1L)) .isEqualTo(0); }

Darüber hinaus gibt es Implementierungen von compare () , die mit Byte und Short arbeiten und den obigen Beispielen sehr ähnlich sind.

Als nächstes folgen in dieser Überprüfung die Methoden createNumber () und isDigit () .

Mit der ersten können wir eine numerische Darstellung einer Zeichenfolge erstellen , während mit der zweiten überprüft wird, ob eine Zeichenfolge nur aus Ziffern besteht:

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

Wenn es darum geht, die Mix- und Max-Werte eines bereitgestellten Arrays zu ermitteln, bietet die NumberUtils- Klasse eine starke Unterstützung für diese Operationen durch die überladenen Implementierungen der Methoden min () und 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. Die Fraktion Klasse

Die Arbeit mit Brüchen ist in Ordnung und gut, wenn wir einen Stift und ein Stück Papier verwenden. Aber müssen wir beim Schreiben von Code die Komplexität dieses Prozesses durchgehen? Nicht wirklich.

Mit der Fraction- Klasse können Sie Brüche ganz einfach addieren, subtrahieren und multiplizieren :

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

Während Operationen mit Brüchen sicherlich nicht die häufigste Aufgabe sind, die wir in unserer täglichen Entwicklungsarbeit angehen müssen, bietet die Fraction- Klasse wertvolle Unterstützung für die einfache Durchführung dieser Operationen.

7. Die SystemUtils- Klasse

Manchmal müssen wir dynamische Informationen über verschiedene Eigenschaften und Variablen der zugrunde liegenden Java-Plattform oder des Betriebssystems erhalten.

Apache Commons Lang 3 bietet die SystemUtils-Klasse, um dies auf schmerzlose Weise zu erreichen .

Betrachten wir zum Beispiel die Methoden getJavaHome () , getUserHome () und 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(); }

Es gibt einige zusätzliche Dienstprogrammmethoden, die von der SystemUtils- Klasse implementiert werden. Wir haben sie weggelassen, um die Beispiele kurz zu halten.

8. Die Lazy Initialization- und Builder-Klassen

Eine der attraktivsten Facetten von Apache Commons Lang 3 ist die Implementierung einiger bekannter Entwurfsmuster, einschließlich der Lazy-Initialisierungs- und Builder-Muster .

Nehmen wir zum Beispiel an, wir haben eine teure Benutzerklasse erstellt (der Kürze halber nicht gezeigt) und möchten ihre Instanziierung verschieben, bis sie wirklich benötigt wird.

In einem solchen Fall müssen wir lediglich die parametrisierte abstrakte LazyInitializer-Klasse erweitern und ihre initialize () -Methode überschreiben :

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

Wenn wir unser teures User- Objekt bei Bedarf abrufen möchten, rufen wir einfach die get () -Methode des UserInitializers auf :

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

Die get () -Methode ist eine Implementierung des Double-Check-Idioms (thread-safe) für ein Instanzfeld, wie in Joshua Blochs „Effective Java“, Punkt 71, angegeben :

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

Darüber hinaus implementiert Apache Commons Lang 3 die HashCodeBuilder-Klasse, mit der wir hashCode () -Implementierungen generieren können , indem wir dem Builder verschiedene Parameter bereitstellen, die auf einer typischen fließenden API basieren:

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

Mit der BasicThreadFactory- Klasse können wir etwas Ähnliches tun und Daemon-Threads mit einem Namensmuster und einer Priorität erstellen:

@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. Die ConstructorUtils- Klasse

Reflection ist ein erstklassiger Bürger in Apache Commons Lang 3.

Die Bibliothek enthält mehrere Reflexionsklassen, mit denen wir reflektierend auf Klassenfelder und -methoden zugreifen und diese bearbeiten können.

Angenommen, wir haben eine naive Benutzerdomänenklasse implementiert :

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

Unter der Annahme, dass der parametrisierte Konstruktor öffentlich ist , können wir mit der ConstructorUtils- Klasse problemlos darauf zugreifen :

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

Alternativ zur Standardklasseninstanziierung über Konstruktoren können wir Benutzerinstanzen reflektierend erstellen, indem wir einfach die Methoden invokeConstructor () und invokeExactConstructor () aufrufen :

@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. Die FieldUtils- Klasse

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 .

Die Bibliothek implementiert viele andere Dienstprogrammklassen, die einen Blick wert sind . Hier haben wir nur die nützlichsten vorgestellt, basierend auf einem ziemlich einfühlsamen Kriterium.

Die vollständige Bibliotheks-API finden Sie in den offiziellen Javadocs.

Wie üblich sind alle in diesem Tutorial gezeigten Codebeispiele auf GitHub verfügbar.