Введение в Apache Commons Lang 3

Введение в Apache Commons Lang 3

1. обзор

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

Репертуар библиотеки довольно богат: от операций со строками, массивами и числами, отражения и параллелизма до реализаций нескольких упорядоченных структур данных, таких как пары и тройки (обычно известные какtuples).

В этом руководствеwe’ll take a deep dive at the library’s most useful utility classes.

2. Зависимость Maven

Как обычно, чтобы начать использовать Apache Commons Lang 3, нам сначала нужно добавитьMaven dependency:


    org.apache.commons
    commons-lang3
    3.8

3. КлассStringUtils

Первый служебный класс, который мы рассмотрим в этом вводном обзоре, - этоStringUtils..

Как следует из названия,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.

Давайте начнем демонстрировать набор служебных методов, которые выполняют несколько проверок для данногоstring, например, определяют, является лиstring пустым, пустым, в нижнем регистре, в верхнем регистре, буквенно-цифровым и т. Д.

@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 реализует множество других методов, которые мы здесь для простоты опустили.

Для некоторых других дополнительных методов, которые проверяют или применяют какой-либо алгоритм преобразования к заданномуstring, пожалуйста,check this tutorial.

Те, которые мы рассмотрели выше, действительно просты, поэтому модульные тесты не требуют пояснений.

4. КлассArrayUtils

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

Давайте начнем с двух перегруженных реализаций методаthe toString(), который возвращает представлениеstring данногоarray и конкретныйstring, когда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 дляarray,, а второй преобразуетarray вMap:

@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().

Первый используется для проверки, имеют ли два массива одинаковую длину, а второй для получения индекса данного элемента:

@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 реализовано гораздо больше дополнительных методов. Вы можете узнать о них больше вthis tutorial.

В данном случае мы представили только самые представительные.

5. КлассNumberUtils

Другой ключевой компонент Apache Commons Lang 3 - это классNumberUtils.

Как и ожидалось,the class provides an extensive number of utility methods, aimed at processing and manipulating numeric types.

Давайте посмотрим на перегруженные реализации методаcompare(), который сравнивает равенство различных примитивов, таких какint и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);
}

Кроме того, существуют реализацииcompare(), которые работают сbyte иshort, которые работают очень похоже на приведенные выше примеры.

Следующими в этом обзоре идут методыcreateNumber() иisDigit().

Первый позволяет нам создать числовое представлениеstring, а второй проверяет, состоит лиstring только из цифр:

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

Работать с дробями - это нормально, когда мы используем ручку и лист бумаги. Но должны ли мы пройти через все сложности этого процесса при написании кода? На самом деле, нет.

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

Хотя операции с дробями, безусловно, не самая частая задача, с которой нам придется сталкиваться в нашей повседневной работе по разработке, классFraction обеспечивает ценную поддержку для выполнения этих операций простым способом.

7. КлассSystemUtils

Иногда нам нужно получить некоторую динамическую информацию о различных свойствах и переменных базовой платформы Java или операционной системы.

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

Рассмотрим, например, методы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. Ленивая инициализация и классы построителя

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.

Например, предположим, что мы создали дорогостоящий классUser (не показан для краткости) и хотим отложить его создание до тех пор, пока он действительно не понадобится.

В таком случае все, что нам нужно сделать, это расширить параметризованный абстрактный классLazyInitializer и переопределить его методinitialize():

public class UserInitializer extends LazyInitializer {

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

Теперь, если мы хотим получить наш дорогостоящий объектUser, когда он потребуется, мы просто вызываем методUserInitializer’s get():

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

Кроме того, Apache Commons Lang 3 реализует классHashCodeBuilder, который позволяет нам создавать реализацииhashCode(), предоставляя построителю различные параметры на основе типичного свободного API:

@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 Commons Lang 3.

Библиотека включает в себя несколько классов отражений, что позволяет нам рефлексивно обращаться к полям и методам классов и манипулировать ими.

Например, предположим, что мы реализовали простой доменный класс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);
}

В качестве альтернативы стандартному созданию экземпляров класса через конструкторы, мы можем рефлексивно создавать экземплярыUser, просто вызывая методыinvokeConstructor() и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. КлассFieldUtils

Аналогичноwe can use the methods of the FieldUtils class for reflectively reading/writing class fields.

Предположим, мы хотим получить поле классаUser или, в конечном итоге, поле, которое класс наследует от суперкласса.

В таком случае мы можем вызвать методgetField():

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

В качестве альтернативы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, мы бы просто использовали метод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.

В этом случае видимость методаgetName() классаUser составляет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

While immutability is a key feature of good object-oriented software that we should default to in every possible case, к сожалению, иногда нам приходится иметь дело с изменяемыми объектами.

Кроме того, создание изменяемых классов требует большого количества стандартного кода, который может быть сгенерирован большинством 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.

Как показывает опыт,we should always strive to create immutable classes, or in the worst case, provide only the required level of mutability.

13. КлассMutablePair

Интересно, что Apache Commons Lang 3 обеспечивает мощную поддержку кортежей в виде пар и троек.

Итак, предположим, что нам нужно создать изменяемую пару упорядоченных элементов.

В таком случае мы бы использовали классMutablePair:

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

Наиболее важная деталь, на которую стоит обратить внимание, - это чистый API класса.

Это позволяет нам устанавливать и получать доступ к левому и правому объектам, обернутым парой, через стандартные методы установки / получения.

14. КлассImmutablePair

Неудивительно, что существует также неизменяемая реализация классаMutablePair, называемая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");
}

Как и следовало ожидать от неизменяемого класса, любая попытка изменить внутреннее состояние пары с помощью методаsetValue() приведет к сбору исключенияUnsupportedOperationException.

15. The Triple Classс

Последний служебный класс, который мы рассмотрим здесь, - этоTriple.

Поскольку класс является абстрактным, мы можем создавать экземплярыTriple, используя статический фабричный методof():

@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 очень похожи на API классовMutablePair иImmutablePair.

16. Заключение

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

В библиотеке реализовано множество других служебных классов, на которые стоит обратить внимание.. Здесь мы только что продемонстрировали самые полезные из них, основываясь на весьма самоуверенном критерии.

Чтобы получить полный API библиотеки, проверьтеofficial Javadocs.

Как обычно, все образцы кода, показанные в этом руководстве, доступны в течениеGitHub.