1. 概要

Apache Commons Lang3ライブラリは、Java API の機能を拡張することを目的とした、人気のあるフル機能のユーティリティクラスのパッケージです。

ライブラリのレパートリーは、文字列、配列、数値の操作、反映、同時実行から、ペアやトリプル(一般にタプル)などのいくつかの順序付けられたデータ構造の実装に至るまで、非常に豊富です。

このチュートリアルでは、ライブラリの最も便利なユーティリティクラスについて詳しく説明します。

2. Mavenの依存関係

いつものように、Apache Commons Lang 3の使用を開始するには、最初にMaven依存関係を追加する必要があります。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>

3. StringUtilsクラス

この紹介のまとめで取り上げる最初のユーティリティクラスは、StringUtils。です。

その名前が示すように、 StringUtilsを使用すると、java.lang.Stringが提供するものを補完/拡張する一連のnullセーフ文字列操作を実行できます

文字列が空白、空、小文字、大文字、英数字など、特定の文字列に対していくつかのチェックを実行する一連のユーティリティメソッドの紹介を始めましょう。

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

もちろん、 StringUtils クラスは他の多くのメソッドを実装しますが、簡単にするためにここでは省略しました。

特定の文字列に特定のタイプの変換アルゴリズムをチェックまたは適用するその他の追加の方法については、このチュートリアルをチェックしてください。

上で説明したものは本当に簡単なので、単体テストは自明である必要があります。

4. ArrayUtilsクラス

ArrayUtilsクラスは、さまざまな形状や形式の配列を処理およびチェックできるユーティリティメソッドのバッチを実装します

toString()メソッドの2つのオーバーロードされた実装から始めましょう。このメソッドは、指定された配列と特定の文字列文字列表現を返します。 ] 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");
}

次に、 hasCode()メソッドと toMap()メソッドがあります。

前者は配列のカスタムhashCode実装を生成し、後者は配列マップに変換します。

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

最後に、 isSameLength()メソッドと indexOf()メソッドを見てみましょう。

前者は2つの配列の長さが同じかどうかを確認するために使用され、後者は特定の要素のインデックスを取得するために使用されます。

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

StringUtils クラスと同様に、ArrayUtilsはさらに多くの追加メソッドを実装します。 それらについて詳しくは、このチュートリアルをご覧ください。

この場合、最も代表的なものだけを紹介しました。

5. NumberUtilsクラス

Apache Commons Lang 3のもう1つの重要なコンポーネントは、NumberUtilsクラスです。

予想通り、クラスは、数値型の処理と操作を目的とした多数のユーティリティメソッドを提供します

compare()メソッドのオーバーロードされた実装を見てみましょう。このメソッドは、intlongなどのさまざまなプリミティブの同等性を比較します。

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

さらに、 byteおよびshortで動作するcompare()の実装があり、これらは上記の例と非常によく似ています。

このレビューの次は、 createNumber()および isDigit()メソッドです。

1つ目は、文字列の数値表現を作成できるようにし、2つ目は、文字列が数字のみで構成されているかどうかを確認します。

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

提供された配列のミックス値と最大値を見つける場合、 NumberUtils クラスは、 min() 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.分数クラス

ペンと一枚の紙を使用する場合、分数での作業はすべてうまくいきます。 しかし、コードを書くとき、このプロセスの複雑さを経験する必要がありますか? あまり。

Fractionクラスは、簡単に分数の加算、減算、乗算を行います

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

分数を使用した操作は、日常の開発作業で取り組む必要のある最も頻繁なタスクではありませんが、分数クラスは、これらの操作を簡単に実行するための貴重なサポートを提供します。

7. SystemUtilsクラス

場合によっては、基盤となるJavaプラットフォームまたはオペレーティングシステムのさまざまなプロパティや変数に関する動的な情報を取得する必要があります。

Apache Commons Lang 3は、これを簡単な方法で実現するためのSystemUtilsクラスを提供します

たとえば、 getJavaHome() getUserHome()、および 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();
}

SystemUtilsクラスが実装する追加のユーティリティメソッドがいくつかあります。 例を短くするために、これらは省略しています。

8. レイジー初期化とビルダークラス

Apache Commons Lang 3の最も魅力的な側面の1つは、レイジー初期化やビルダーパターンなどのよく知られたデザインパターンの実装です。

たとえば、高価な User クラス(簡潔にするために表示されていません)を作成し、実際に必要になるまでそのインスタンス化を延期したいとします。

このような場合、必要なのは、パラメーター化された LazyInitializer 抽象クラスを拡張し、その initialize()メソッドをオーバーライドすることだけです。

public class UserInitializer extends LazyInitializer<User> {

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

ここで、必要なときにコストのかかる User オブジェクトを取得する場合は、 UserInitializerのget()メソッドを呼び出すだけです。

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

get()メソッドは、 Joseph Blochの「EffectiveJava」、アイテム71 で指定されている、インスタンスフィールドのダブルチェックイディオム(スレッドセーフ)の実装です。 :

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

さらに、Apache CommonsLang3はHashCodeBuilderクラスを実装します。これにより、一般的な流暢なAPIに基づいて、ビルダーにさまざまなパラメーターを提供することで hashCode()実装を生成できます。

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

BasicThreadFactory クラスと同様のことを行い、命名パターンと優先度を使用してデーモンスレッドを作成できます。

@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. ConstructorUtilsクラス

Reflectionは、Apache CommonsLang3の第一級市民です。

ライブラリにはいくつかのリフレクションクラスが含まれているため、クラスフィールドとメソッドにリフレクティブにアクセスして操作できます。

たとえば、ナイーブなUserドメインクラスを実装したとします。

public class User {

    private String name;
    private String email;
    
    // standard constructors / getters / setters / toString
}

パラメータ化されたコンストラクタがpublicであるとすると、ConstructorUtilsクラスを使用して簡単にアクセスできます。

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

コンストラクターを介した標準のクラスインスタンス化の代わりに、 invokeConstructor()および invokeExactConstructor()メソッドを呼び出すだけで、Userインスタンスを反射的に作成できます。

@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. FieldUtilsクラス

同様に、 FieldUtilsクラスのメソッドを使用して、クラスフィールドの反射的な読み取り/書き込みを行うことができます

User クラスのフィールド、または最終的にはクラスがスーパークラスから継承しているフィールドを取得したいとします。

このような場合、 getField()メソッドを呼び出すことができます。

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

または、より制限的なリフレクションスコープを使用し、Userクラスで宣言されたフィールドのみを取得し、スーパークラスから継承しない場合は、 getDeclaredField( )メソッド:

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

さらに、 getAllFields()メソッドを使用して、反映されたクラスのフィールド数を取得し、宣言されたフィールドまたはwriteFieldを使用して階層で定義されたフィールドに値を書き込むことができます。 ()および writeDeclaredField()メソッド:

@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. MethodUtilsクラス

同じように、MethodUtilsクラスのクラスメソッドでリフレクションを使用できます。

この場合、 UserクラスのgetName()メソッドの可視性はpublicです。 したがって、 getAccessibleMethod()メソッドを使用してアクセスできます。

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

メソッドを反射的に呼び出す場合は、 invokeExactMethod()および 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. MutableObjectクラス

不変性は優れたオブジェクト指向ソフトウェアの重要な機能であり、考えられるすべての場合にデフォルトにする必要がありますが、残念ながら、可変オブジェクトを処理する必要がある場合があります。

さらに、可変クラスを作成するには、多くのボイラープレートコードが必要です。これは、自動生成されたセッターを介してほとんどのIDEで生成できます。

この目的のために、Apache Commons Lang 3は、 MutableObject クラスを提供します。これは、最小限の手間で可変オブジェクトを作成するための単純なラッパークラスです。

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

もちろん、これはMutableObjectクラスの使用方法の一例にすぎません。

経験則として、常に不変のクラスを作成するように努める必要があります。最悪の場合、必要なレベルの可変性のみを提供する必要があります

13. MutablePairクラス

興味深いことに、Apache Commons Lang 3は、ペアとトリプルの形式でタプルを強力にサポートします。

したがって、順序付けられた要素の可変ペアを作成する必要があると仮定しましょう。

このような場合、MutablePairクラスを使用します。

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

ここで強調する価値のある最も関連性の高い詳細は、クラスのクリーンなAPIです。

これにより、標準のセッター/ゲッターを介して、ペアでラップされた左右のオブジェクトを設定してアクセスできます。

14. ImmutablePairクラス

当然のことながら、ImmutablePairと呼ばれるMutablePairクラスの不変の対応する実装もあります。

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

不変のクラスから予想されるように、 setValue()メソッドを使用してペアの内部状態を変更しようとすると、UnsupportedOperationException例外がスローされます。

15. トリプルクラス

ここで見る最後のユーティリティクラスはTripleです。

クラスは抽象であるため、 of()静的ファクトリメソッドを使用してTripleインスタンスを作成できます。

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

MutableTripleおよびImmutableTripleクラスを介して、可変トリプルと不変トリプルの両方の具体的な実装もあります。

静的ファクトリメソッドではなく、パラメータ化されたコンストラクタを介してインスタンスを作成できます。

この場合、APIはMutablePairおよびImmutablePairクラスのものと非常によく似ているため、スキップします。

16. 結論

このチュートリアルでは、Apache CommonsLang3が提供する最も便利なユーティリティクラスのいくつかを詳しく見てきました

ライブラリは、一見の価値がある他の多くのユーティリティクラスを実装していますここでは、かなり意見の分かれる基準に基づいて、最も有用なものを紹介しました。

完全なライブラリAPIについては、公式Javadocを確認してください。

いつものように、このチュートリアルに示されているすべてのコードサンプルは、GitHubから入手できます。