Using a Stack and StringTokenizer seems to be a bit of an overkill here. A more simplified version could be written like this:
public static String reverse(final String input) {
Objects.requireNonNull(input);
final StringBuilder stringBuilder = new StringBuilder();
for (final String part : input.split("\\s+")) {
if (!part.isEmpty()) {
if (stringBuilder.length() > 0) {
stringBuilder.insert(0, " ");
}
stringBuilder.insert(0, part);
}
}
return stringBuilder.toString();
}
This uses the ability of split()
to take a String apart based on a given Regex. So the string is split based on a sequence of one or more white-spaces, which matches your initial requirement. Note that split will return an empty array in case input is an empty string.
The for-each loop then works through the array and inserts the part at the beginning of the stringBuilder (except for the first time), which will effectively reverse the array. Most people would probably use a reverse for(i...)
loop here, but because this is a code review I try to be extra correct, and this is the safer version: You cannot cause ArrayIndexOutOfBoundsExceptions with for-each.
Any leading/trailing white-space will cause empty parts to appear in the splitted list, so there is a check for it in the loop. I use isEmpty()
here, as this is in general safer (as in: less chance to do typos) than length() > 0
and benefits from potential, internal optimizations of String in terms of execution speed. You could call trim()
beforehand, but this would cause some unnecessary String operations and creations, so this version is more efficient.
Please also note the check for null
at the beginning. The code would otherwise throw when trying to split on null
, but it is considered good practice to check before-hand, as theoretically (not in this code but in other) you otherwise might leave the system in an undefined state.
I also make use of final
, which allows some compiler optimizations and prevents you from some basic coding mistakes, which is considered good practice.
Testing
It is always a good idea to do some quick testing of the functionality including the basic edge-cases, so here it is:
To check whether or not I do correct white-space removal, I change stringBuilder.insert(0, " ")
to stringBuilder.insert(0, "+")
for the test, to make the white-space visible.
When testing with System.out.println(reverse("the sky is blue"));
the result is:
blue+is+sky+the
The initial requirement is met.
When testing with System.out.println(reverse(" \t the sky is\t blue "));
the result is:
blue+is+sky+the
Leading, trailing and in-between white-spaces are correctly removed.
When testing with reverse("")
the result is an empty String as expected.
When testing with reverse(null)
a NullPointerException is thrown at the beginning of the function.
BreakIterator
(as an answer:) \$\endgroup\$