- Paano kumonekta?
- Mga halimbawa mula sa aking trabaho: kung paano, nang hindi nalalaman ang tungkol sa isang kapaki-pakinabang na klase, ginawa ko ang aking saklay
ng bisikleta. - Tingnan natin ang iba pang mga pamamaraan na nakita kong kawili-wili.
- I-summarize natin.
0. Paano kumonekta
Ang mga naglalakad na magkahawak-kamay sa akin ay halos pamilyar na sa Git at Maven, kaya higit pa ay aasa ako sa kaalamang ito at hindi na uulitin ang aking sarili. Para sa mga nakaligtaan ang aking mga naunang artikulo o nagsimula pa lang magbasa, narito ang mga materyales tungkol sa Maven at Git . Siyempre, nang walang isang build system (Maven, Gredl), maaari mo ring ikonekta ang lahat nang manu-mano, ngunit ito ay baliw sa ngayon at tiyak na hindi mo kailangang gawin ito nang ganoon: mas mahusay na agad na matutunan kung paano gawin ang lahat ng tama. Samakatuwid, upang gumana sa Maven, idinagdag muna namin ang naaangkop na dependency:<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${apache.common.version}</version>
</dependency>
Kung saan ang ${apache.common.version} ay ang bersyon ng library na ito. Susunod, upang mag-import sa ilang klase, magdagdag ng pag-import:
import org.apache.commons.lang3.StringUtils;
At ayun, nasa bag na lahat))
1. Mga halimbawa mula sa isang tunay na proyekto
- paraan ng leftPad
Первый пример вообще сейчас кажется настолько глупым, что очень хорошо, что мои коллеги знали о StringUtils.leftPad и подсказали мне. Какая была задача: code был построен так, что нужно было сделать трансформацию данных, если они пришли не совсем корректно. Ожидалось, что строковое поле должно состоять только из цифр, т.е. если его длина его 3, а meaning — 1, то запись должно быть “001”. То есть, сперва нужно удалить все пробелы, а потом замостить уже это нулями. Еще примеров, чтобы была понятна суть задачи: из “12 “ -> “012” из “1 “ -> “001” И так далее. What сделал я? Описал это в классе 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();
}
За основу взял идею, что мы можем просто получить разницу между оригинальным и обрезанным meaningм и заполнить впереди нулями. Для этого я использовал IntStream, чтобы n раз сделать одну и ту же операцию. И это точно нужно тестировать. А вот что можно было сделать, если бы я знал заранее о методе StringUtils.leftPad:
public static String apacheCommonLeftPad(String value) {
return StringUtils.leftPad(value.trim(), value.length(), "0");
}
Как видите, codeа намного меньше, при этом еще и используется всеми подтвержденная библиотека. Для этого дела я создал два теста в классе LeftPadExampleTest (обычно когда планируют тестировать Howой-то класс, создают в таком же пакете, только в src/test/java, класс с таким же именем+Test). Эти тесты проверяют то один метод, чтобы он правильно трансформировал meaning, то другой. Конечно, тестов нужно бы написать намного больше, но тема тестирования в нашем случае не главная:
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:
- Тест будет восприниматься How тест, если у него есть соответствующая annotation — @Test.
- Если в имени сложно описать работу теста or же описание длинное и его неудобно читать, можно добавить аннотацию @DisplayName и сделать в ней нормальное описание, которое будет видно при запуске тестов.
- При написании тестов я использую BDD подход, в котором разделяю тесты на логические части:
- //given — блок настройки данных перед тестом;
- //when — блок, где запускается та часть codeа, которую мы тестируем;
- //then — блок, в котором проходят проверки результатов работы блока when.
- stripStart метод
Здесь мне нужно было решить вопрос со строкой, в начале которой могли быть пробелы и запятые. После трансформации их не должно было быть в новом значении. Постановка задачи ясна How никогда. Несколько примеров закрепит наше понимание: “, , books” -> “books” “,,,books” -> “books” b , books” -> “b , books” Как и для случая с 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);
}
Здесь мы передаем первым аргументом информацию о том, с Howой строкой работаем, а во втором передаем строку, состоящую из символов, которые нужно пропустить. Точно так же создаем 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(), в который еще добавляется проверка на null. Зачем? Whatбы не было NullPointerException, то есть, во избежание вызова методов переменной, которая является null. Поэтому чтобы не писать:
if(value != null && value.isEmpty()) {
//doing something
}
Можно просто сделать так:
if(StringUtils.isEmpty(value)) {
//doing something
}
Плюс этого метода в том, что сразу видно где Howой метод используются.
2. Разбор других методов класса StringUtils
Теперь поговорим о тех методах, которые на мой взгляд тоже заслуживают внимания. Говоря в общем о StringUtils, стоит сказать, что он предоставляет null безопасные методы-аналоги тех, что есть в классе String (How в случае с методом isEmpty). Пройдемся по ним:
- compare метод
Такой метод есть в String и будет NullPointerException, если в сравнении двух строк одна из них будет null. Whatбы избежать уродских проверок в нашем codeе, можем использовать метод StringUtils.compare(String str1, String str2): он возвращает int How результат сравнения. What обозначают эти значения? int = 0, если они одинаковы (or оба null). int < 0, if str1 меньше, чем str2. int > 0, if str1 больше, чем str2. Также если посмотреть на их documentацию, то в 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
- contains... методы
Здесь разработчики утorты разгулялись на славу. Какой хочешь метод есть. Я решил их собрать воедино:
-
contains — метод, проверяющий, есть ли предполагаемая строка внутри другой строки. Чем это полезно? Можно использовать этот метод, если нужно удостовериться, что есть Howое-то слово в тексте.
Примеры:
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) безопасность присутствует.
containsAny — метод, проверяющий, есть ли хоть Howой-то символ из представленных в строке. Также полезная вещь: часто приходится такое выполнять. Примеры из documentации:
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
-
containsIgnoreCase — полезное расширение для метода contains. Действительно, чтобы проверить такой случай без этого метода, придется перебрать несколько вариантов. А так гармонично будет использован только один метод.
-
containsNone — уже судя по названию можно понять, что проверяется. Строк внутри не должно быть. Полезная вещь, определенно. Быстрый поиск Howих-то неугодных символов ;). В нашем телеграм-боте будем фильтровать маты, не пройдем мимо этих забавных методов.
И примеры, куда ж без них:
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
Несколько примеров из доки:
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
- defaultString метод
Серия методов, которые помогают избежать добавления лишнего ифчика в случае, если строка null и нужно поставить Howое-то meaning по умолчанию. Вариантов есть много, на любой вкус. Главный среди них — StringUtils.defaultString(final String str, final String defaultStr) — в случае, если str равно null, мы просто передадим defaultStr meaning. Примеры из documentации:
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 метод
Говорит сам за себя. Это очень полезный метод: он проверяет, заканчивается ли строка предлагаемой строкой or нет. Часто такое такое нужно. Конечно можно написать проверку и самому, но использовать уже готовый метод явно удобнее и лучше. Примеры:
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", "") = true) просто идет How бонус, ведь это ж абсурд) Также есть там и метод, который игнорирует регистр.
- equals метод
Отличный пример null безопасного метода, который сравнивает две строки. What бы мы туда ни положor, ответ будет, и будет без ошибок. Примеры:
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
- equalsAny метод
Идем дальше и расширяем метод equals. Допустим, instead of нескольких проверок на equalsство, мы хотим выполнить одну. Вот для этого мы можем передать строку, с которой будут сравнивать и набор строк, если Howая-то из них будет равна предлагаемой — то будет 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, Howие в нем есть полезные методы. Ну и с осознанием, что есть вот такие полезные вещи и не нужно городить каждый раз костыли в местах, где можно было бы закрыть вопрос при помощи готового решения. В целом мы разобрали только часть методов. Если будет желание, я могу продолжить: там их еще много, и они реально заслуживают внимания. Если есть идеи, How это еще можно подать, пожалуйста, пишите — я всегда открыт к новым идеям. Документация к методам написана очень качественно, добавлены тестовые примеры с результатами, что помогает лучше понять работу метода. Поэтому не чураемся чтения documentации: она развеет ваши сомнения по поводу функционала утorты. Whatбы получить новый опыт codeинга, советую посмотреть, How делают и пишут утильные классы. Это будет полезно в будущем, так How обычно на каждом проекте есть свои утильные классы, и опыт их написания пригодится. Традиционно предлагаю подписаться на гитхабе на мой аккаунт) Тех, кто не знает о моем проекте с телеграмм-ботом — вот link на первую статью. Всем спасибо за чтение. Внизу добавил несколько полезных ссылок.Полезные ссылки |
---|
GO TO FULL VERSION