Problem
Given a dot separated domain name, reverse the domain elements.
Example:
codereview.stackexchange.com -> com.stackexchange.codereview
google.com -> com.google
I just wanted some suggestions to improve my code. Or if you can suggest a better way, please do so.
package practice;
import java.util.Scanner;
import java.util.StringTokenizer;
public class ReverseDomainName
{
public static void main(String args[])
{
Scanner sc = new Scanner(System.in);
System.out.println("Enter the domain name to be reversed");
String domain = sc.nextLine();
sc.close();
ReverseDomainName obj = new ReverseDomainName();
String reversedDomainName = obj.reverseDomainNameString(domain);
System.out.println("The reversed Domain Name = "+reversedDomainName);
}
public String reverseDomainNameString(String s)
{
String reverse1 = "",word ="" ;
int i;
StringTokenizer st = new StringTokenizer(s,".");
int len = st.countTokens();
/*
* The check is performed so that instead of com.stackexchange.codereview.
* we can get the proper com.stackexhange.codereview so no
* extra dot
*/
word = st.nextToken();
reverse1 = word+reverse1;
for(i=1;i<len;i++)
{
word = st.nextToken();
reverse1 = word +"."+reverse1;
}
return reverse1;
}
}
Solution
StringTokenizer
is an OK solution, but I think that String.split()
would lead to a less verbose solution.
Here is a Java 8 solution that uses split()
:
public static String reverseDomainNameString(String s) {
List<String> components = Arrays.asList(s.split("\."));
Collections.reverse(components);
return String.join(".", components.toArray(new String[0]));
}
Without Java 8’s String.join()
, though, the solution would be more tedious. Note that it might be a good idea to ensure that the string is non-empty, otherwise components[0]
(or st.nextToken()
in your original solution) would crash.
public static String reverse(String s) {
if (s == null || s.isEmpty()) return s;
String[] components = s.split("\.");
StringBuilder result = new StringBuilder(s.length());
for (int i = components.length - 1; i > 0; i--) {
result.append(components[i]).append(".");
}
return result.append(components[0]).toString();
}
One big point
From the JavaDoc for StringTokenizer
StringTokenizer
is a legacy class that is retained for compatibility reasons although its use is discouraged in new code.1 (emphasis mine)
If even Oracle discourage its use, I suggest you avoid it like the plague.
A Java 8 Stream
based solution:
import static java.util.stream.Collectors.joining;
public static String reverseDomain(final String domain) {
final String[] tokenized = domain.split("\.");
return IntStream.range(0, tokenized.length)
.map(i -> tokenized.length - 1 - i)
.mapToObj(i -> tokenized[i])
.collect(joining("."));
}
Here we use String.split
to tokenize the String
. Using Pattern.splitToStream
, which snazzier, makes for uglier code as there is no way to reverse a Stream
.
We then Stream
the range [0, tokenized.length)
and use map
to get the indices in reverse. Finally we just need to get the item at the index from tokenized
and use Collectors.joining
to reconstruct the reverse domain.
As always, unit tests are a must:
@RunWith(Parameterized.class)
public class AppTest {
@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> parameters() {
return Arrays.asList(new Object[][]{
{"", ""},
{"google.com", "com.google"},
{"codereview.stackexchange.com", "com.stackexchange.codereview"}
});
}
private final String input;
private final String expected;
public AppTest(String input, String expected) {
this.input = input;
this.expected = expected;
}
@Test
public void testReverseDomain() {
Assert.assertEquals(expected, App.reverseDomain(input));
}
}