Pengantar Apache Commons Lang 3

1. Ikhtisar

Pustaka Apache Commons Lang 3 adalah paket kelas utilitas berfitur lengkap yang populer, yang bertujuan untuk memperluas fungsionalitas API Java .

Repertoar perpustakaan ini cukup kaya, mulai dari string, array dan manipulasi angka, refleksi dan konkurensi, hingga implementasi beberapa struktur data terurut, seperti pasangan dan tripel (secara umum dikenal sebagai tupel).

Dalam tutorial ini, kita akan mempelajari kelas utilitas perpustakaan yang paling berguna .

2. Ketergantungan Maven

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

 org.apache.commons commons-lang3 3.8 

3. Kelas StringUtils

Kelas utilitas pertama yang akan kita bahas dalam pengantar ini adalah StringUtils.

Seperti namanya, StringUtils memungkinkan kita untuk melakukan sekelompok nol-aman s Trings operasi yang komplemen / memperpanjang orang yang java.lang.String menyediakan luar kotak .

Mari mulai menampilkan kumpulan metode utilitas yang melakukan beberapa pemeriksaan pada string tertentu , seperti menentukan apakah string 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(); } 

Tentu saja, kelas StringUtils mengimplementasikan banyak metode lain, yang telah kami hilangkan di sini demi kesederhanaan.

Untuk beberapa metode tambahan lain yang memeriksa atau menerapkan beberapa jenis algoritme konversi ke string tertentu , lihat tutorial ini.

Yang telah kami bahas di atas sangat mudah, jadi pengujian unit harus cukup jelas.

4. Kelas ArrayUtils

Kelas ArrayUtils mengimplementasikan sekumpulan metode utilitas yang memungkinkan kita memproses dan memeriksa array dalam berbagai bentuk dan bentuk .

Mari kita mulai dengan dua implementasi yang kelebihan beban dari metode toString () , yang mengembalikan representasi string dari larik yang diberikan dan string tertentu ketika lariknya nihil:

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

Selanjutnya, kita memiliki metode hasCode () dan toMap () .

Yang pertama menghasilkan implementasi hashCode khusus untuk sebuah array, sedangkan yang terakhir mengonversi sebuah array ke 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 metode isSameLength () dan indexOf () .

Yang pertama digunakan untuk memeriksa apakah dua larik memiliki panjang yang sama, dan yang terakhir untuk mendapatkan indeks dari elemen yang diberikan:

@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 mengimplementasikan lebih banyak metode tambahan. Anda dapat mempelajari lebih lanjut tentang mereka di tutorial ini.

Dalam kasus ini, kami hanya menampilkan yang paling representatif.

5. Kelas NumberUtils

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

Seperti yang diharapkan, kelas menyediakan sejumlah besar metode utilitas, yang ditujukan untuk memproses dan memanipulasi tipe numerik .

Mari kita lihat implementasi overload dari metode bandingkan () , yang membandingkan persamaan primitif yang berbeda, seperti int dan 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); }

Selain itu, terdapat implementasi bandingkan () yang beroperasi pada byte dan pendek , yang bekerja sangat mirip dengan contoh di atas.

Berikutnya dalam ulasan ini adalah metode createNumber () dan isDigit () .

Yang pertama memungkinkan kita membuat representasi numerik dari sebuah string , sedangkan yang kedua memeriksa apakah sebuah string 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 datang untuk menemukan nilai mix dan max dari array yang disediakan, kelas NumberUtils memberikan dukungan yang kuat untuk operasi ini melalui implementasi yang kelebihan beban dari metode min () dan 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. The Fraksi Kelas

Bekerja dengan pecahan semuanya baik-baik saja jika kita menggunakan pena dan selembar kertas. Tapi, apakah kita harus melalui kerumitan proses ini saat menulis kode? Tidak juga.

Kelas Pecahan memudahkan penjumlahan, pengurangan, dan perkalian pecahan :

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

Meskipun operasi dengan pecahan jelas bukan tugas yang paling sering kita tangani dalam pekerjaan pengembangan sehari-hari, kelas Fraksi memberikan dukungan yang berharga untuk melakukan operasi ini secara langsung.

7. Kelas SystemUtils

Terkadang, kita perlu mendapatkan beberapa informasi dinamis tentang properti dan variabel yang berbeda dari platform Java atau sistem operasi yang mendasarinya.

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

Mari pertimbangkan, misalnya, metode 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(); }

Ada beberapa metode utilitas tambahan yang diimplementasikan oleh kelas SystemUtils . Kami telah menghilangkannya agar contohnya tetap singkat.

8. The Lazy Initialization dan Builder Classes

Salah satu aspek paling menarik dari Apache Commons Lang 3 adalah penerapan beberapa pola desain terkenal, termasuk pola inisialisasi malas dan pembangun .

Sebagai contoh, katakanlah kita telah membuat kelas User yang mahal (tidak diperlihatkan untuk singkatnya), dan ingin menunda pembuatannya sampai benar-benar dibutuhkan.

Dalam kasus seperti itu, yang perlu kita lakukan hanyalah memperluas kelas abstrak LazyInitializer berparameter dan mengganti metode inisialisasi () :

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 .

Pustaka mengimplementasikan banyak kelas utilitas lain yang layak untuk dilihat . Di sini, kami baru saja memamerkan yang paling berguna, berdasarkan kriteria yang cukup beralasan.

Untuk API perpustakaan lengkap, silakan periksa Javadocs resmi.

Seperti biasa, semua contoh kode yang ditampilkan dalam tutorial ini tersedia di GitHub.