Eine Einführung in Apache Commons Lang 3

Eine Einführung in Apache Commons Lang 3

1. Überblick

The Apache Commons Lang 3 libraryis a popular, full-featured package of utility classes, aimed at extending the functionality of the Java API.

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 bekannt alstuples).

In diesem Tutorial werdenwe’ll take a deep dive at the library’s most useful utility classes.

2. Die Maven-Abhängigkeit

Wie üblich müssen Sie zunächstMaven dependency hinzufügen, um mit Apache Commons Lang 3 arbeiten zu können:


    org.apache.commons
    commons-lang3
    3.8

3. DieStringUtils Klasse

Die erste Utility-Klasse, die wir in dieser einführenden Zusammenfassung behandeln, istStringUtils.

Wie der Name schon sagt,StringUtils allows us to perform a bunch of null-safe strings operations that complement/extend the ones that java.lang.String provides out of the box.

Lassen Sie uns zunächst eine Reihe von Dienstprogrammmethoden vorstellen, mit denen mehrere Überprüfungen für ein bestimmtesstringdurchgeführt werden, z. B. um festzustellen, obstringleer, 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 KlasseStringUtilsviele andere Methoden, die wir hier der Einfachheit halber weggelassen haben.

Für einige andere zusätzliche Methoden, die einen Konvertierungsalgorithmus überprüfen oder auf einen bestimmtenstring anwenden, geben Sie bittecheck this tutorial an.

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

4. DieArrayUtils Klasse

The ArrayUtils class implements a batch of utility methods that allow us to process and check arrays in many different shapes and forms.

Beginnen wir mit den zwei überladenen Implementierungen derthe toString()-Methode, die einestring-Darstellung der angegebenenarray und eine bestimmtestring zurückgibt, wennarray 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 MethodenhasCode() undtoMap().

Ersteres generiert eine benutzerdefiniertehashCode-Implementierung für einarray,, während letzteres einarray in einMap 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);
}

Schauen wir uns zum Schluss die MethodenisSameLength() undindexOf()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 KlasseStringUtils implementierenArrayUtilsviel mehr zusätzliche Methoden. Sie können mehr über sie inthis tutorial erfahren.

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

5. DieNumberUtils Klasse

Eine weitere Schlüsselkomponente von Apache Commons Lang 3 ist die KlasseNumberUtils.

Wie erwartet,the class provides an extensive number of utility methods, aimed at processing and manipulating numeric types.

Schauen wir uns die überladenen Implementierungen dercompare()-Methode an, die die Gleichheit verschiedener Grundelemente wieint undlong 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 voncompare(), die mitbyte undshort arbeiten und den obigen Beispielen sehr ähnlich sind.

Als nächstes werden in dieser Übersicht die MethodencreateNumber() undisDigit() aufgeführt.

Mit dem ersten können wir eine numerische Darstellung vonstring erstellen, während mit dem zweiten geprüft wird, ob einstring 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 KlasseNumberUtils durch die überladenen Implementierungen der Methodenmin() undmax() eine starke Unterstützung für diese Operationen:

@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. DieFraction Class

Das Arbeiten mit Brüchen ist in Ordnung, wenn wir einen Stift und ein Stück Papier verwenden. Aber müssen wir die Komplexität dieses Prozesses durchgehen, wenn wir Code schreiben? Nicht wirklich.

The Fraction class makes adding, subtracting and multiplying fractions in a breeze:

@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 dieFraction-Klasse wertvolle Unterstützung für die einfache Durchführung dieser Operationen.

7. DieSystemUtils Klasse

Manchmal müssen dynamische Informationen zu verschiedenen Eigenschaften und Variablen der zugrunde liegenden Java-Plattform oder des Betriebssystems abgerufen werden.

Apache Commons Lang 3 provides the SystemUtils class for accomplishing this in a painless way.

Betrachten wir zum Beispiel die MethodengetJavaHome(),getUserHome() undisJavaVersionAtLeast():

@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 die KlasseSystemUtilsimplementiert. Wir haben sie weggelassen, um die Beispiele kurz zu halten.

8. Die Lazy Initialization- und Builder-Klassen

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.

Nehmen wir zum Beispiel an, wir haben eine teureUser-Klasse 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 abstrakte Klasse des parametrisiertenLazyInitializererweitern und die Methodeinitialize()überschreiben:

public class UserInitializer extends LazyInitializer {

    @Override
    protected User initialize() {
        return new User("John", "[email protected]");
    }
}

Wenn wir nun unser teuresUser-Objekt bei Bedarf abrufen möchten, rufen wir einfach dieUserInitializer’s get()-Methode auf:

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

Darüber hinaus implementiert Apache Commons Lang 3 dieHashCodeBuilder-Klasse, mit der wirhashCode()-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 KlasseBasicThreadFactorykö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. DieConstructorUtils Klasse

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

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

Angenommen, wir haben eine naiveUser-Domänenklasse implementiert:

public class User {

    private String name;
    private String email;

    // standard constructors / getters / setters / toString
}

Angenommen, sein parametrisierter Konstruktor istpublic, können wir mit der KlasseConstructorUtils leicht 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 die Instanzen vonUserreflektierend erstellen, indem wir einfach die MethodeninvokeConstructor() undinvokeExactConstructor()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. DieFieldUtils Klasse

In ähnlicher Weise istwe can use the methods of the FieldUtils class for reflectively reading/writing class fields.

Nehmen wir an, wir möchten ein Feld derUser-Klasse oder schließlich ein Feld erhalten, das die Klasse von einer Oberklasse erbt.

In einem solchen Fall können wir die MethodegetField()aufrufen:

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

Alternativ,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, verwenden wir einfach diegetDeclaredField()-Methode:

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

Darüber hinaus können wir diegetAllFields()-Methode verwenden, um die Anzahl der Felder der reflektierten Klasse abzurufen, und einen Wert in ein deklariertes Feld oder ein Feld schreiben, das in einer Hierarchie mitwriteField() undwriteDeclaredField() Methoden:

@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. DieMethodUtils Klasse

In diesem Sinne können wir die Klassenmethoden mit der KlasseMethodUtilsreflektieren.

In diesem Fall beträgt die Sichtbarkeit dergetName()-Methode derUser-Klassepublic. Wir können also mit der MethodegetAccessibleMethod()darauf zugreifen:

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

Wenn es darum geht, Methoden reflektierend aufzurufen, können wir die MethodeninvokeExactMethod() undinvokeMethod() verwenden:

@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. DieMutableObject Klasse

While immutability is a key feature of good object-oriented software that we should default to in every possible case, leider müssen wir uns manchmal mit veränderlichen Objekten befassen.

Darüber hinaus erfordert das Erstellen veränderlicher Klassen eine Menge Code, der von den meisten IDEs über automatisch generierte Setter generiert werden kann.

Zu diesem Zweck bietet Apache Commons Lang 3 die KlasseMutableObject, eine einfache Wrapper-Klasse zum Erstellen veränderlicher Objekte mit minimalem Aufwand:

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

Dies ist natürlich nur ein Beispiel für die Verwendung der KlasseMutableObject.

Als Faustregel giltwe should always strive to create immutable classes, or in the worst case, provide only the required level of mutability.

13. DieMutablePair Klasse

Interessanterweise bietet Apache Commons Lang 3 eine starke Unterstützung für Tupel in Form von Paaren und Tripeln.

Nehmen wir also an, wir müssen ein veränderliches Paar geordneter Elemente erstellen.

In einem solchen Fall verwenden wir die KlasseMutablePair:

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

Das wichtigste Detail, das hier hervorgehoben werden sollte, ist die saubere API der Klasse.

Es ermöglicht uns das Setzen und Zugreifen auf die linken und rechten Objekte, die vom Paar durch die Standard-Setter / Getter umwickelt werden.

14. DieImmutablePair Klasse

Es ist nicht überraschend, dass es auch eine unveränderliche Gegenstückimplementierung der KlasseMutablePairgibt, die alsImmutablePairbezeichnet wird:

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

Wie wir es von einer unveränderlichen Klasse erwarten können, führt jeder Versuch, den internen Zustand des Paares durch die MethodesetValue()zu ändern, dazu, dass eine AusnahmeUnsupportedOperationExceptionausgelöst wird.

15. The Triple Class

Die letzte Dienstprogrammklasse, die hier angezeigt wird, istTriple.

Da die Klasse abstrakt ist, können wir die Instanzen vonTriplemithilfe der statischen Factory-Methode vonof()erstellen:

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

Es gibt auch konkrete Implementierungen für veränderliche und unveränderliche Tripel in den KlassenMutableTriple undImmutableTriple.

Wir können ihre Instanzen über parametrisierte Konstruktoren anstatt mit einer statischen Factory-Methode erstellen.

In diesem Fall überspringen wir sie einfach, da ihre APIs denen der KlassenMutablePair undImmutablePair sehr ähnlich sehen.

16. Fazit

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

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

Überprüfen Sie für die vollständige Bibliotheks-API dieofficial Javadocs.

Wie üblich sind alle in diesem Lernprogramm gezeigten Codebeispiele überGitHub verfügbar.