7
\$\begingroup\$

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;
    }

}
\$\endgroup\$
0
10
\$\begingroup\$

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();
}
\$\endgroup\$
5
\$\begingroup\$

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));
    }

}
\$\endgroup\$
6
  • \$\begingroup\$ Good catch about that remark in the JavaDoc. Interestingly, it's "discouraged", but not quite deprecated. And to my knowledge, no deprecated method has actually been removed, to date. I think it's just saying that the Enumeration-based interface feels "old". \$\endgroup\$ – 200_success Dec 6 '15 at 17:24
  • \$\begingroup\$ Some people still swear by StringTokenizer because it does not use regex to parse the String. Sure, it's not really recommended in this day and age, and choosing a 'discouraged' class in the name of performance smells of premature optimization, but it's still a valid point. Also, I don't think there's an easy equivalent of StringTokenizer.nextToken(String) in the 'modern' approaches... if anyone so happens to really require it. \$\endgroup\$ – h.j.k. Dec 7 '15 at 1:51
  • 1
    \$\begingroup\$ @h.j.k. Would be interesting to see some micro-benchmarks between the two. My suspicion would be that any regex equivalent to a simple match that can be used in StringTokenizer would be equally fast. As far as hasNextToken goes - Pattern.splitAsStream().iterator() covers that and much more. Pre-Java8 a Scanner is an Iterator so covers both regex and non-regex use cases... In short: no excuses! \$\endgroup\$ – Boris the Spider Dec 7 '15 at 9:21
  • 1
    \$\begingroup\$ @h.j.k. see Scanner.useDelimiter - this allows for the same and to switch between basic/regex patterns. Agreed that this functionality isn't available on splitAsStream - but the same might be achieved with the correct regex; depending on how dynamic you need the pattern to be. \$\endgroup\$ – Boris the Spider Dec 7 '15 at 10:45
  • 1
    \$\begingroup\$ @h.j.k. I have posted a benchmark for review. But it seems to indicate that split and splitAsStream are rather faster than StringTokenizer. \$\endgroup\$ – Boris the Spider Dec 7 '15 at 11:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.