Pengenalan Apache Commons Lang 3

1. Gambaran keseluruhan

Perpustakaan Apache Commons Lang 3 adalah pakej kelas utiliti yang terkenal dan lengkap, yang bertujuan untuk memperluas fungsi API Java .

Repertoar perpustakaan cukup kaya, mulai dari rentetan, manipulasi rentetan dan nombor, refleksi dan konkurensi, hingga pelaksanaan beberapa struktur data yang disusun, seperti pasangan dan tiga kali lipat (umumnya dikenali sebagai tupel).

Dalam tutorial ini, kita akan menyelami kelas utiliti yang paling berguna di perpustakaan .

2. Ketergantungan Maven

Seperti biasa, untuk mula menggunakan Apache Commons Lang 3, pertama-tama kita perlu menambahkan kebergantungan Maven:

 org.apache.commons commons-lang3 3.8 

3. Kelas StringUtils

Kelas utiliti pertama yang akan kami bahas dalam rangkuman pengenalan ini ialah StringUtils.

Seperti namanya, StringUtils membolehkan kita untuk melaksanakan sekumpulan null selamat s trings operasi yang pelengkap / melanjutkan orang-orang yang java.lang.String menyediakan di luar kotak .

Mari kita mulai mempamerkan sekumpulan kaedah utiliti yang melakukan beberapa pemeriksaan pada rentetan tertentu , seperti menentukan apakah rentetan itu kosong, kosong, huruf kecil, huruf besar, alfanumerik dan sebagainya:

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

Sudah tentu, kelas StringUtils menerapkan banyak kaedah lain, yang telah kita hilangkan di sini demi kesederhanaan.

Untuk beberapa kaedah tambahan lain yang memeriksa atau menerapkan beberapa jenis algoritma penukaran pada rentetan tertentu , sila periksa tutorial ini.

Yang telah kami bahas di atas benar-benar mudah, jadi ujian unit harus jelas.

4. Kelas ArrayUtils

The ArrayUtils alat kelas batch kaedah utiliti yang membolehkan kita untuk memproses dan menyemak tatasusunan dalam pelbagai bentuk dan bentuk yang berbeza .

Mari kita mulakan dengan dua implementasi yang terlalu banyak dari kaedah toString () , yang mengembalikan representasi rentetan dari array yang diberikan dan rentetan tertentu ketika array itu kosong:

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

Seterusnya, kita mempunyai kaedah hasCode () dan toMap () .

Yang pertama menghasilkan pelaksanaan hashCode khusus untuk array, sementara yang terakhir mengubah array menjadi Peta :

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

Terakhir, mari kita lihat kaedah isSameLength () dan indexOf () .

Yang pertama digunakan untuk memeriksa apakah dua tatasusunan mempunyai panjang yang sama, dan yang kedua untuk mendapatkan indeks elemen tertentu:

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

Seperti kelas StringUtils , ArrayUtils menerapkan lebih banyak kaedah tambahan. Anda boleh mengetahui lebih lanjut mengenai mereka dalam tutorial ini.

Dalam kes ini, kami hanya mempamerkan yang paling mewakili.

5. Kelas NumberUtils

Komponen utama lain dari Apache Commons Lang 3 adalah kelas NumberUtils.

Seperti yang dijangkakan, kelas menyediakan sebilangan besar kaedah utiliti, yang bertujuan memproses dan memanipulasi jenis angka .

Mari kita lihat pelaksanaan kaedah perbandingan () yang berlebihan , yang membandingkan persamaan primitif yang berbeza, seperti int dan panjang :

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

Di samping itu, terdapat pelaksanaan membandingkan () yang beroperasi pada byte dan pendek , yang berfungsi sangat serupa dengan contoh di atas.

Seterusnya dalam tinjauan ini adalah kaedah createNumber () dan isDigit () .

Yang pertama membolehkan kita membuat representasi numerik rentetan , sementara yang kedua memeriksa apakah rentetan hanya terdiri dari digit:

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

Ketika mencari campuran dan nilai maksimum dari array yang disediakan, kelas NumberUtils memberikan sokongan yang kuat untuk operasi ini melalui pelaksanaan kaedah min () dan max () yang terlalu banyak :

@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. The Pecahan Kelas

Bekerja dengan pecahan adalah baik dan baik apabila kita menggunakan pen dan sehelai kertas. Tetapi, adakah kita perlu melalui kerumitan proses ini semasa menulis kod? Tidak juga.

The Pecahan kelas membuat menambah, menolak dan mendarabkan pecahan dalam angin :

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

Walaupun operasi dengan pecahan bukanlah tugas yang paling kerap yang harus kita laksanakan dalam kerja pembangunan harian kita, kelas Fraction memberikan sokongan yang berharga untuk melaksanakan operasi ini dengan cara yang mudah.

7. Kelas SystemUtils

Kadang kala, kita perlu mendapatkan beberapa maklumat dinamik mengenai sifat dan pemboleh ubah yang berbeza dari platform Java yang mendasari atau sistem operasi.

Apache Commons Lang 3 menyediakan kelas SystemUtils untuk menyelesaikannya dengan cara yang tidak menyakitkan .

Mari kita pertimbangkan, sebagai contoh, kaedah getJavaHome () , getUserHome () dan 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 .

Perpustakaan melaksanakan banyak kelas utiliti lain yang patut dilihat . Di sini, kami baru saja mempamerkan yang paling berguna, berdasarkan kriteria yang cukup baik.

Untuk API perpustakaan penuh, sila periksa Javadocs rasmi.

Seperti biasa, semua contoh kod yang ditunjukkan dalam tutorial ini terdapat di GitHub.