Reverse a String in Java












24












$begingroup$


Here is the code for the CString class that I created.



public class CString {

public String reverse(String s) {
char array = new char[s.length()];
array = s.toCharArray();
for(int i=0; i<array.length/2; i++) {
char tmp = array[i];
array[i] = array[array.length-1-i];
array[array.length-1-i] = tmp;
}
return charArrayToString(array);
}

public String charArrayToString(char array) {
StringBuffer sb = new StringBuffer();
sb.append(array);
return sb.toString();
}
}


Is there any bug in the code? Are there more efficient ways to reverse a string?










share|improve this question









$endgroup$








  • 6




    $begingroup$
    Have you not checked for bugs yourself? We are not a debugging service. We review working code.
    $endgroup$
    – Jamal
    Feb 27 '14 at 21:24






  • 1




    $begingroup$
    Yes, it passed some simple tests.
    $endgroup$
    – Jane Foster
    Feb 27 '14 at 21:25










  • $begingroup$
    Okay, just making sure. The second question is good, and we can help with that.
    $endgroup$
    – Jamal
    Feb 27 '14 at 21:26
















24












$begingroup$


Here is the code for the CString class that I created.



public class CString {

public String reverse(String s) {
char array = new char[s.length()];
array = s.toCharArray();
for(int i=0; i<array.length/2; i++) {
char tmp = array[i];
array[i] = array[array.length-1-i];
array[array.length-1-i] = tmp;
}
return charArrayToString(array);
}

public String charArrayToString(char array) {
StringBuffer sb = new StringBuffer();
sb.append(array);
return sb.toString();
}
}


Is there any bug in the code? Are there more efficient ways to reverse a string?










share|improve this question









$endgroup$








  • 6




    $begingroup$
    Have you not checked for bugs yourself? We are not a debugging service. We review working code.
    $endgroup$
    – Jamal
    Feb 27 '14 at 21:24






  • 1




    $begingroup$
    Yes, it passed some simple tests.
    $endgroup$
    – Jane Foster
    Feb 27 '14 at 21:25










  • $begingroup$
    Okay, just making sure. The second question is good, and we can help with that.
    $endgroup$
    – Jamal
    Feb 27 '14 at 21:26














24












24








24


10



$begingroup$


Here is the code for the CString class that I created.



public class CString {

public String reverse(String s) {
char array = new char[s.length()];
array = s.toCharArray();
for(int i=0; i<array.length/2; i++) {
char tmp = array[i];
array[i] = array[array.length-1-i];
array[array.length-1-i] = tmp;
}
return charArrayToString(array);
}

public String charArrayToString(char array) {
StringBuffer sb = new StringBuffer();
sb.append(array);
return sb.toString();
}
}


Is there any bug in the code? Are there more efficient ways to reverse a string?










share|improve this question









$endgroup$




Here is the code for the CString class that I created.



public class CString {

public String reverse(String s) {
char array = new char[s.length()];
array = s.toCharArray();
for(int i=0; i<array.length/2; i++) {
char tmp = array[i];
array[i] = array[array.length-1-i];
array[array.length-1-i] = tmp;
}
return charArrayToString(array);
}

public String charArrayToString(char array) {
StringBuffer sb = new StringBuffer();
sb.append(array);
return sb.toString();
}
}


Is there any bug in the code? Are there more efficient ways to reverse a string?







java strings array






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Feb 27 '14 at 21:20









Jane FosterJane Foster

165126




165126








  • 6




    $begingroup$
    Have you not checked for bugs yourself? We are not a debugging service. We review working code.
    $endgroup$
    – Jamal
    Feb 27 '14 at 21:24






  • 1




    $begingroup$
    Yes, it passed some simple tests.
    $endgroup$
    – Jane Foster
    Feb 27 '14 at 21:25










  • $begingroup$
    Okay, just making sure. The second question is good, and we can help with that.
    $endgroup$
    – Jamal
    Feb 27 '14 at 21:26














  • 6




    $begingroup$
    Have you not checked for bugs yourself? We are not a debugging service. We review working code.
    $endgroup$
    – Jamal
    Feb 27 '14 at 21:24






  • 1




    $begingroup$
    Yes, it passed some simple tests.
    $endgroup$
    – Jane Foster
    Feb 27 '14 at 21:25










  • $begingroup$
    Okay, just making sure. The second question is good, and we can help with that.
    $endgroup$
    – Jamal
    Feb 27 '14 at 21:26








6




6




$begingroup$
Have you not checked for bugs yourself? We are not a debugging service. We review working code.
$endgroup$
– Jamal
Feb 27 '14 at 21:24




$begingroup$
Have you not checked for bugs yourself? We are not a debugging service. We review working code.
$endgroup$
– Jamal
Feb 27 '14 at 21:24




1




1




$begingroup$
Yes, it passed some simple tests.
$endgroup$
– Jane Foster
Feb 27 '14 at 21:25




$begingroup$
Yes, it passed some simple tests.
$endgroup$
– Jane Foster
Feb 27 '14 at 21:25












$begingroup$
Okay, just making sure. The second question is good, and we can help with that.
$endgroup$
– Jamal
Feb 27 '14 at 21:26




$begingroup$
Okay, just making sure. The second question is good, and we can help with that.
$endgroup$
– Jamal
Feb 27 '14 at 21:26










4 Answers
4






active

oldest

votes


















36












$begingroup$

Reversing a string, accurately and efficiently.



You are doing it accurately, yes. But, not very efficiently (although there are worse ways to do things).



NOTE:: Palacsint is right that you are not handling null input and surrogate-pairs in the input data. Your solution is not completely accurate. Consider this answer a discussion of the efficiency only.... though I have also updated this answer to include a solution which deals with surrogate pairs efficiently



To understand the efficiency side of things, you have to understand Java String internals.




  • Strings are immutable, cannot be changed.

  • Java is relatively slow at allocating/cleaning memory, try to avoid it.

  • Java can 'inline' method calls and make methods really fast.


So, the best way to make Java efficient is to create/use as little memory as possible, and still end up with a new String (instead of changing an existing string).



Your code has 1 string already, you are creating another string. You cannot avoid that.



What you can avoid though is what happens in between.



Your 'In Between'



What you are doing in between is a bit messy, and wasteful:




    char array = new char[s.length()];
array = s.toCharArray();



You create a new array, then you throw it away, and replace it with the s.toCharArray()... why?



Could be just:



    char array = s.toCharArray();


Also, you have a loop that swaps the chars... this is implemented like:




for(int i=0; i<array.length/2; i++) {



This could be faster if you did it backwards ( could be - depending on which Java you use).



for (int i = array.length / 2; i >= 0; i--) {


This way it only has to do the array.length / 2 one time (though, as I say, some Java implementations will perhaps compile it to work out for you).



Finally, the charArrayToString() is serious overkill....



Converting to a StringBuilder then to a String is a waste of time/resources...




return charArrayToString(array);



can be



return new String(array);


EDIT: Also, as has been mentioned by Richard Miskin... and I assumed you were already using a StringBuilder .... StringBuilder is much more efficient in a single-thread situation than StringBuffer. Unless you have good reason, you always should use StringBuilder.



Efficient in-between ....



public String reverse(String s) {
char array = s.toCharArray();
char tmp;
for(int i = (array.length - 1) / 2; i >= 0; i--) {
tmp = array[i];
array[i] = array[array.length-1-i];
array[array.length-1-i] = tmp;
}
return new String(array);
}


Edit: a different way:



Here are some performance numbers...




String Reverse                           => 4473870 (hot 19.74881ms)
String Reverse Surrogate Aware => 4473870 (hot 22.73488ms)
String Reverse B => 4473870 (hot 25.16192ms)
String Reverse StringBuilder => 4473870 (hot 31.60709ms)
String Reverse StringBuilder NoNullCheck => 4473870 (hot 31.72952ms)
String Reverse Orig => 4473870 (hot 36.83827ms)



For each of those 'hot' runs, I am reversing the order of 479829 words (linux.words) (and there are 4473870 characters in the data excluding newlines).




  • the code I suggested above as the 'efficient in-between' does it in 20 milliseconds



  • based on the discussion about null and Surrogate Pairs, the following code does this 'right', and runs in 23 milliseconds:



    public String reverse(final String s) {
    if (s == null) {
    return null;
    }
    final char array = s.toCharArray();
    char tmp;
    for(int i=array.length/2; i >= 0; i--) {
    tmp = array[i];
    array[i] = array[array.length-1-i];
    array[array.length-1-i] = tmp;
    }
    //surrogate pairs will have been swapped.
    //identify, and un-swap them.
    for (int i = 1; i < array.length; i++) {
    if (Character.isHighSurrogate(array[i]) && Character.isLowSurrogate(array[i - 1])) {
    tmp = array[i];
    array[i] = array[i - 1];
    array[i - 1] = tmp;
    }
    }
    return new String(array);
    }



  • The following code does it in 25 milliseconds



    public String reverse(String s) {
    char array = new char[s.length()];
    for(int i=array.length - 1, j = 0; i >= 0; i--, j++) {
    array[i] = s.charAt(j);
    }
    return new String(array);
    }



  • @palacsint's recommendation does it in 31 milliseconds:



    public static String reverse(final String str) {
    if (str == null) {
    return null;
    }
    return new StringBuilder(str).reverse().toString();
    }



  • @palacsint's recommendation (without the null-check) does it in 31 milliseconds:



    public static String reverse(final String str) {
    return new StringBuilder(str).reverse().toString();
    }


  • Your code does it in 37milliseconds.



If you look at the code, my code creates three objects (char and new String() (which creates char as well))



The s.charAt() code also creates three objects, but has a lot of calls to String.charAt().



The @palacsint recommendation creates 4 objects (StringBuffer, StringBuffer's internal char, String, and String's internal char);



That is true with and without the null-check.



Your code creates 5 objects (6 if you count the first array which is likely to be compiled out...) : (char array, new StringBuffer, StringBuffer's char, String, and String's char)



My guess is that there is a close correlation between our times simply because it takes 5ms to create 480,000 objects on the heap, plus some overhead of actual work.






share|improve this answer











$endgroup$









  • 4




    $begingroup$
    "Java is relatively slow at allocating/cleaning memory, try to avoid it." Fast memory allocation (i.e. memory retrieving by the VM) is not one of the key points of a GC-based system and managed-by-vm memory systems in general? As far I know, "allocating" memory in Java-like languages is pretty fast because there is no "true" allocation (i.e. calling a heap allocator to retrieve new chunks/pages of free memory), only is the VM retrieving you some piece of a larg amount of memory it allocated previously to avoid calling the slow "mallocs" continuously.
    $endgroup$
    – Manu343726
    Feb 27 '14 at 22:24








  • 4




    $begingroup$
    Also, GCs are not slow at collecting, they are pretty fast nowadays. The only problem is the indeterministic way they works (i.e. "I don't know when the GC would stop my program to perform the collecting"), which could be a problem in realtime systems (like videogames).
    $endgroup$
    – Manu343726
    Feb 27 '14 at 22:25








  • 2




    $begingroup$
    @Manu343726 - both your points are valid, but out of context for this discussion. What I am saying is 'using the heap (whether pre-malloc'd or not) is slower than not using the heap.'. Not having to GC some memory is faster than the alternative.
    $endgroup$
    – rolfl
    Feb 27 '14 at 23:20






  • 1




    $begingroup$
    Edited the answer to include some comparative performance results.
    $endgroup$
    – rolfl
    Feb 27 '14 at 23:21






  • 1




    $begingroup$
    Maybe i'm missing something but it doesn't seem like your efficient in-between method is actually reversing the string fully. Pass in any string with an even number of characters. Let's use "Java" as an example. When passed into your method you would expect "avaJ" as the output however you get "aavJ".
    $endgroup$
    – IZI_Shadow_IZI
    7 hours ago





















17












$begingroup$

Learn from the existing implementations, they usually have solutions to corner cases and common pitfalls. For example, Apache Commons Lang StringUtils also has a reverse function. It's implementation is quite simple:



public static String reverse(final String str) {
if (str == null) {
return null;
}
return new StringBuilder(str).reverse().toString();
}


It uses StringBuilder.reverse whose javadoc mentions some special cases:




If there are any surrogate pairs included in the sequence,
these are treated as single characters for the reverse operation.
Thus, the order of the high-low surrogates is never reversed.




Here are a few tests:



@Test
public void testCstring() {
assertEquals("uD800uDC00", CString.reverse("uD800uDC00")); // fails
assertEquals("uD800uDC00", CString.reverse("uDC00uD800")); // OK
}

@Test
public void testStringUtils() throws Exception {
assertEquals("uD800uDC00", StringUtils.reverse("uD800uDC00"));
assertEquals("uD800uDC00", StringUtils.reverse("uDC00uD800"));
}


I don't know too much about these surrogates but you should check it and handle them in your code. I suppose the JDK's implementation is more reliable and it's not coincidence that the handle them in the way they mention in the javadoc.



There is a good question (with great answers) about surrogates on Stack Overflow: What is a surrogate pair in Java?



(See also: Effective Java, 2nd edition, Item 47: Know and use the libraries)






share|improve this answer











$endgroup$









  • 3




    $begingroup$
    Handling surrugates isn't enough. You also need to handle combining characters.
    $endgroup$
    – CodesInChaos
    Feb 28 '14 at 20:06





















10












$begingroup$

The code appears to be functionally correct, although you could simply choose to use a StringBuffer.reverse(). There is some discussion of this here.



If you do need to roll your own reversing method, you can avoid using StringBuffer/StringBuilder at all and simply do new String(array) instead.



As a general point, if you're not dealing with multithreaded code you should probably use StringBuilder in preference to StringBuffer.






share|improve this answer











$endgroup$





















    0












    $begingroup$

    You can use Java 8 lambda functions to reverse a string without mutating or using any local variables. This code will illustrate the reverse function:



    public static void reverse(String myString) {
    return myString
    .chars()
    .mapToObj(c -> String.valueOf((char) c))
    .reduce("", (sb, str) -> str + sb);
    }


    This code gets you the integer stream from the String object:



    myString.chars()


    Once you have the integer stream you can transform the integers to characters using the map function:



    mapToObj(c -> String.valueOf((char) c))


    Then finally you can reduce your characters the way you want. Here I have prepended the characters to the final output string:



    reduce("", (sb, str) -> str + sb);





    share|improve this answer











    $endgroup$













    • $begingroup$
      This code is horribly slow for large strings. Did you ever try to reverse a Wikipedia article using that code? It can take minutes, but should only take microseconds.
      $endgroup$
      – Roland Illig
      Apr 29 '18 at 7:26












    • $begingroup$
      Definitely this code can be optimized, I have given the basic approach on writing a cleaner code.
      $endgroup$
      – Joydeep Bhattacharya
      Apr 30 '18 at 3:03










    protected by Jamal Apr 29 '18 at 5:58



    Thank you for your interest in this question.
    Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



    Would you like to answer one of these unanswered questions instead?














    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    36












    $begingroup$

    Reversing a string, accurately and efficiently.



    You are doing it accurately, yes. But, not very efficiently (although there are worse ways to do things).



    NOTE:: Palacsint is right that you are not handling null input and surrogate-pairs in the input data. Your solution is not completely accurate. Consider this answer a discussion of the efficiency only.... though I have also updated this answer to include a solution which deals with surrogate pairs efficiently



    To understand the efficiency side of things, you have to understand Java String internals.




    • Strings are immutable, cannot be changed.

    • Java is relatively slow at allocating/cleaning memory, try to avoid it.

    • Java can 'inline' method calls and make methods really fast.


    So, the best way to make Java efficient is to create/use as little memory as possible, and still end up with a new String (instead of changing an existing string).



    Your code has 1 string already, you are creating another string. You cannot avoid that.



    What you can avoid though is what happens in between.



    Your 'In Between'



    What you are doing in between is a bit messy, and wasteful:




        char array = new char[s.length()];
    array = s.toCharArray();



    You create a new array, then you throw it away, and replace it with the s.toCharArray()... why?



    Could be just:



        char array = s.toCharArray();


    Also, you have a loop that swaps the chars... this is implemented like:




    for(int i=0; i<array.length/2; i++) {



    This could be faster if you did it backwards ( could be - depending on which Java you use).



    for (int i = array.length / 2; i >= 0; i--) {


    This way it only has to do the array.length / 2 one time (though, as I say, some Java implementations will perhaps compile it to work out for you).



    Finally, the charArrayToString() is serious overkill....



    Converting to a StringBuilder then to a String is a waste of time/resources...




    return charArrayToString(array);



    can be



    return new String(array);


    EDIT: Also, as has been mentioned by Richard Miskin... and I assumed you were already using a StringBuilder .... StringBuilder is much more efficient in a single-thread situation than StringBuffer. Unless you have good reason, you always should use StringBuilder.



    Efficient in-between ....



    public String reverse(String s) {
    char array = s.toCharArray();
    char tmp;
    for(int i = (array.length - 1) / 2; i >= 0; i--) {
    tmp = array[i];
    array[i] = array[array.length-1-i];
    array[array.length-1-i] = tmp;
    }
    return new String(array);
    }


    Edit: a different way:



    Here are some performance numbers...




    String Reverse                           => 4473870 (hot 19.74881ms)
    String Reverse Surrogate Aware => 4473870 (hot 22.73488ms)
    String Reverse B => 4473870 (hot 25.16192ms)
    String Reverse StringBuilder => 4473870 (hot 31.60709ms)
    String Reverse StringBuilder NoNullCheck => 4473870 (hot 31.72952ms)
    String Reverse Orig => 4473870 (hot 36.83827ms)



    For each of those 'hot' runs, I am reversing the order of 479829 words (linux.words) (and there are 4473870 characters in the data excluding newlines).




    • the code I suggested above as the 'efficient in-between' does it in 20 milliseconds



    • based on the discussion about null and Surrogate Pairs, the following code does this 'right', and runs in 23 milliseconds:



      public String reverse(final String s) {
      if (s == null) {
      return null;
      }
      final char array = s.toCharArray();
      char tmp;
      for(int i=array.length/2; i >= 0; i--) {
      tmp = array[i];
      array[i] = array[array.length-1-i];
      array[array.length-1-i] = tmp;
      }
      //surrogate pairs will have been swapped.
      //identify, and un-swap them.
      for (int i = 1; i < array.length; i++) {
      if (Character.isHighSurrogate(array[i]) && Character.isLowSurrogate(array[i - 1])) {
      tmp = array[i];
      array[i] = array[i - 1];
      array[i - 1] = tmp;
      }
      }
      return new String(array);
      }



    • The following code does it in 25 milliseconds



      public String reverse(String s) {
      char array = new char[s.length()];
      for(int i=array.length - 1, j = 0; i >= 0; i--, j++) {
      array[i] = s.charAt(j);
      }
      return new String(array);
      }



    • @palacsint's recommendation does it in 31 milliseconds:



      public static String reverse(final String str) {
      if (str == null) {
      return null;
      }
      return new StringBuilder(str).reverse().toString();
      }



    • @palacsint's recommendation (without the null-check) does it in 31 milliseconds:



      public static String reverse(final String str) {
      return new StringBuilder(str).reverse().toString();
      }


    • Your code does it in 37milliseconds.



    If you look at the code, my code creates three objects (char and new String() (which creates char as well))



    The s.charAt() code also creates three objects, but has a lot of calls to String.charAt().



    The @palacsint recommendation creates 4 objects (StringBuffer, StringBuffer's internal char, String, and String's internal char);



    That is true with and without the null-check.



    Your code creates 5 objects (6 if you count the first array which is likely to be compiled out...) : (char array, new StringBuffer, StringBuffer's char, String, and String's char)



    My guess is that there is a close correlation between our times simply because it takes 5ms to create 480,000 objects on the heap, plus some overhead of actual work.






    share|improve this answer











    $endgroup$









    • 4




      $begingroup$
      "Java is relatively slow at allocating/cleaning memory, try to avoid it." Fast memory allocation (i.e. memory retrieving by the VM) is not one of the key points of a GC-based system and managed-by-vm memory systems in general? As far I know, "allocating" memory in Java-like languages is pretty fast because there is no "true" allocation (i.e. calling a heap allocator to retrieve new chunks/pages of free memory), only is the VM retrieving you some piece of a larg amount of memory it allocated previously to avoid calling the slow "mallocs" continuously.
      $endgroup$
      – Manu343726
      Feb 27 '14 at 22:24








    • 4




      $begingroup$
      Also, GCs are not slow at collecting, they are pretty fast nowadays. The only problem is the indeterministic way they works (i.e. "I don't know when the GC would stop my program to perform the collecting"), which could be a problem in realtime systems (like videogames).
      $endgroup$
      – Manu343726
      Feb 27 '14 at 22:25








    • 2




      $begingroup$
      @Manu343726 - both your points are valid, but out of context for this discussion. What I am saying is 'using the heap (whether pre-malloc'd or not) is slower than not using the heap.'. Not having to GC some memory is faster than the alternative.
      $endgroup$
      – rolfl
      Feb 27 '14 at 23:20






    • 1




      $begingroup$
      Edited the answer to include some comparative performance results.
      $endgroup$
      – rolfl
      Feb 27 '14 at 23:21






    • 1




      $begingroup$
      Maybe i'm missing something but it doesn't seem like your efficient in-between method is actually reversing the string fully. Pass in any string with an even number of characters. Let's use "Java" as an example. When passed into your method you would expect "avaJ" as the output however you get "aavJ".
      $endgroup$
      – IZI_Shadow_IZI
      7 hours ago


















    36












    $begingroup$

    Reversing a string, accurately and efficiently.



    You are doing it accurately, yes. But, not very efficiently (although there are worse ways to do things).



    NOTE:: Palacsint is right that you are not handling null input and surrogate-pairs in the input data. Your solution is not completely accurate. Consider this answer a discussion of the efficiency only.... though I have also updated this answer to include a solution which deals with surrogate pairs efficiently



    To understand the efficiency side of things, you have to understand Java String internals.




    • Strings are immutable, cannot be changed.

    • Java is relatively slow at allocating/cleaning memory, try to avoid it.

    • Java can 'inline' method calls and make methods really fast.


    So, the best way to make Java efficient is to create/use as little memory as possible, and still end up with a new String (instead of changing an existing string).



    Your code has 1 string already, you are creating another string. You cannot avoid that.



    What you can avoid though is what happens in between.



    Your 'In Between'



    What you are doing in between is a bit messy, and wasteful:




        char array = new char[s.length()];
    array = s.toCharArray();



    You create a new array, then you throw it away, and replace it with the s.toCharArray()... why?



    Could be just:



        char array = s.toCharArray();


    Also, you have a loop that swaps the chars... this is implemented like:




    for(int i=0; i<array.length/2; i++) {



    This could be faster if you did it backwards ( could be - depending on which Java you use).



    for (int i = array.length / 2; i >= 0; i--) {


    This way it only has to do the array.length / 2 one time (though, as I say, some Java implementations will perhaps compile it to work out for you).



    Finally, the charArrayToString() is serious overkill....



    Converting to a StringBuilder then to a String is a waste of time/resources...




    return charArrayToString(array);



    can be



    return new String(array);


    EDIT: Also, as has been mentioned by Richard Miskin... and I assumed you were already using a StringBuilder .... StringBuilder is much more efficient in a single-thread situation than StringBuffer. Unless you have good reason, you always should use StringBuilder.



    Efficient in-between ....



    public String reverse(String s) {
    char array = s.toCharArray();
    char tmp;
    for(int i = (array.length - 1) / 2; i >= 0; i--) {
    tmp = array[i];
    array[i] = array[array.length-1-i];
    array[array.length-1-i] = tmp;
    }
    return new String(array);
    }


    Edit: a different way:



    Here are some performance numbers...




    String Reverse                           => 4473870 (hot 19.74881ms)
    String Reverse Surrogate Aware => 4473870 (hot 22.73488ms)
    String Reverse B => 4473870 (hot 25.16192ms)
    String Reverse StringBuilder => 4473870 (hot 31.60709ms)
    String Reverse StringBuilder NoNullCheck => 4473870 (hot 31.72952ms)
    String Reverse Orig => 4473870 (hot 36.83827ms)



    For each of those 'hot' runs, I am reversing the order of 479829 words (linux.words) (and there are 4473870 characters in the data excluding newlines).




    • the code I suggested above as the 'efficient in-between' does it in 20 milliseconds



    • based on the discussion about null and Surrogate Pairs, the following code does this 'right', and runs in 23 milliseconds:



      public String reverse(final String s) {
      if (s == null) {
      return null;
      }
      final char array = s.toCharArray();
      char tmp;
      for(int i=array.length/2; i >= 0; i--) {
      tmp = array[i];
      array[i] = array[array.length-1-i];
      array[array.length-1-i] = tmp;
      }
      //surrogate pairs will have been swapped.
      //identify, and un-swap them.
      for (int i = 1; i < array.length; i++) {
      if (Character.isHighSurrogate(array[i]) && Character.isLowSurrogate(array[i - 1])) {
      tmp = array[i];
      array[i] = array[i - 1];
      array[i - 1] = tmp;
      }
      }
      return new String(array);
      }



    • The following code does it in 25 milliseconds



      public String reverse(String s) {
      char array = new char[s.length()];
      for(int i=array.length - 1, j = 0; i >= 0; i--, j++) {
      array[i] = s.charAt(j);
      }
      return new String(array);
      }



    • @palacsint's recommendation does it in 31 milliseconds:



      public static String reverse(final String str) {
      if (str == null) {
      return null;
      }
      return new StringBuilder(str).reverse().toString();
      }



    • @palacsint's recommendation (without the null-check) does it in 31 milliseconds:



      public static String reverse(final String str) {
      return new StringBuilder(str).reverse().toString();
      }


    • Your code does it in 37milliseconds.



    If you look at the code, my code creates three objects (char and new String() (which creates char as well))



    The s.charAt() code also creates three objects, but has a lot of calls to String.charAt().



    The @palacsint recommendation creates 4 objects (StringBuffer, StringBuffer's internal char, String, and String's internal char);



    That is true with and without the null-check.



    Your code creates 5 objects (6 if you count the first array which is likely to be compiled out...) : (char array, new StringBuffer, StringBuffer's char, String, and String's char)



    My guess is that there is a close correlation between our times simply because it takes 5ms to create 480,000 objects on the heap, plus some overhead of actual work.






    share|improve this answer











    $endgroup$









    • 4




      $begingroup$
      "Java is relatively slow at allocating/cleaning memory, try to avoid it." Fast memory allocation (i.e. memory retrieving by the VM) is not one of the key points of a GC-based system and managed-by-vm memory systems in general? As far I know, "allocating" memory in Java-like languages is pretty fast because there is no "true" allocation (i.e. calling a heap allocator to retrieve new chunks/pages of free memory), only is the VM retrieving you some piece of a larg amount of memory it allocated previously to avoid calling the slow "mallocs" continuously.
      $endgroup$
      – Manu343726
      Feb 27 '14 at 22:24








    • 4




      $begingroup$
      Also, GCs are not slow at collecting, they are pretty fast nowadays. The only problem is the indeterministic way they works (i.e. "I don't know when the GC would stop my program to perform the collecting"), which could be a problem in realtime systems (like videogames).
      $endgroup$
      – Manu343726
      Feb 27 '14 at 22:25








    • 2




      $begingroup$
      @Manu343726 - both your points are valid, but out of context for this discussion. What I am saying is 'using the heap (whether pre-malloc'd or not) is slower than not using the heap.'. Not having to GC some memory is faster than the alternative.
      $endgroup$
      – rolfl
      Feb 27 '14 at 23:20






    • 1




      $begingroup$
      Edited the answer to include some comparative performance results.
      $endgroup$
      – rolfl
      Feb 27 '14 at 23:21






    • 1




      $begingroup$
      Maybe i'm missing something but it doesn't seem like your efficient in-between method is actually reversing the string fully. Pass in any string with an even number of characters. Let's use "Java" as an example. When passed into your method you would expect "avaJ" as the output however you get "aavJ".
      $endgroup$
      – IZI_Shadow_IZI
      7 hours ago
















    36












    36








    36





    $begingroup$

    Reversing a string, accurately and efficiently.



    You are doing it accurately, yes. But, not very efficiently (although there are worse ways to do things).



    NOTE:: Palacsint is right that you are not handling null input and surrogate-pairs in the input data. Your solution is not completely accurate. Consider this answer a discussion of the efficiency only.... though I have also updated this answer to include a solution which deals with surrogate pairs efficiently



    To understand the efficiency side of things, you have to understand Java String internals.




    • Strings are immutable, cannot be changed.

    • Java is relatively slow at allocating/cleaning memory, try to avoid it.

    • Java can 'inline' method calls and make methods really fast.


    So, the best way to make Java efficient is to create/use as little memory as possible, and still end up with a new String (instead of changing an existing string).



    Your code has 1 string already, you are creating another string. You cannot avoid that.



    What you can avoid though is what happens in between.



    Your 'In Between'



    What you are doing in between is a bit messy, and wasteful:




        char array = new char[s.length()];
    array = s.toCharArray();



    You create a new array, then you throw it away, and replace it with the s.toCharArray()... why?



    Could be just:



        char array = s.toCharArray();


    Also, you have a loop that swaps the chars... this is implemented like:




    for(int i=0; i<array.length/2; i++) {



    This could be faster if you did it backwards ( could be - depending on which Java you use).



    for (int i = array.length / 2; i >= 0; i--) {


    This way it only has to do the array.length / 2 one time (though, as I say, some Java implementations will perhaps compile it to work out for you).



    Finally, the charArrayToString() is serious overkill....



    Converting to a StringBuilder then to a String is a waste of time/resources...




    return charArrayToString(array);



    can be



    return new String(array);


    EDIT: Also, as has been mentioned by Richard Miskin... and I assumed you were already using a StringBuilder .... StringBuilder is much more efficient in a single-thread situation than StringBuffer. Unless you have good reason, you always should use StringBuilder.



    Efficient in-between ....



    public String reverse(String s) {
    char array = s.toCharArray();
    char tmp;
    for(int i = (array.length - 1) / 2; i >= 0; i--) {
    tmp = array[i];
    array[i] = array[array.length-1-i];
    array[array.length-1-i] = tmp;
    }
    return new String(array);
    }


    Edit: a different way:



    Here are some performance numbers...




    String Reverse                           => 4473870 (hot 19.74881ms)
    String Reverse Surrogate Aware => 4473870 (hot 22.73488ms)
    String Reverse B => 4473870 (hot 25.16192ms)
    String Reverse StringBuilder => 4473870 (hot 31.60709ms)
    String Reverse StringBuilder NoNullCheck => 4473870 (hot 31.72952ms)
    String Reverse Orig => 4473870 (hot 36.83827ms)



    For each of those 'hot' runs, I am reversing the order of 479829 words (linux.words) (and there are 4473870 characters in the data excluding newlines).




    • the code I suggested above as the 'efficient in-between' does it in 20 milliseconds



    • based on the discussion about null and Surrogate Pairs, the following code does this 'right', and runs in 23 milliseconds:



      public String reverse(final String s) {
      if (s == null) {
      return null;
      }
      final char array = s.toCharArray();
      char tmp;
      for(int i=array.length/2; i >= 0; i--) {
      tmp = array[i];
      array[i] = array[array.length-1-i];
      array[array.length-1-i] = tmp;
      }
      //surrogate pairs will have been swapped.
      //identify, and un-swap them.
      for (int i = 1; i < array.length; i++) {
      if (Character.isHighSurrogate(array[i]) && Character.isLowSurrogate(array[i - 1])) {
      tmp = array[i];
      array[i] = array[i - 1];
      array[i - 1] = tmp;
      }
      }
      return new String(array);
      }



    • The following code does it in 25 milliseconds



      public String reverse(String s) {
      char array = new char[s.length()];
      for(int i=array.length - 1, j = 0; i >= 0; i--, j++) {
      array[i] = s.charAt(j);
      }
      return new String(array);
      }



    • @palacsint's recommendation does it in 31 milliseconds:



      public static String reverse(final String str) {
      if (str == null) {
      return null;
      }
      return new StringBuilder(str).reverse().toString();
      }



    • @palacsint's recommendation (without the null-check) does it in 31 milliseconds:



      public static String reverse(final String str) {
      return new StringBuilder(str).reverse().toString();
      }


    • Your code does it in 37milliseconds.



    If you look at the code, my code creates three objects (char and new String() (which creates char as well))



    The s.charAt() code also creates three objects, but has a lot of calls to String.charAt().



    The @palacsint recommendation creates 4 objects (StringBuffer, StringBuffer's internal char, String, and String's internal char);



    That is true with and without the null-check.



    Your code creates 5 objects (6 if you count the first array which is likely to be compiled out...) : (char array, new StringBuffer, StringBuffer's char, String, and String's char)



    My guess is that there is a close correlation between our times simply because it takes 5ms to create 480,000 objects on the heap, plus some overhead of actual work.






    share|improve this answer











    $endgroup$



    Reversing a string, accurately and efficiently.



    You are doing it accurately, yes. But, not very efficiently (although there are worse ways to do things).



    NOTE:: Palacsint is right that you are not handling null input and surrogate-pairs in the input data. Your solution is not completely accurate. Consider this answer a discussion of the efficiency only.... though I have also updated this answer to include a solution which deals with surrogate pairs efficiently



    To understand the efficiency side of things, you have to understand Java String internals.




    • Strings are immutable, cannot be changed.

    • Java is relatively slow at allocating/cleaning memory, try to avoid it.

    • Java can 'inline' method calls and make methods really fast.


    So, the best way to make Java efficient is to create/use as little memory as possible, and still end up with a new String (instead of changing an existing string).



    Your code has 1 string already, you are creating another string. You cannot avoid that.



    What you can avoid though is what happens in between.



    Your 'In Between'



    What you are doing in between is a bit messy, and wasteful:




        char array = new char[s.length()];
    array = s.toCharArray();



    You create a new array, then you throw it away, and replace it with the s.toCharArray()... why?



    Could be just:



        char array = s.toCharArray();


    Also, you have a loop that swaps the chars... this is implemented like:




    for(int i=0; i<array.length/2; i++) {



    This could be faster if you did it backwards ( could be - depending on which Java you use).



    for (int i = array.length / 2; i >= 0; i--) {


    This way it only has to do the array.length / 2 one time (though, as I say, some Java implementations will perhaps compile it to work out for you).



    Finally, the charArrayToString() is serious overkill....



    Converting to a StringBuilder then to a String is a waste of time/resources...




    return charArrayToString(array);



    can be



    return new String(array);


    EDIT: Also, as has been mentioned by Richard Miskin... and I assumed you were already using a StringBuilder .... StringBuilder is much more efficient in a single-thread situation than StringBuffer. Unless you have good reason, you always should use StringBuilder.



    Efficient in-between ....



    public String reverse(String s) {
    char array = s.toCharArray();
    char tmp;
    for(int i = (array.length - 1) / 2; i >= 0; i--) {
    tmp = array[i];
    array[i] = array[array.length-1-i];
    array[array.length-1-i] = tmp;
    }
    return new String(array);
    }


    Edit: a different way:



    Here are some performance numbers...




    String Reverse                           => 4473870 (hot 19.74881ms)
    String Reverse Surrogate Aware => 4473870 (hot 22.73488ms)
    String Reverse B => 4473870 (hot 25.16192ms)
    String Reverse StringBuilder => 4473870 (hot 31.60709ms)
    String Reverse StringBuilder NoNullCheck => 4473870 (hot 31.72952ms)
    String Reverse Orig => 4473870 (hot 36.83827ms)



    For each of those 'hot' runs, I am reversing the order of 479829 words (linux.words) (and there are 4473870 characters in the data excluding newlines).




    • the code I suggested above as the 'efficient in-between' does it in 20 milliseconds



    • based on the discussion about null and Surrogate Pairs, the following code does this 'right', and runs in 23 milliseconds:



      public String reverse(final String s) {
      if (s == null) {
      return null;
      }
      final char array = s.toCharArray();
      char tmp;
      for(int i=array.length/2; i >= 0; i--) {
      tmp = array[i];
      array[i] = array[array.length-1-i];
      array[array.length-1-i] = tmp;
      }
      //surrogate pairs will have been swapped.
      //identify, and un-swap them.
      for (int i = 1; i < array.length; i++) {
      if (Character.isHighSurrogate(array[i]) && Character.isLowSurrogate(array[i - 1])) {
      tmp = array[i];
      array[i] = array[i - 1];
      array[i - 1] = tmp;
      }
      }
      return new String(array);
      }



    • The following code does it in 25 milliseconds



      public String reverse(String s) {
      char array = new char[s.length()];
      for(int i=array.length - 1, j = 0; i >= 0; i--, j++) {
      array[i] = s.charAt(j);
      }
      return new String(array);
      }



    • @palacsint's recommendation does it in 31 milliseconds:



      public static String reverse(final String str) {
      if (str == null) {
      return null;
      }
      return new StringBuilder(str).reverse().toString();
      }



    • @palacsint's recommendation (without the null-check) does it in 31 milliseconds:



      public static String reverse(final String str) {
      return new StringBuilder(str).reverse().toString();
      }


    • Your code does it in 37milliseconds.



    If you look at the code, my code creates three objects (char and new String() (which creates char as well))



    The s.charAt() code also creates three objects, but has a lot of calls to String.charAt().



    The @palacsint recommendation creates 4 objects (StringBuffer, StringBuffer's internal char, String, and String's internal char);



    That is true with and without the null-check.



    Your code creates 5 objects (6 if you count the first array which is likely to be compiled out...) : (char array, new StringBuffer, StringBuffer's char, String, and String's char)



    My guess is that there is a close correlation between our times simply because it takes 5ms to create 480,000 objects on the heap, plus some overhead of actual work.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 14 mins ago

























    answered Feb 27 '14 at 21:37









    rolflrolfl

    90.9k13191395




    90.9k13191395








    • 4




      $begingroup$
      "Java is relatively slow at allocating/cleaning memory, try to avoid it." Fast memory allocation (i.e. memory retrieving by the VM) is not one of the key points of a GC-based system and managed-by-vm memory systems in general? As far I know, "allocating" memory in Java-like languages is pretty fast because there is no "true" allocation (i.e. calling a heap allocator to retrieve new chunks/pages of free memory), only is the VM retrieving you some piece of a larg amount of memory it allocated previously to avoid calling the slow "mallocs" continuously.
      $endgroup$
      – Manu343726
      Feb 27 '14 at 22:24








    • 4




      $begingroup$
      Also, GCs are not slow at collecting, they are pretty fast nowadays. The only problem is the indeterministic way they works (i.e. "I don't know when the GC would stop my program to perform the collecting"), which could be a problem in realtime systems (like videogames).
      $endgroup$
      – Manu343726
      Feb 27 '14 at 22:25








    • 2




      $begingroup$
      @Manu343726 - both your points are valid, but out of context for this discussion. What I am saying is 'using the heap (whether pre-malloc'd or not) is slower than not using the heap.'. Not having to GC some memory is faster than the alternative.
      $endgroup$
      – rolfl
      Feb 27 '14 at 23:20






    • 1




      $begingroup$
      Edited the answer to include some comparative performance results.
      $endgroup$
      – rolfl
      Feb 27 '14 at 23:21






    • 1




      $begingroup$
      Maybe i'm missing something but it doesn't seem like your efficient in-between method is actually reversing the string fully. Pass in any string with an even number of characters. Let's use "Java" as an example. When passed into your method you would expect "avaJ" as the output however you get "aavJ".
      $endgroup$
      – IZI_Shadow_IZI
      7 hours ago
















    • 4




      $begingroup$
      "Java is relatively slow at allocating/cleaning memory, try to avoid it." Fast memory allocation (i.e. memory retrieving by the VM) is not one of the key points of a GC-based system and managed-by-vm memory systems in general? As far I know, "allocating" memory in Java-like languages is pretty fast because there is no "true" allocation (i.e. calling a heap allocator to retrieve new chunks/pages of free memory), only is the VM retrieving you some piece of a larg amount of memory it allocated previously to avoid calling the slow "mallocs" continuously.
      $endgroup$
      – Manu343726
      Feb 27 '14 at 22:24








    • 4




      $begingroup$
      Also, GCs are not slow at collecting, they are pretty fast nowadays. The only problem is the indeterministic way they works (i.e. "I don't know when the GC would stop my program to perform the collecting"), which could be a problem in realtime systems (like videogames).
      $endgroup$
      – Manu343726
      Feb 27 '14 at 22:25








    • 2




      $begingroup$
      @Manu343726 - both your points are valid, but out of context for this discussion. What I am saying is 'using the heap (whether pre-malloc'd or not) is slower than not using the heap.'. Not having to GC some memory is faster than the alternative.
      $endgroup$
      – rolfl
      Feb 27 '14 at 23:20






    • 1




      $begingroup$
      Edited the answer to include some comparative performance results.
      $endgroup$
      – rolfl
      Feb 27 '14 at 23:21






    • 1




      $begingroup$
      Maybe i'm missing something but it doesn't seem like your efficient in-between method is actually reversing the string fully. Pass in any string with an even number of characters. Let's use "Java" as an example. When passed into your method you would expect "avaJ" as the output however you get "aavJ".
      $endgroup$
      – IZI_Shadow_IZI
      7 hours ago










    4




    4




    $begingroup$
    "Java is relatively slow at allocating/cleaning memory, try to avoid it." Fast memory allocation (i.e. memory retrieving by the VM) is not one of the key points of a GC-based system and managed-by-vm memory systems in general? As far I know, "allocating" memory in Java-like languages is pretty fast because there is no "true" allocation (i.e. calling a heap allocator to retrieve new chunks/pages of free memory), only is the VM retrieving you some piece of a larg amount of memory it allocated previously to avoid calling the slow "mallocs" continuously.
    $endgroup$
    – Manu343726
    Feb 27 '14 at 22:24






    $begingroup$
    "Java is relatively slow at allocating/cleaning memory, try to avoid it." Fast memory allocation (i.e. memory retrieving by the VM) is not one of the key points of a GC-based system and managed-by-vm memory systems in general? As far I know, "allocating" memory in Java-like languages is pretty fast because there is no "true" allocation (i.e. calling a heap allocator to retrieve new chunks/pages of free memory), only is the VM retrieving you some piece of a larg amount of memory it allocated previously to avoid calling the slow "mallocs" continuously.
    $endgroup$
    – Manu343726
    Feb 27 '14 at 22:24






    4




    4




    $begingroup$
    Also, GCs are not slow at collecting, they are pretty fast nowadays. The only problem is the indeterministic way they works (i.e. "I don't know when the GC would stop my program to perform the collecting"), which could be a problem in realtime systems (like videogames).
    $endgroup$
    – Manu343726
    Feb 27 '14 at 22:25






    $begingroup$
    Also, GCs are not slow at collecting, they are pretty fast nowadays. The only problem is the indeterministic way they works (i.e. "I don't know when the GC would stop my program to perform the collecting"), which could be a problem in realtime systems (like videogames).
    $endgroup$
    – Manu343726
    Feb 27 '14 at 22:25






    2




    2




    $begingroup$
    @Manu343726 - both your points are valid, but out of context for this discussion. What I am saying is 'using the heap (whether pre-malloc'd or not) is slower than not using the heap.'. Not having to GC some memory is faster than the alternative.
    $endgroup$
    – rolfl
    Feb 27 '14 at 23:20




    $begingroup$
    @Manu343726 - both your points are valid, but out of context for this discussion. What I am saying is 'using the heap (whether pre-malloc'd or not) is slower than not using the heap.'. Not having to GC some memory is faster than the alternative.
    $endgroup$
    – rolfl
    Feb 27 '14 at 23:20




    1




    1




    $begingroup$
    Edited the answer to include some comparative performance results.
    $endgroup$
    – rolfl
    Feb 27 '14 at 23:21




    $begingroup$
    Edited the answer to include some comparative performance results.
    $endgroup$
    – rolfl
    Feb 27 '14 at 23:21




    1




    1




    $begingroup$
    Maybe i'm missing something but it doesn't seem like your efficient in-between method is actually reversing the string fully. Pass in any string with an even number of characters. Let's use "Java" as an example. When passed into your method you would expect "avaJ" as the output however you get "aavJ".
    $endgroup$
    – IZI_Shadow_IZI
    7 hours ago






    $begingroup$
    Maybe i'm missing something but it doesn't seem like your efficient in-between method is actually reversing the string fully. Pass in any string with an even number of characters. Let's use "Java" as an example. When passed into your method you would expect "avaJ" as the output however you get "aavJ".
    $endgroup$
    – IZI_Shadow_IZI
    7 hours ago















    17












    $begingroup$

    Learn from the existing implementations, they usually have solutions to corner cases and common pitfalls. For example, Apache Commons Lang StringUtils also has a reverse function. It's implementation is quite simple:



    public static String reverse(final String str) {
    if (str == null) {
    return null;
    }
    return new StringBuilder(str).reverse().toString();
    }


    It uses StringBuilder.reverse whose javadoc mentions some special cases:




    If there are any surrogate pairs included in the sequence,
    these are treated as single characters for the reverse operation.
    Thus, the order of the high-low surrogates is never reversed.




    Here are a few tests:



    @Test
    public void testCstring() {
    assertEquals("uD800uDC00", CString.reverse("uD800uDC00")); // fails
    assertEquals("uD800uDC00", CString.reverse("uDC00uD800")); // OK
    }

    @Test
    public void testStringUtils() throws Exception {
    assertEquals("uD800uDC00", StringUtils.reverse("uD800uDC00"));
    assertEquals("uD800uDC00", StringUtils.reverse("uDC00uD800"));
    }


    I don't know too much about these surrogates but you should check it and handle them in your code. I suppose the JDK's implementation is more reliable and it's not coincidence that the handle them in the way they mention in the javadoc.



    There is a good question (with great answers) about surrogates on Stack Overflow: What is a surrogate pair in Java?



    (See also: Effective Java, 2nd edition, Item 47: Know and use the libraries)






    share|improve this answer











    $endgroup$









    • 3




      $begingroup$
      Handling surrugates isn't enough. You also need to handle combining characters.
      $endgroup$
      – CodesInChaos
      Feb 28 '14 at 20:06


















    17












    $begingroup$

    Learn from the existing implementations, they usually have solutions to corner cases and common pitfalls. For example, Apache Commons Lang StringUtils also has a reverse function. It's implementation is quite simple:



    public static String reverse(final String str) {
    if (str == null) {
    return null;
    }
    return new StringBuilder(str).reverse().toString();
    }


    It uses StringBuilder.reverse whose javadoc mentions some special cases:




    If there are any surrogate pairs included in the sequence,
    these are treated as single characters for the reverse operation.
    Thus, the order of the high-low surrogates is never reversed.




    Here are a few tests:



    @Test
    public void testCstring() {
    assertEquals("uD800uDC00", CString.reverse("uD800uDC00")); // fails
    assertEquals("uD800uDC00", CString.reverse("uDC00uD800")); // OK
    }

    @Test
    public void testStringUtils() throws Exception {
    assertEquals("uD800uDC00", StringUtils.reverse("uD800uDC00"));
    assertEquals("uD800uDC00", StringUtils.reverse("uDC00uD800"));
    }


    I don't know too much about these surrogates but you should check it and handle them in your code. I suppose the JDK's implementation is more reliable and it's not coincidence that the handle them in the way they mention in the javadoc.



    There is a good question (with great answers) about surrogates on Stack Overflow: What is a surrogate pair in Java?



    (See also: Effective Java, 2nd edition, Item 47: Know and use the libraries)






    share|improve this answer











    $endgroup$









    • 3




      $begingroup$
      Handling surrugates isn't enough. You also need to handle combining characters.
      $endgroup$
      – CodesInChaos
      Feb 28 '14 at 20:06
















    17












    17








    17





    $begingroup$

    Learn from the existing implementations, they usually have solutions to corner cases and common pitfalls. For example, Apache Commons Lang StringUtils also has a reverse function. It's implementation is quite simple:



    public static String reverse(final String str) {
    if (str == null) {
    return null;
    }
    return new StringBuilder(str).reverse().toString();
    }


    It uses StringBuilder.reverse whose javadoc mentions some special cases:




    If there are any surrogate pairs included in the sequence,
    these are treated as single characters for the reverse operation.
    Thus, the order of the high-low surrogates is never reversed.




    Here are a few tests:



    @Test
    public void testCstring() {
    assertEquals("uD800uDC00", CString.reverse("uD800uDC00")); // fails
    assertEquals("uD800uDC00", CString.reverse("uDC00uD800")); // OK
    }

    @Test
    public void testStringUtils() throws Exception {
    assertEquals("uD800uDC00", StringUtils.reverse("uD800uDC00"));
    assertEquals("uD800uDC00", StringUtils.reverse("uDC00uD800"));
    }


    I don't know too much about these surrogates but you should check it and handle them in your code. I suppose the JDK's implementation is more reliable and it's not coincidence that the handle them in the way they mention in the javadoc.



    There is a good question (with great answers) about surrogates on Stack Overflow: What is a surrogate pair in Java?



    (See also: Effective Java, 2nd edition, Item 47: Know and use the libraries)






    share|improve this answer











    $endgroup$



    Learn from the existing implementations, they usually have solutions to corner cases and common pitfalls. For example, Apache Commons Lang StringUtils also has a reverse function. It's implementation is quite simple:



    public static String reverse(final String str) {
    if (str == null) {
    return null;
    }
    return new StringBuilder(str).reverse().toString();
    }


    It uses StringBuilder.reverse whose javadoc mentions some special cases:




    If there are any surrogate pairs included in the sequence,
    these are treated as single characters for the reverse operation.
    Thus, the order of the high-low surrogates is never reversed.




    Here are a few tests:



    @Test
    public void testCstring() {
    assertEquals("uD800uDC00", CString.reverse("uD800uDC00")); // fails
    assertEquals("uD800uDC00", CString.reverse("uDC00uD800")); // OK
    }

    @Test
    public void testStringUtils() throws Exception {
    assertEquals("uD800uDC00", StringUtils.reverse("uD800uDC00"));
    assertEquals("uD800uDC00", StringUtils.reverse("uDC00uD800"));
    }


    I don't know too much about these surrogates but you should check it and handle them in your code. I suppose the JDK's implementation is more reliable and it's not coincidence that the handle them in the way they mention in the javadoc.



    There is a good question (with great answers) about surrogates on Stack Overflow: What is a surrogate pair in Java?



    (See also: Effective Java, 2nd edition, Item 47: Know and use the libraries)







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited May 23 '17 at 12:40









    Community

    1




    1










    answered Feb 27 '14 at 21:50









    palacsintpalacsint

    29.1k971153




    29.1k971153








    • 3




      $begingroup$
      Handling surrugates isn't enough. You also need to handle combining characters.
      $endgroup$
      – CodesInChaos
      Feb 28 '14 at 20:06
















    • 3




      $begingroup$
      Handling surrugates isn't enough. You also need to handle combining characters.
      $endgroup$
      – CodesInChaos
      Feb 28 '14 at 20:06










    3




    3




    $begingroup$
    Handling surrugates isn't enough. You also need to handle combining characters.
    $endgroup$
    – CodesInChaos
    Feb 28 '14 at 20:06






    $begingroup$
    Handling surrugates isn't enough. You also need to handle combining characters.
    $endgroup$
    – CodesInChaos
    Feb 28 '14 at 20:06













    10












    $begingroup$

    The code appears to be functionally correct, although you could simply choose to use a StringBuffer.reverse(). There is some discussion of this here.



    If you do need to roll your own reversing method, you can avoid using StringBuffer/StringBuilder at all and simply do new String(array) instead.



    As a general point, if you're not dealing with multithreaded code you should probably use StringBuilder in preference to StringBuffer.






    share|improve this answer











    $endgroup$


















      10












      $begingroup$

      The code appears to be functionally correct, although you could simply choose to use a StringBuffer.reverse(). There is some discussion of this here.



      If you do need to roll your own reversing method, you can avoid using StringBuffer/StringBuilder at all and simply do new String(array) instead.



      As a general point, if you're not dealing with multithreaded code you should probably use StringBuilder in preference to StringBuffer.






      share|improve this answer











      $endgroup$
















        10












        10








        10





        $begingroup$

        The code appears to be functionally correct, although you could simply choose to use a StringBuffer.reverse(). There is some discussion of this here.



        If you do need to roll your own reversing method, you can avoid using StringBuffer/StringBuilder at all and simply do new String(array) instead.



        As a general point, if you're not dealing with multithreaded code you should probably use StringBuilder in preference to StringBuffer.






        share|improve this answer











        $endgroup$



        The code appears to be functionally correct, although you could simply choose to use a StringBuffer.reverse(). There is some discussion of this here.



        If you do need to roll your own reversing method, you can avoid using StringBuffer/StringBuilder at all and simply do new String(array) instead.



        As a general point, if you're not dealing with multithreaded code you should probably use StringBuilder in preference to StringBuffer.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited May 23 '17 at 12:41









        Community

        1




        1










        answered Feb 27 '14 at 21:34









        Richard MiskinRichard Miskin

        20113




        20113























            0












            $begingroup$

            You can use Java 8 lambda functions to reverse a string without mutating or using any local variables. This code will illustrate the reverse function:



            public static void reverse(String myString) {
            return myString
            .chars()
            .mapToObj(c -> String.valueOf((char) c))
            .reduce("", (sb, str) -> str + sb);
            }


            This code gets you the integer stream from the String object:



            myString.chars()


            Once you have the integer stream you can transform the integers to characters using the map function:



            mapToObj(c -> String.valueOf((char) c))


            Then finally you can reduce your characters the way you want. Here I have prepended the characters to the final output string:



            reduce("", (sb, str) -> str + sb);





            share|improve this answer











            $endgroup$













            • $begingroup$
              This code is horribly slow for large strings. Did you ever try to reverse a Wikipedia article using that code? It can take minutes, but should only take microseconds.
              $endgroup$
              – Roland Illig
              Apr 29 '18 at 7:26












            • $begingroup$
              Definitely this code can be optimized, I have given the basic approach on writing a cleaner code.
              $endgroup$
              – Joydeep Bhattacharya
              Apr 30 '18 at 3:03
















            0












            $begingroup$

            You can use Java 8 lambda functions to reverse a string without mutating or using any local variables. This code will illustrate the reverse function:



            public static void reverse(String myString) {
            return myString
            .chars()
            .mapToObj(c -> String.valueOf((char) c))
            .reduce("", (sb, str) -> str + sb);
            }


            This code gets you the integer stream from the String object:



            myString.chars()


            Once you have the integer stream you can transform the integers to characters using the map function:



            mapToObj(c -> String.valueOf((char) c))


            Then finally you can reduce your characters the way you want. Here I have prepended the characters to the final output string:



            reduce("", (sb, str) -> str + sb);





            share|improve this answer











            $endgroup$













            • $begingroup$
              This code is horribly slow for large strings. Did you ever try to reverse a Wikipedia article using that code? It can take minutes, but should only take microseconds.
              $endgroup$
              – Roland Illig
              Apr 29 '18 at 7:26












            • $begingroup$
              Definitely this code can be optimized, I have given the basic approach on writing a cleaner code.
              $endgroup$
              – Joydeep Bhattacharya
              Apr 30 '18 at 3:03














            0












            0








            0





            $begingroup$

            You can use Java 8 lambda functions to reverse a string without mutating or using any local variables. This code will illustrate the reverse function:



            public static void reverse(String myString) {
            return myString
            .chars()
            .mapToObj(c -> String.valueOf((char) c))
            .reduce("", (sb, str) -> str + sb);
            }


            This code gets you the integer stream from the String object:



            myString.chars()


            Once you have the integer stream you can transform the integers to characters using the map function:



            mapToObj(c -> String.valueOf((char) c))


            Then finally you can reduce your characters the way you want. Here I have prepended the characters to the final output string:



            reduce("", (sb, str) -> str + sb);





            share|improve this answer











            $endgroup$



            You can use Java 8 lambda functions to reverse a string without mutating or using any local variables. This code will illustrate the reverse function:



            public static void reverse(String myString) {
            return myString
            .chars()
            .mapToObj(c -> String.valueOf((char) c))
            .reduce("", (sb, str) -> str + sb);
            }


            This code gets you the integer stream from the String object:



            myString.chars()


            Once you have the integer stream you can transform the integers to characters using the map function:



            mapToObj(c -> String.valueOf((char) c))


            Then finally you can reduce your characters the way you want. Here I have prepended the characters to the final output string:



            reduce("", (sb, str) -> str + sb);






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Apr 29 '18 at 6:00









            Jamal

            30.3k11118227




            30.3k11118227










            answered Apr 29 '18 at 5:57









            Joydeep BhattacharyaJoydeep Bhattacharya

            594




            594












            • $begingroup$
              This code is horribly slow for large strings. Did you ever try to reverse a Wikipedia article using that code? It can take minutes, but should only take microseconds.
              $endgroup$
              – Roland Illig
              Apr 29 '18 at 7:26












            • $begingroup$
              Definitely this code can be optimized, I have given the basic approach on writing a cleaner code.
              $endgroup$
              – Joydeep Bhattacharya
              Apr 30 '18 at 3:03


















            • $begingroup$
              This code is horribly slow for large strings. Did you ever try to reverse a Wikipedia article using that code? It can take minutes, but should only take microseconds.
              $endgroup$
              – Roland Illig
              Apr 29 '18 at 7:26












            • $begingroup$
              Definitely this code can be optimized, I have given the basic approach on writing a cleaner code.
              $endgroup$
              – Joydeep Bhattacharya
              Apr 30 '18 at 3:03
















            $begingroup$
            This code is horribly slow for large strings. Did you ever try to reverse a Wikipedia article using that code? It can take minutes, but should only take microseconds.
            $endgroup$
            – Roland Illig
            Apr 29 '18 at 7:26






            $begingroup$
            This code is horribly slow for large strings. Did you ever try to reverse a Wikipedia article using that code? It can take minutes, but should only take microseconds.
            $endgroup$
            – Roland Illig
            Apr 29 '18 at 7:26














            $begingroup$
            Definitely this code can be optimized, I have given the basic approach on writing a cleaner code.
            $endgroup$
            – Joydeep Bhattacharya
            Apr 30 '18 at 3:03




            $begingroup$
            Definitely this code can be optimized, I have given the basic approach on writing a cleaner code.
            $endgroup$
            – Joydeep Bhattacharya
            Apr 30 '18 at 3:03





            protected by Jamal Apr 29 '18 at 5:58



            Thank you for your interest in this question.
            Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



            Would you like to answer one of these unanswered questions instead?



            Popular posts from this blog

            Create new schema in PostgreSQL using DBeaver

            Deepest pit of an array with Javascript: test on Codility

            Costa Masnaga