- How to connect?
- Examples from my work: how, without knowing about such a useful class, I created my
bicyclecrutch. - Let's look at other methods that I found interesting.
- Let's summarize.
0. How to connect
Those who walk hand in hand with me are already more or less familiar with both Git and Maven, so further I will rely on this knowledge and not repeat myself. For those who missed my previous articles or just started reading, here are materials about Maven and Git . Of course, without a build system (Maven, Gredl), you can also connect everything manually, but this is crazy nowadays and you definitely don’t need to do it like that: it’s better to immediately learn how to do everything correctly. Therefore, to work with Maven, we first add the appropriate dependency:<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${apache.common.version}</version>
</dependency>
Where ${apache.common.version} is the version of this library. Next, to import in some class, add import:
import org.apache.commons.lang3.StringUtils;
And that's it, it's all in the bag))
1. Examples from a real project
- leftPad method
The first example generally seems so stupid now that it’s very good that my colleagues knew about StringUtils.leftPad and told me. What was the task: the code was built in such a way that it was necessary to transform the data if it did not arrive quite correctly. It was expected that the string field should consist only of numbers, i.e. if its length is 3 and its value is 1, then the entry should be “001”. That is, first you need to remove all spaces, and then cover it with zeros. More examples to make the essence of the task clear: from “12“ -> “012” from “1“ -> “001” And so on. What did I do? Described this in the LeftPadExample class . I wrote a method that will do all this:
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();
}
As a basis, I took the idea that we can simply get the difference between the original and the trimmed value and fill it with zeros in front. To do this I used IntStream to do the same operation n times. And this definitely needs to be tested. Here's what I could have done if I had known about the StringUtils.leftPad method in advance :
public static String apacheCommonLeftPad(String value) {
return StringUtils.leftPad(value.trim(), value.length(), "0");
}
As you can see, there is much less code, and a library confirmed by everyone is also used. For this purpose, I created two tests in the LeftPadExampleTest class (usually when they plan to test a class, they create a class with the same name + Test in the same package, only in src/test/java). These tests check one method to ensure that it correctly transforms the value, then another. Of course, a lot more tests would need to be written, but testing is not the main topic in our case:
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);
}
}
I can make a few comments about the tests for now. They are written using JUnit 5:
- A test will be treated as a test if it has the appropriate annotation - @Test.
- If it is difficult to describe the operation of the test in the name or the description is long and inconvenient to read, you can add the @DisplayName annotation and make it a normal description that will be visible when running tests.
- When writing tests, I use the BDD approach, in which I divide the tests into logical parts:
- //given - data setup block before the test;
- //when is the block where the part of the code that we are testing is launched;
- //then is a block in which the results of the when block are checked.
- stripStart method
Here I needed to solve an issue with a line that could have spaces and commas at the beginning. After the transformation, they should not have had a new meaning. The problem statement is clearer than ever. A few examples will reinforce our understanding: “, , books” -> “books” “,,, books” -> “books” b , books” -> “b , books” As in the case with leftPad, I added the StrimStartExample class , in which has two methods. One - with its own solution:
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);
}
Here the idea was to find the index starting from which there are no more spaces or commas. If they were not there at all at the beginning, then the index will be zero. And the second one - with a solution via StringUtils :
public static String apacheCommonLeftPad(String value) {
return StringUtils.stripStart(value, StringUtils.SPACE + COMMA);
}
Here we pass the first argument information about which string we are working with, and in the second we pass a string consisting of characters that need to be skipped. We create the StripStartExampleTest class in the same way :
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 method
This method, of course, is much simpler, but that doesn’t make it any less useful. It extends the capabilities of the String.isEmpty() method , which also adds a check for null. For what? To avoid NullPointerException, that is, to avoid calling methods on a variable that is null . Therefore, in order not to write:
if(value != null && value.isEmpty()) {
//doing something
}
You can simply do this:
if(StringUtils.isEmpty(value)) {
//doing something
}
The advantage of this method is that it is immediately clear where which method is used.
2. Analysis of other methods of the StringUtils class
Now let's talk about those methods that, in my opinion, also deserve attention. Speaking generally about StringUtils , it is worth saying that it provides null safe methods analogous to those found in the String class (as is the case with the isEmpty method ). Let's go through them:
- compare method
Such a method exists in String and will throw a NullPointerException if, when comparing two strings, one of them is null. To avoid ugly checks in our code, we can use the StringUtils.compare(String str1, String str2) method : it returns an int as the result of the comparison. What do these values mean? int = 0 if they are the same (or both are null). int < 0, if str1 is less than str2. int > 0, if str1 is greater than str2. Also, if you look at their documentation, the Javadoc of this method presents the following scenarios:
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... methods
Here the utility developers had a blast. Whatever method you want is there. I decided to put them together:
-
contains is a method that checks whether the expected string is inside another string. How is this useful? You can use this method if you need to make sure that there is a certain word in the text.
Examples:
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
Again, NPE (Null Pointer Exception) security is present.
containsAny is a method that checks whether any of the characters present in the string are present. Also a useful thing: you often have to do this. Examples from the documentation:
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 is a useful extension to the contains method . Indeed, to check such a case without this method, you will have to go through several options. And so only one method will be used harmoniously.
-
containsNone - judging by the name, you can already understand what is being checked. There should be no lines inside. A useful thing, definitely. Quick search for some unwanted characters ;). In our telegram bot we will filter obscenities and will not ignore these funny methods.
And examples, where would we be without them:
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
A few examples from the docs:
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 method
A series of methods that help avoid adding an extra information if the string is null and you need to set some default value. There are many options to suit every taste. Chief among them is StringUtils.defaultString(final String str, final String defaultStr) - in case str is null, we will simply pass the defaultStr value. Examples from the documentation:
StringUtils.defaultString(null, "NULL") = "NULL"
StringUtils.defaultString("", "NULL") = ""
StringUtils.defaultString("bat", "NULL") = "bat"
It is very convenient to use when you create a POJO class with data.
- deleteWhitespace method
This is an interesting method, although there are not many options for its application. At the same time, if such a case arises, the method will definitely be very useful. It removes all spaces from the string. Wherever this gap is, there will be no trace of it))) Examples from the docs:
StringUtils.deleteWhitespace(null) = null
StringUtils.deleteWhitespace("") = ""
StringUtils.deleteWhitespace("abc") = "abc"
StringUtils.deleteWhitespace(" ab c ") = "abc"
- endsWith method
Speaks for itself. This is a very useful method: it checks whether the string ends with the suggested string or not. This is often necessary. Of course, you can write the check yourself, but using a ready-made method is clearly more convenient and better. Examples:
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
As you can see, everything ends with an empty line))) I think that this example (StringUtils.endsWith("ABCDEF", "") = true) is just a bonus, because this is absurd) There is also a method that ignores case .
- equals method
A great example of a null safe method that compares two strings. Whatever we put in there, the answer will be there, and it will be without errors. Examples:
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
Of course, there is also equalsIgnoreCase - everything is done in exactly the same way, only we ignore the case. Let's see?
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 method
Let's go ahead and extend the equals method . Let's say that instead of several equality checks, we want to perform one. For this, we can pass a string with which a set of strings will be compared; if any of them is equal to the proposed one, it will be TRUE. We pass a string and a collection of strings to compare them with each other (the first string with the strings from the collection). Difficult? Here are examples from the docs to help you understand what is meant:
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
There is also equalsAnyIgnoreCase . And examples for it:
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
GO TO FULL VERSION