JavaRush /Java блогы /Random-KK /StringUtils класын бөлейік
Roman Beekeeper
Деңгей

StringUtils класын бөлейік

Топта жарияланған
Барлығына сәлем, құрметті оқырмандарым. Мені шынымен не қызықтыратыны және қазіргі уақытта мені не мазалайтыны туралы жазуға тырысамын. Сондықтан, бүгін сізге болашақта анықтама ретінде пайдалы болатын кейбір жеңіл оқулар болады: StringUtils туралы сөйлесейік . Бір кездері мен Apache Commons Lang 3StringUtils класын бөлейік - 1 кітапханасын айналып өткенім осылай болды . Бұл әртүрлі an objectілермен жұмыс істеуге арналған көмекші сыныптары бар кітапхана. Бұл жолдармен, жинақтармен және т.б. жұмыс істеуге арналған пайдалы әдістердің жинағы. Мен 25 жылдық бизнес логикасын (COBOL-дан Java-ға дейін) аударуда жолдармен егжей-тегжейлі жұмыс істеуге тура келген ағымдағы жобада менде StringUtils класы туралы терең білім жоқ екені анықталды . Сондықтан бәрін өзім жасауға тура келді. Мен не айтқым келеді? Жолдық манипуляцияны қамтитын белгілі бір тапсырмаларды өзіңіз жазудың қажеті жоқ, бірақ дайын шешімді қолданыңыз. Оны өзің жазғаның несі жаман? Кем дегенде, бұл көп уақыт бұрын жазылған code. Қосымша жазылған codeты тестілеу мәселесі өзекті болып табылады. Біз өзін жақсы деп таныған кітапхананы пайдаланған кезде, біз оның сынақтан өткенін және оны тексеру үшін көптеген сынақ жағдайларын жазудың қажеті жоқ деп күтеміз. Java-да жолмен жұмыс істеу әдістерінің жиынтығы соншалықты үлкен емес. Жұмыс үшін пайдалы болатын әдістер көп емес. Бұл сынып сонымен қатар NullPointerException үшін тексерулерді қамтамасыз ету үшін жасалған. Біздің мақаланың жоспары келесідей болады:
  1. Қалай қосылуға болады?
  2. Менің жұмысымнан мысалдар: мен осындай пайдалы сынып туралы білмей, велосипед балдағын қалай жасадым.
  3. Маған қызықты деп тапқан басқа әдістерді қарастырайық.
  4. Қорытындылайық.
Барлық істер GitHub жүйесіндегі Javarush қауымдастығы ұйымындағы бөлек репозиторийге қосылады . Олар үшін жеке мысалдар мен сынақтар болады.

0. Қосылу жолы

Менімен қол ұстасып жүргендер Гитпен де, Мавенмен де азды-көпті таныс, сондықтан мен бұл білімге сүйенемін және өзімді қайталамаймын. Менің алдыңғы мақалаларымды жіберіп алған немесе оқуды енді бастағандар үшін мұнда Maven және Git туралы материалдар бар . Әрине, құрастыру жүйесі жоқ (Maven, Gredl) сіз бәрін қолмен қоса аласыз, бірақ бұл қазіргі уақытта ақылсыз және мұны істеудің қажеті жоқ: бәрін қалай дұрыс жасау керектігін бірден үйренгеніңіз жөн. Сондықтан, Maven-пен жұмыс істеу үшін алдымен сәйкес тәуелділікті қосамыз:
<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-lang3</artifactId>
   <version>${apache.common.version}</version>
</dependency>
Мұндағы ${apache.common.version} - осы кітапхананың нұсқасы. Әрі қарай, кейбір сыныпта импорттау үшін импортты қосыңыз:
import org.apache.commons.lang3.StringUtils;
Міне, бәрі сөмкеде))

1. Нақты жобадан мысалдар

  • leftPad әдісі

Бірінші мысал әдетте ақымақ болып көрінеді, сондықтан әріптестерімнің StringUtils.leftPad туралы білгені және маған айтқаны өте жақсы. Тапсырма қандай болды: code егер ол дұрыс келмесе, деректерді түрлендіру қажет болатындай етіп жасалған. Жол өрісі тек сандардан тұруы керек деп күтілді, яғни. егер оның ұзындығы 3 болса және оның мәні 1 болса, онда жазба «001» болуы керек. Яғни, алдымен барлық бос орындарды алып тастау керек, содан кейін оны нөлдермен жабу керек. Тапсырманың мәнін түсіндіру үшін көбірек мысалдар: «12» -> «012» «1» -> «001» және т.б. Мен не істедім? Бұл LeftPadExample сыныбында сипатталған . Мен мұның бәрін жасайтын әдісті жаздым:
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();
}
Негізінде мен бастапқы мен кесілген мәннің арасындағы айырмашылықты алып, оны алдына нөлдермен толтыра аламыз деген идеяны алдым. Бұл әрекетті орындау үшін мен IntStream қызметін n рет бірдей әрекетті орындау үшін қолдандым. Және бұл міндетті түрде сынақтан өтуі керек. Егер мен StringUtils.leftPad әдісі туралы алдын ала білетін болсам, мынаны істей алар едім :
public static String apacheCommonLeftPad(String value) {
   return StringUtils.leftPad(value.trim(), value.length(), "0");
}
Көріп отырғаныңыздай, code әлдеқайда аз және барлығы растаған кітапхана да пайдаланылады. Осы мақсатта мен LeftPadExampleTest сыныбында екі тест жасадым (әдетте олар сыныпты сынауды жоспарлағанда, олар бірдей атпен класс жасайды + Бір пакетте Test, тек src/test/java ішінде). Бұл сынақтар мәнді дұрыс түрлендіретініне көз жеткізу үшін бір әдісті, содан кейін екіншісін тексереді. Әрине, көп сынақтар жазылуы керек, бірақ тестілеу біздің жағдайда негізгі тақырып емес:
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);
   }

}
Мен қазір сынақтар туралы бірнеше түсініктеме бере аламын. Олар JUnit 5 көмегімен жазылған:
  1. Сынақ тиісті annotationға ие болса, сынақ сынақ ретінде қарастырылады - @Test.
  2. Егер атау сынақ жұмысын сипаттау қиын болса немесе сипаттама ұзақ және оқуға ыңғайсыз болса, @DisplayName annotationсын қосып, оны сынақтарды орындау кезінде көрінетін қалыпты сипаттамаға айналдыруға болады.
  3. Тесттерді жазу кезінде мен BDD әдісін қолданамын, онда мен тесттерді логикалық бөліктерге бөлемін:
    1. //берілген – тест алдында деректерді орнату блогы;
    2. //біз сынап жатқан code бөлігі іске қосылатын блок қашан;
    3. //онда қашан блогының нәтижелері тексерілетін блок.
Егер сіз оларды іске қоссаңыз, олар бәрі күткендей жұмыс істеп тұрғанын растайды.

  • stripStart әдісі

Мұнда мен басында бос орындар мен үтірлер болуы мүмкін сызықпен мәселені шешу керек болды. Трансформациядан кейін олар жаңа мағынаға ие болмауы керек еді. Мәселе туралы мәлімдеме бұрынғыдан да анық. Бірнеше мысалдар біздің түсінігімізді нығайтады: “, , кітаптар” -> “кітаптар” “,,, кітаптар” -> “кітаптар” b , кітаптар” -> “b , кітаптар” leftPad-тегідей, мен қостым StrimStartExample класы , оның екі әдісі бар. Біреуі - өз шешімімен:
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);
}
Мұнда бос орындар немесе үтірлер жоқ индексті табу идеясы болды. Егер олар басында мүлде болмаса, онда индекс нөлге тең болады. Ал екіншісі - StringUtils арқылы шешіммен :
public static String apacheCommonLeftPad(String value) {
   return StringUtils.stripStart(value, StringUtils.SPACE + COMMA);
}
Мұнда біз қай жолмен жұмыс істеп жатқанымыз туралы бірінші аргумент ақпаратын береміз, ал екіншісінде өткізіп жіберуді қажет ететін таңбалардан тұратын жолды береміз. Біз StripStartExampleTest сыныбын дәл осылай жасаймыз :
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);
   }
}

  • isEmpty әдісі

Бұл әдіс, әрине, әлдеқайда қарапайым, бірақ бұл оның пайдалылығын азайтпайды. Ол String.isEmpty() әдісінің мүмкіндіктерін кеңейтеді , ол сонымен қатар нөлге тексеру қосады. Не үшін? NullPointerException болдырмау үшін, яғни null болатын айнымалыға әдістерді шақырмау . Сондықтан жазбау үшін:
if(value != null && value.isEmpty()) {
   //doing something
}
Сіз мұны жай ғана жасай аласыз:
if(StringUtils.isEmpty(value)) {
   //doing something
}
Бұл әдістің артықшылығы – қай әдістің қай жерде қолданылатыны бірден белгілі болады.

2. StringUtils класының басқа әдістерін талдау

Енді, менің ойымша, назар аударуға лайық әдістер туралы сөйлесейік. Жалпы StringUtils туралы айтатын болсақ, ол String класында табылғандарға ұқсас нөлдік қауіпсіз әдістерді қамтамасыз ететінін айту керек ( isEmpty әдісі сияқты ). Оларды қарастырайық:

  • салыстыру әдісі

Мұндай әдіс String ішінде бар және егер екі жолды салыстыру кезінде олардың біреуі нөл болса, NullPointerException шығарады. Біздің codeта жағымсыз тексерулерді болдырмау үшін StringUtils.compare(String str1, String str2) әдісін пайдалана аламыз : ол салыстыру нәтижесі ретінде int мәнін қайтарады. Бұл құндылықтар нені білдіреді? int = 0, егер олар бірдей болса (немесе екеуі де нөл). int < 0, егер str1 str2-ден кіші болса. int > 0, егер str1 str2-ден үлкен болса. Сондай-ақ, олардың құжаттамасын қарасаңыз, осы әдістің Javadoc бағдарламасы келесі сценарийлерді ұсынады:
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

  • ... әдістерін қамтиды

Мұнда утorталарды әзірлеушілер жарылыс болды. Сіз қалаған әдістің бәрі бар. Мен оларды біріктіруді шештім:
  1. құрамында — күтілетін жолдың басқа жолдың ішінде екенін тексеретін әдіс. Бұл қаншалықты пайдалы? Мәтінде белгілі бір сөздің бар екеніне көз жеткізу қажет болса, бұл әдісті қолдануға болады.

    Мысалдар:

    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

    Тағы да NPE (Null Pointer Exception) қауіпсіздігі бар.

  2. containAny - жолда бар таңбалардың кез келгенінің бар-жоғын тексеретін әдіс. Сондай-ақ пайдалы нәрсе: мұны жиі жасауға тура келеді.

    Құжаттамадан мысалдар:

    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. containIgnoreCase - contain әдісінің пайдалы кеңейтімі . Шынында да, мұндай істі осы әдіссіз тексеру үшін сізге бірнеше нұсқадан өту керек. Сондықтан бір ғана әдіс үйлесімді түрде қолданылады.

  4. Құжаттардан бірнеше мысалдар:

    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. containNone - атына қарап, не тексеріліп жатқанын түсінуге болады. Ішінде сызықтар болмауы керек. Пайдалы нәрсе, сөзсіз. Кейбір қажетсіз таңбаларды жылдам іздеу;). Telegram-ботымызда біз ұятсыздықты сүзгіден өткіземіз және бұл күлкілі әдістерді елемейміз.

    Ал мысалдар, оларсыз біз қайда болар едік:

    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

  • defaultString әдісі

Жол бос болса және кейбір әдепкі мәнді орнату қажет болса, қосымша ақпаратты қосуды болдырмауға көмектесетін әдістер қатары. Кез келген талғамға сай көптеген нұсқалар бар. Олардың ішіндегі ең бастысы - StringUtils.defaultString (соңғы жол str, соңғы жол defaultStr) - str нөл болған жағдайда, біз мәнді defaultStr мәніне жібереміз . Құжаттамадан мысалдар:
StringUtils.defaultString(null, "NULL")  = "NULL"
StringUtils.defaultString("", "NULL")    = ""
StringUtils.defaultString("bat", "NULL") = "bat"
Оны деректермен POJO класын жасағанда пайдалану өте ыңғайлы.

  • deleteWhitespace әдісі

Бұл қызықты әдіс, бірақ оны қолданудың көптеген нұсқалары жоқ. Сонымен қатар, егер мұндай жағдай туындаса, әдіс өте пайдалы болары сөзсіз. Ол жолдағы барлық бос орындарды жояды. Бұл олқылық қай жерде болса да, оның ізі де қалмайды))) Құжаттардан мысалдар:
StringUtils.deleteWhitespace(null)         = null
StringUtils.deleteWhitespace("")           = ""
StringUtils.deleteWhitespace("abc")        = "abc"
StringUtils.deleteWhitespace("   ab  c  ") = "abc"

  • endsWith әдісі

Өзі үшін сөйлейді. Бұл өте пайдалы әдіс: ол жолдың ұсынылған жолмен аяқталатынын немесе аяқталмағанын тексереді. Бұл жиі қажет. Әрине, сіз чекті өзіңіз жаза аласыз, бірақ дайын әдісті пайдалану әлдеқайда ыңғайлы және жақсырақ. Мысалдар:
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
Көріп отырғаныңыздай, бәрі бос жолмен аяқталады))) Менің ойымша, бұл мысал (StringUtils.endsWith("ABCDEF", "") = шын) тек бонус деп ойлаймын, өйткені бұл абсурд) Сондай-ақ әдіс бар. жағдайды елемейді.

  • тең әдіс

Екі жолды салыстыратын нөлдік қауіпсіз әдістің тамаша мысалы. Ол жерге нені салсақ та, жауап сонда болады және ол қатесіз болады. Мысалдар:
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
Әрине, equalsIgnoreCase де бар - бәрі дәл осылай жасалады, тек біз істі елемейміз. Қарайық?
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

  • тең кез келген әдіс

Келіңіздер, теңдік әдісін кеңейтейік . Бірнеше теңдікті тексерудің орнына біз біреуін орындағымыз келеді делік. Ол үшін жолдар жиынтығы салыстырылатын жолды беруге болады; егер олардың кез келгені ұсынылғанға тең болса, ол ШЫН болады. Біз оларды бір-бірімен салыстыру үшін жолды және жолдар жинағын өткіземіз (жинақтан алынған жолдармен бірінші жол). Қиын ба? Мұнда нені білдіретінін түсінуге көмектесетін құжаттардан мысалдар берілген:
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
Сондай-ақ equalsAnyIgnoreCase бар . Және оған мысалдар:
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

Төменгі сызық

Нәтижесінде біз StringUtils дегеннің не екенін және оның қандай пайдалы әдістері бар екенін білу арқылы қалдырамыз. Ал, мұндай пайдалы нәрселер бар екенін және дайын шешімнің көмегімен мәселені жабуға болатын жерлерде әр жолы балдақпен қоршаудың қажеті жоқ екенін түсіну арқылы. Жалпы, біз әдістердің бір бөлігін ғана талдадық. Қаласаңыз, мен жалғастыра аламын: олар көп және олар шынымен назар аударуға лайық. Егер сізде мұны қалай ұсынуға болатыны туралы идеяларыңыз болса, жазыңыз - мен әрқашан жаңа идеяларға ашықпын. Әдістерге арналған құжаттама өте жақсы жазылған, нәтижелермен сынақ мысалдары қосылған, бұл әдіс жұмысын жақсы түсінуге көмектеседі. Сондықтан біз құжаттаманы оқудан тартынбаймыз: бұл қызметтік бағдарламаның функционалдығына қатысты күмәніңізді жояды. Жаңа codeтау тәжірибесін алу үшін мен сізге утorта кластарының қалай жасалатынын және жазылатынын қарауға кеңес беремін. Бұл болашақта пайдалы болады, өйткені әдетте әр жобаның өз сынықтары бар және оларды жазу тәжірибесі пайдалы болады. Дәстүр бойынша, мен сізге Github-тағы аккаунтыма жазылуды ұсынамын ) Менің телеграмма боты бар жобам туралы білмейтіндер үшін мына жерде бірінші мақалаға сілтеме . Оқығаныңыз үшін барлығына рахмет. Мен төменде бірнеше пайдалы сілтемелерді қостым.
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION