JavaRush /Blog Java /Random-MS /Mari pecahkan kelas StringUtils

Mari pecahkan kelas StringUtils

Diterbitkan dalam kumpulan
Salam semua, pembaca yang dikasihi. Saya cuba menulis tentang apa yang benar-benar menarik minat saya dan apa yang membimbangkan saya pada masa ini. Oleh itu, hari ini akan ada beberapa bacaan ringan yang akan berguna kepada anda sebagai rujukan pada masa hadapan: mari kita bercakap tentang StringUtils . Mari kita pecahkan kelas StringUtils - 1Kebetulan pada satu masa saya memintas perpustakaan Apache Commons Lang 3 . Ini adalah perpustakaan dengan kelas tambahan untuk bekerja dengan objek yang berbeza. Ini ialah koleksi kaedah berguna untuk bekerja dengan rentetan, koleksi dan sebagainya. Mengenai projek semasa, di mana saya terpaksa bekerja dengan lebih terperinci dengan rentetan dalam menterjemah logik perniagaan berusia 25 tahun (dari COBOL ke Java), ternyata saya tidak mempunyai pengetahuan yang cukup mendalam tentang kelas StringUtils . Jadi saya terpaksa mencipta semuanya sendiri. Apa yang saya maksudkan? Hakikat bahawa anda tidak perlu menulis tugas tertentu yang melibatkan manipulasi rentetan sendiri, tetapi gunakan penyelesaian siap sedia. Apa salahnya menulis sendiri? Sekurang-kurangnya ini adalah lebih banyak kod yang telah ditulis lama dahulu. Tidak kurang mendesak ialah isu menguji kod yang ditulis tambahan. Apabila kami menggunakan perpustakaan yang telah membuktikan dirinya baik, kami menjangkakan perpustakaan itu telah pun diuji dan kami tidak perlu menulis banyak kes ujian untuk mengujinya. Kebetulan set kaedah untuk bekerja dengan rentetan di Jawa tidak begitu besar. Sebenarnya tidak banyak kaedah yang berguna untuk kerja. Kelas ini juga dicipta untuk menyediakan semakan untuk NullPointerException. Rangka artikel kami adalah seperti berikut:
  1. Bagaimana untuk menyambung?
  2. Contoh dari kerja saya: bagaimana, tanpa mengetahui tentang kelas yang berguna, saya mencipta tongkat basikal saya .
  3. Mari lihat kaedah lain yang saya rasa menarik.
  4. Mari kita ringkaskan.
Semua kes akan ditambahkan ke repositori berasingan dalam organisasi Komuniti Javarush di GitHub. Akan ada contoh dan ujian yang berasingan untuk mereka.

0. Bagaimana untuk menyambung

Mereka yang berjalan seiring dengan saya sudah lebih kurang mengenali kedua-dua Git dan Maven, jadi selanjutnya saya akan bergantung pada pengetahuan ini dan tidak mengulangi diri saya sendiri. Bagi mereka yang terlepas artikel saya sebelum ini atau baru mula membaca, berikut adalah bahan tentang Maven dan Git . Sudah tentu, tanpa sistem binaan (Maven, Gredl), anda juga boleh menyambungkan semuanya secara manual, tetapi ini gila pada masa kini dan anda pastinya tidak perlu melakukannya seperti itu: lebih baik untuk segera belajar cara melakukan semuanya dengan betul. Oleh itu, untuk bekerja dengan Maven, kami mula-mula menambah kebergantungan yang sesuai:
<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-lang3</artifactId>
   <version>${apache.common.version}</version>
</dependency>
Di mana ${apache.common.version} ialah versi pustaka ini. Seterusnya, untuk mengimport dalam beberapa kelas, tambahkan import:
import org.apache.commons.lang3.StringUtils;
Dan itu sahaja, semuanya ada dalam beg))

1. Contoh daripada projek sebenar

  • kaedah leftPad

Contoh pertama secara amnya kelihatan sangat bodoh sekarang kerana sangat bagus bahawa rakan sekerja saya tahu tentang StringUtils.leftPad dan memberitahu saya. Apakah tugasnya: kod itu dibina sedemikian rupa sehingga perlu mengubah data jika ia tidak sampai dengan betul. Adalah dijangkakan bahawa medan rentetan hendaklah terdiri daripada nombor sahaja, i.e. jika panjangnya ialah 3 dan nilainya ialah 1, maka entri hendaklah "001". Iaitu, pertama anda perlu mengalih keluar semua ruang, dan kemudian menutupnya dengan sifar. Lebih banyak contoh untuk menjelaskan intipati tugasan: daripada "12" -> "012" daripada "1" -> "001" Dan seterusnya. Apa yang saya buat? Terangkan perkara ini dalam kelas LeftPadExample . Saya menulis kaedah yang akan melakukan semua ini:
public static String ownLeftPad(String value) {
   String trimmedValue = value.trim();

   if(trimmedValue.length() == value.length()) {
       return value;
   }

   StringBuilder newValue = new StringBuilder(trimmedValue);

   IntStream.rangeClosed(1, value.length() - trimmedValue.length())
           .forEach(it -> newValue.insert(0, "0"));
   return newValue.toString();
}
Sebagai asas, saya mengambil idea bahawa kita hanya boleh mendapatkan perbezaan antara nilai asal dan nilai yang dipangkas dan mengisinya dengan sifar di hadapan. Untuk melakukan ini, saya menggunakan IntStream untuk melakukan operasi yang sama n kali. Dan ini pastinya perlu diuji. Inilah yang boleh saya lakukan jika saya tahu tentang kaedah StringUtils.leftPad terlebih dahulu :
public static String apacheCommonLeftPad(String value) {
   return StringUtils.leftPad(value.trim(), value.length(), "0");
}
Seperti yang anda lihat, terdapat lebih sedikit kod, dan perpustakaan yang disahkan oleh semua orang juga digunakan. Untuk tujuan ini, saya mencipta dua ujian dalam kelas LeftPadExampleTest (biasanya apabila mereka merancang untuk menguji kelas, mereka mencipta kelas dengan nama yang sama + Ujian dalam pakej yang sama, hanya dalam src/test/java). Ujian ini menyemak satu kaedah untuk memastikan ia menukar nilai dengan betul, kemudian yang lain. Sudah tentu, lebih banyak ujian perlu ditulis, tetapi ujian bukanlah topik utama dalam kes kami:
package com.github.javarushcommunity.stringutilsdemo;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

@DisplayName("Unit-level testing for LeftPadExample")
class LeftPadExampleTest {

   @DisplayName("Should transform by using ownLeftPad method as expected")
   @Test
   public void shouldTransformOwnLeftPadAsExpected() {
       //given
       String value = "1   ";
       String expectedTransformedValue = "0001";

       //when
       String transformedValue = LeftPadExample.ownLeftPad(value);

       //then
       Assertions.assertEquals(expectedTransformedValue, transformedValue);
   }

   @DisplayName("Should transform by using StringUtils method as expected")
   @Test
   public void shouldTransformStringUtilsLeftPadAsExpected() {
       //given
       String value = "1   ";
       String expectedTransformedValue = "0001";

       //when
       String transformedValue = LeftPadExample.apacheCommonLeftPad(value);

       //then
       Assertions.assertEquals(expectedTransformedValue, transformedValue);
   }

}
Saya boleh membuat sedikit ulasan tentang ujian buat masa ini. Mereka ditulis menggunakan JUnit 5:
  1. Ujian akan dianggap sebagai ujian jika ia mempunyai anotasi yang sesuai - @Test.
  2. Jika sukar untuk menerangkan pengendalian ujian dalam nama atau perihalan panjang dan menyusahkan untuk dibaca, anda boleh menambah anotasi @DisplayName dan menjadikannya perihalan biasa yang akan kelihatan semasa menjalankan ujian.
  3. Semasa menulis ujian, saya menggunakan pendekatan BDD, di mana saya membahagikan ujian kepada bahagian logik:
    1. //diberikan - blok persediaan data sebelum ujian;
    2. //bilakah blok di mana bahagian kod yang kami uji dilancarkan;
    3. //maka ialah blok di mana keputusan blok bila disemak.
Jika anda menjalankannya, mereka akan mengesahkan bahawa semuanya berfungsi seperti yang diharapkan.

  • kaedah stripStart

Di sini saya perlu menyelesaikan masalah dengan baris yang boleh mempunyai ruang dan koma pada mulanya. Selepas transformasi, mereka tidak sepatutnya mempunyai makna baru. Pernyataan masalah lebih jelas daripada sebelumnya. Beberapa contoh akan menguatkan pemahaman kita: “, , books” -> “books” “,,, books” -> “books” b , books” -> “b , books” Seperti dalam kes leftPad, saya menambah StrimStartExample class , yang mempunyai dua kaedah. Satu - dengan penyelesaiannya sendiri:
public static String ownStripStart(String value) {
   int index = 0;
   List commaSpace = asList(" ", ",");
   for (int i = 0; i < value.length(); i++) {
       if (commaSpace.contains(String.valueOf(value.charAt(i)))) {
           index++;
       } else {
           break;
       }
   }
   return value.substring(index);
}
Di sini ideanya adalah untuk mencari indeks yang bermula dari mana tiada lagi ruang atau koma. Jika mereka tidak berada di sana pada mulanya, maka indeksnya akan menjadi sifar. Dan yang kedua - dengan penyelesaian melalui StringUtils :
public static String apacheCommonLeftPad(String value) {
   return StringUtils.stripStart(value, StringUtils.SPACE + COMMA);
}
Di sini kita luluskan maklumat hujah pertama tentang rentetan yang sedang kita kerjakan, dan pada yang kedua kita lulus rentetan yang terdiri daripada aksara yang perlu dilangkau. Kami mencipta kelas StripStartExampleTest dengan cara yang sama :
package com.github.javarushcommunity.stringutilsdemo;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@DisplayName("Unit-level testing for StripStartExample")
class StripStartExampleTest {

   @DisplayName("Should transform by using stripStart method as expected")
   @Test
   public void shouldTransformOwnStripStartAsExpected() {
       //given
       String value = ", , books";
       String expectedTransformedValue = "books";

       //when
       String transformedValue = StripStartExample.ownStripStart(value);

       //then
       Assertions.assertEquals(expectedTransformedValue, transformedValue);
   }

   @DisplayName("Should transform by using StringUtils method as expected")
   @Test
   public void shouldTransformStringUtilsStripStartAsExpected() {
       //given
       String value = ", , books";
       String expectedTransformedValue = "books";

       //when
       String transformedValue = StripStartExample.apacheCommonLeftPad(value);

       //then
       Assertions.assertEquals(expectedTransformedValue, transformedValue);
   }
}

  • kaedah isEmpty

Kaedah ini, tentu saja, jauh lebih mudah, tetapi itu tidak menjadikannya kurang berguna. Ia memanjangkan keupayaan kaedah String.isEmpty() , yang juga menambah semakan untuk null. Untuk apa? Untuk mengelakkan NullPointerException, iaitu, untuk mengelakkan kaedah memanggil pada pembolehubah iaitu null . Oleh itu, untuk tidak menulis:
if(value != null && value.isEmpty()) {
   //doing something
}
Anda hanya boleh melakukan ini:
if(StringUtils.isEmpty(value)) {
   //doing something
}
Kelebihan kaedah ini ialah dengan serta-merta jelas di mana kaedah yang digunakan.

2. Analisis kaedah lain kelas StringUtils

Sekarang mari kita bercakap tentang kaedah-kaedah yang, pada pendapat saya, juga patut diberi perhatian. Bercakap secara umum tentang StringUtils , patut dikatakan bahawa ia menyediakan kaedah selamat nol yang serupa dengan yang terdapat dalam kelas String (seperti yang berlaku dengan kaedah isEmpty ). Mari kita pergi melalui mereka:

  • membandingkan kaedah

Kaedah sedemikian wujud dalam String dan akan membuang NullPointerException jika, apabila membandingkan dua rentetan, salah satu daripadanya adalah null. Untuk mengelakkan semakan hodoh dalam kod kami, kami boleh menggunakan kaedah StringUtils.compare(String str1, String str2) : ia mengembalikan int sebagai hasil perbandingan. Apakah maksud nilai-nilai ini? int = 0 jika ia adalah sama (atau kedua-duanya adalah nol). int < 0, jika str1 kurang daripada str2. int > 0, jika str1 lebih besar daripada str2. Juga, jika anda melihat dokumentasi mereka, Javadoc kaedah ini membentangkan senario berikut:
StringUtils.compare(null, null)   = 0
StringUtils.compare(null , "a")   < 0
StringUtils.compare("a", null)    > 0
StringUtils.compare("abc", "abc") = 0
StringUtils.compare("a", "b")     < 0
StringUtils.compare("b", "a")     > 0
StringUtils.compare("a", "B")     > 0
StringUtils.compare("ab", "abc")  < 0

  • mengandungi... kaedah

Di sini pemaju utiliti mempunyai letupan. Apa sahaja kaedah yang anda mahukan ada. Saya memutuskan untuk menggabungkannya:
  1. mengandungi ialah kaedah yang menyemak sama ada rentetan yang dijangkakan berada di dalam rentetan lain. Bagaimanakah ini berguna? Anda boleh menggunakan kaedah ini jika anda perlu memastikan bahawa terdapat perkataan tertentu dalam teks.

    Contoh:

    StringUtils.contains(null, *)     = false
    StringUtils.contains(*, null)     = false
    StringUtils.contains("", "")      = true
    StringUtils.contains("abc", "")   = true
    StringUtils.contains("abc", "a")  = true
    StringUtils.contains("abc", "z")  = false

    Sekali lagi, keselamatan NPE (Null Pointer Exception) hadir.

  2. containsAny ialah kaedah yang menyemak sama ada mana-mana aksara yang terdapat dalam rentetan itu ada. Juga perkara yang berguna: anda sering perlu melakukan ini.

    Contoh daripada dokumentasi:

    StringUtils.containsAny(null, *)                  = false
    StringUtils.containsAny("", *)                    = false
    StringUtils.containsAny(*, null)                  = false
    StringUtils.containsAny(*, [])                    = false
    StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
    StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
    StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
    StringUtils.containsAny("aba", ['z'])             = false

  3. containsIgnoreCase ialah sambungan berguna kepada kaedah contains . Sesungguhnya, untuk memeriksa kes sedemikian tanpa kaedah ini, anda perlu melalui beberapa pilihan. Oleh itu, hanya satu kaedah yang akan digunakan secara harmoni.

  4. Beberapa contoh daripada dokumen:

    StringUtils.containsIgnoreCase(null, *) = false
    StringUtils.containsIgnoreCase(*, null) = false
    StringUtils.containsIgnoreCase("", "") = true
    StringUtils.containsIgnoreCase("abc", "") = true
    StringUtils.containsIgnoreCase("abc", "a") = true
    StringUtils.containsIgnoreCase("abc", "z") = false
    StringUtils.containsIgnoreCase("abc", "A") = true
    StringUtils.containsIgnoreCase("abc", "Z") = false

  5. mengandungiTiada - berdasarkan nama, anda sudah boleh memahami perkara yang sedang diperiksa. Seharusnya tiada garisan di dalam. Satu perkara yang berguna, pastinya. Carian pantas untuk beberapa aksara yang tidak diingini ;). Dalam bot telegram kami , kami akan menapis kelucahan dan tidak akan mengabaikan kaedah lucu ini.

    Dan contoh, di manakah kita tanpa mereka:

    StringUtils.containsNone(null, *)       = true
    StringUtils.containsNone(*, null)       = true
    StringUtils.containsNone("", *)         = true
    StringUtils.containsNone("ab", '')      = true
    StringUtils.containsNone("abab", 'xyz') = true
    StringUtils.containsNone("ab1", 'xyz')  = true
    StringUtils.containsNone("abz", 'xyz')  = false

  • kaedah defaultString

Satu siri kaedah yang membantu mengelak daripada menambah maklumat tambahan jika rentetan adalah batal dan anda perlu menetapkan beberapa nilai lalai. Terdapat banyak pilihan untuk memenuhi setiap citarasa. Ketua di antara mereka ialah StringUtils.defaultString(final String str, final String defaultStr) - sekiranya str adalah batal, kami hanya akan menghantar nilai kepada defaultStr . Contoh daripada dokumentasi:
StringUtils.defaultString(null, "NULL")  = "NULL"
StringUtils.defaultString("", "NULL")    = ""
StringUtils.defaultString("bat", "NULL") = "bat"
Ia sangat mudah digunakan apabila anda mencipta kelas POJO dengan data.

  • kaedah deleteWhitespace

Ini adalah kaedah yang menarik, walaupun tidak banyak pilihan untuk aplikasinya. Pada masa yang sama, jika kes sedemikian timbul, kaedah itu pasti akan sangat berguna. Ia mengalih keluar semua ruang daripada rentetan. Di mana sahaja jurang ini, tidak akan ada kesannya))) Contoh daripada dokumen:
StringUtils.deleteWhitespace(null)         = null
StringUtils.deleteWhitespace("")           = ""
StringUtils.deleteWhitespace("abc")        = "abc"
StringUtils.deleteWhitespace("   ab  c  ") = "abc"

  • berakhirDengan kaedah

Bercakap untuk dirinya sendiri. Ini adalah kaedah yang sangat berguna: ia menyemak sama ada rentetan berakhir dengan rentetan yang dicadangkan atau tidak. Ini selalunya perlu. Sudah tentu, anda boleh menulis cek sendiri, tetapi menggunakan kaedah siap pakai jelas lebih mudah dan lebih baik. Contoh:
StringUtils.endsWith(null, null)      = true
StringUtils.endsWith(null, "def")     = false
StringUtils.endsWith("abcdef", null)  = false
StringUtils.endsWith("abcdef", "def") = true
StringUtils.endsWith("ABCDEF", "def") = false
StringUtils.endsWith("ABCDEF", "cde") = false
StringUtils.endsWith("ABCDEF", "")    = true
Seperti yang anda lihat, semuanya berakhir dengan baris kosong))) Saya fikir contoh ini (StringUtils.endsWith("ABCDEF", "") = benar) hanyalah bonus, kerana ini tidak masuk akal) Terdapat juga kaedah yang mengabaikan kes.

  • kaedah sama

Contoh hebat kaedah selamat nol yang membandingkan dua rentetan. Apa sahaja yang kita letakkan di sana, jawapannya akan ada, dan ia akan menjadi tanpa kesilapan. Contoh:
StringUtils.equals(null, null)   = true
StringUtils.equals(null, "abc")  = false
StringUtils.equals("abc", null)  = false
StringUtils.equals("abc", "abc") = true
StringUtils.equals("abc", "ABC") = false
Sudah tentu, terdapat juga equalsIgnoreCase - semuanya dilakukan dengan cara yang sama, hanya kami mengabaikan kes itu. Jom tengok?
StringUtils.equalsIgnoreCase(null, null)   = true
StringUtils.equalsIgnoreCase(null, "abc")  = false
StringUtils.equalsIgnoreCase("abc", null)  = false
StringUtils.equalsIgnoreCase("abc", "abc") = true
StringUtils.equalsIgnoreCase("abc", "ABC") = true

  • sama denganSebarang kaedah

Mari kita teruskan dan lanjutkan kaedah equals . Katakan bahawa bukannya beberapa semakan kesaksamaan, kami mahu melaksanakan satu. Untuk ini, kita boleh lulus rentetan yang mana satu set rentetan akan dibandingkan; jika mana-mana daripadanya sama dengan yang dicadangkan, ia akan BENAR. Kami lulus rentetan dan koleksi rentetan untuk membandingkannya antara satu sama lain (rentetan pertama dengan rentetan daripada koleksi). Sukar? Berikut ialah contoh daripada dokumen untuk membantu anda memahami maksud:
StringUtils.equalsAny(null, (CharSequence[]) null) = false
StringUtils.equalsAny(null, null, null)    = true
StringUtils.equalsAny(null, "abc", "def")  = false
StringUtils.equalsAny("abc", null, "def")  = false
StringUtils.equalsAny("abc", "abc", "def") = true
StringUtils.equalsAny("abc", "ABC", "DEF") = false
Terdapat juga equalsAnyIgnoreCase . Dan contoh untuknya:
StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true

Pokoknya

Akibatnya, kami pergi dengan pengetahuan tentang apa itu StringUtils dan kaedah berguna yang ada padanya. Nah, dengan kesedaran bahawa terdapat perkara-perkara yang berguna dan tidak perlu untuk memagar setiap kali dengan tongkat di tempat-tempat di mana ia mungkin untuk menutup isu dengan bantuan penyelesaian siap sedia. Secara umum, kami telah menganalisis hanya sebahagian daripada kaedah. Jika anda mahu, saya boleh meneruskan: terdapat banyak lagi daripada mereka, dan mereka benar-benar patut diberi perhatian. Jika anda mempunyai sebarang idea tentang cara lain ini boleh disampaikan, sila tulis - Saya sentiasa terbuka kepada idea baharu. Dokumentasi untuk kaedah ditulis dengan sangat baik, contoh ujian dengan keputusan ditambah, yang membantu untuk lebih memahami operasi kaedah. Oleh itu, kami tidak segan untuk membaca dokumentasi: ia akan menghilangkan keraguan anda tentang kefungsian utiliti. Untuk mendapatkan pengalaman pengekodan baharu, saya menasihati anda untuk melihat cara kelas utiliti dibuat dan ditulis. Ini akan berguna pada masa hadapan, kerana biasanya setiap projek mempunyai kelas sekerap sendiri, dan pengalaman menulisnya akan berguna. Secara tradisinya, saya cadangkan anda melanggan akaun saya di Github ) Bagi mereka yang tidak tahu tentang projek saya dengan bot telegram, berikut adalah pautan ke artikel pertama . Terima kasih semua kerana membaca. Saya telah menambah beberapa pautan berguna di bawah.
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION