开发者

Question about reversing a string

i am trying to do a simple string manipulation. input is "murder", i want to get "murderredrum".

i tried this

String str = "murder";
StringBu开发者_开发问答ffer buf = new StringBuffer(str);
// buf is now "murder", so i append the reverse which is "redrum"
buf.append(buf.reverse());
System.out.println(buf);

but now i get "redrumredrum" instead of "murderredrum".

can someone explain what's wrong with my program? thank you.


The short answer

The line:

buf.append(buf.reverse());

essentially does the following:

buf.reverse();    // buf is now "redrum"
buf.append(buf);

This is why you get "redrumredrum".

That is, buf.reverse() doesn't return a new StringBuffer which is the reverse of buf. It returns buf, after it had reversed itself!

There are many ways to "fix" this, but the easiest would be to explicitly create a new StringBuffer for the reversal, so something like this:

buf.append(new StringBuffer(str).reverse());

Deeper insight: comparing String and StringBuffer

String in Java is immutable. On the other hand, StringBuffer is mutable (which is why you can, among other things, append things to it).

This is why with String, a transforming method really returns a new String. This is why something like this is "wrong"

String str = "murder";
str.toUpperCase(); // this is "wrong"!!!
System.out.println(str); // still "murder"

Instead you want to do:

String str = "murder";
str = str.toUpperCase(); // YES!!!
System.out.println(str); // now "MURDER"!!!

However, the situation is far from analogous with StringBuffer. Most StringBuffer methods do return StringBuffer, but they return the same instance that it was invoked on! They do NOT return a new StringBuffer instance. In fact, you're free to discard the "result", because these methods have already accomplished what they do through various mutations (i.e. side effects) to the instance it's invoked upon.

These methods could've been declared as void, but the reason why they essentially return this; instead is because it facilitates method chaining, allowing you to write something like:

sb.append(thisThing).append(thatThing).append(oneMoreForGoodMeasure);

Related questions

  • Method chaining - why is it a good practice, or not?
  • Fluent Interfaces - Method Chaining

Appendix: StringBuffer vs StringBuilder

Instead of StringBuffer, you should generally prefer StringBuilder, which is faster because it's not synchronized. Most of the discussions above also applies to StringBuilder.

From the documentation:

StringBuffer : A thread-safe, mutable sequence of characters. [...] As of JDK 5, this class has been supplemented with an equivalent class designed for use by a single thread, StringBuilder, which should generally be preferred as it supports all of the same operations but faster, as it performs no synchronization.

StringBuilder : A mutable sequence of characters. [...] Instances of StringBuilder are not safe for use by multiple threads. If such synchronization is required then it is recommended that StringBuffer be used.

Related questions

  • StringBuilder and StringBuffer in Java

Bonus material! Alternative solution!

Here's an alternative "fix" to the problem that is perhaps more readable:

StringBuilder word = new StringBuilder("murder");
StringBuilder worddrow = new StringBuilder(); // starts empty

worddrow.append(word).append(word.reverse());

System.out.println(worddrow); // "murderredrum"

Note that while this should do fine for short strings, it does use an extra buffer which means that it's not the most efficient way to solve the problem.

Related questions

  • Reverse a string in Java, in O(1)? - as a CharSequence, yes this can be done!

Bonus material again! The last laugh!

StringBuilder sb = new StringBuilder("ha");
sb.append(sb.append(sb));
System.out.println(sb); // "hahahaha"


buf.reverse() gets called first it modifies the stringbuffer to redrum. Now you are appending redrum to redrum

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜