Exact Difference Between Charsequence and String in Java

Exact difference between CharSequence and String in java

General differences

There are several classes which implement the CharSequence interface besides String. Among these are

  • StringBuilder for variable-length character sequences which can be modified
  • CharBuffer for fixed-length low-level character sequences which can be modified

Any method which accepts a CharSequence can operate on all of these equally well. Any method which only accepts a String will require conversion. So using CharSequence as an argument type in all the places where you don't care about the internals is prudent. However you should use String as a return type if you actually return a String, because that avoids possible conversions of returned values if the calling method actually does require a String.

Also note that maps should use String as key type, not CharSequence, as map keys must not change. In other words, sometimes the immutable nature of String is essential.

Specific code snippet

As for the code you pasted: simply compile that, and have a look at the JVM bytecode using javap -v. There you will notice that both obj and str are references to the same constant object. As a String is immutable, this kind of sharing is all right.

The + operator of String is compiled as invocations of various StringBuilder.append calls. So it is equivalent to

System.out.println(
(new StringBuilder())
.append("output is : ")
.append((Object)obj)
.append(" ")
.append(str)
.toString()
)

I must confess I'm a bit surprised that my compiler javac 1.6.0_33 compiles the + obj using StringBuilder.append(Object) instead of StringBuilder.append(CharSequence). The former probably involves a call to the toString() method of the object, whereas the latter should be possible in a more efficient way. On the other hand, String.toString() simply returns the String itself, so there is little penalty there. So StringBuilder.append(String) might be more efficient by about one method invocation.

CharSequence VS String in Java?

Strings are CharSequences, so you can just use Strings and not worry. Android is merely trying to be helpful by allowing you to also specify other CharSequence objects, like StringBuffers.

Choosing between CharSequence and String for an API

Quoting CharSequence Javadoc:

This interface does not refine the general contracts of the equals and hashCode methods. The result of testing two objects that implement CharSequence for equality is therefore, in general, undefined. Each object may be implemented by a different class, and there is no guarantee that each class will be capable of testing its instances for equality with those of the other. It is therefore inappropriate to use arbitrary CharSequence instances as elements in a set or as keys in a map.

Hence IMO We must think twice before using CharSequnce as a replacement for String.

Difference Between StringBuffer(String str) and StringBuffer(CharSequence chars)

A CharSequence is an interface; it happens that String implements it.

This means that for instance, when you call .charAt() on a String, what is really called is the implementation of String for this method of CharSequence.

As you can see from the javadoc of CharSequence, not many classes in the JDK actually implement this interface.

As to why two constructors, StringBuffer dates back to Java 1.0 and CharSequence appears in 1.4 only; however, this is also the case that StringBuilder (which you should use, really, instead of StringBuffer) has two constructors (one with a CharSequence as an argument, another with a String as an argument), so there are probably optimizations implied when a String is passed as an argument. As to what such optimizations could be, well, it is a case of "Use The Source, Luke"(tm).

As an example of a CharSequence implementation which is not in the JDK, you can for example see one of my projects: largetext. Note that among other things, generating a Matcher from a Pattern uses a CharSequence and not a String as an argument; and since String implements CharSequence, well, passing a String as an argument works.

Difference between CharSequence interface and CharSequence key

Take a look at the JavaDocs for CharSequence: https://docs.oracle.com/javase/8/docs/api/java/lang/CharSequence.html

Under implementing classes, you will see

CharBuffer, Segment, String, StringBuffer, StringBuilder

So by defining Action as taking a CharSequence parameter, it means that you can use any of the CharSequence implementations above, or possibly create your own. It is a way to loosely couple classes / class dependencies and make code more reusable and durable.

equality check between CharSequence and String objects with possible null values in java

As far as I understand your question, it is this:
You have two objects, and you want to see if they're equal.

What we'd WANT to do is to use String.equalsIgnoreCase(). It's literally precisely what you want.
If the CharSequence object is not null, it's pretty easy, because CharSequence.toString() returns a string with the exact same characters in the exact same order.

charSequence.toString().equalsIgnoreCase(otherString);

Unfortunately this doesn't work. If the charsequence is null, then this throws a NullPointerException. So we need to see if the charsequence is null, and proceed from there.

public boolean compareCSAndString(CharSequence cs, String string) {
if(cs == null) {
// If both are null, then they're equal
return string == null;
}
else {
return cs.toString().equalsIgnoreCase(string);
}
}

This ticks all the boxes:

  • It's case insensitive
  • It handles null values
  • It is clean and easy to read (no nested ifs)

When to use CharSequence in an API

CharSequence is rarely used in general purpose libraries. It should usually be used when your main use case is string handling (manipulation, parsing, ...).

Generally speaking you can do anything with a CharSequence that you could do with a String (trivially, since you can convert every CharSequence into a String). But there's one important difference: A CharSequence is not guaranteed to be immutable! Whenever you handle a String and inspect it at two different points in time, you can be sure that it will have the same value every time.

But for a CharSequence that's not necessarily true. For example someone could pass a StringBuilder into your method and modify it while you do something with it, which can break a lot of sane code.

Consider this pseudo-code:

public Object frobnicate(CharSequence something) {
Object o = getFromCache(something);
if (o == null) {
o = computeValue(something);
putIntoCache(o, something);
}
return o;
}

This looks harmless enough and if you'd had used String here it would mostly work (except maybe that the value might be calculated twice). But if something is a CharSequence then its content could change between the getFromCache call and the computeValue call. Or worse: between the computeValue call and the putIntoCache call!

Therefore: only accept CharSequence if there are big advantages and you know the drawbacks.

If you accept CharSequence you should document how your API handles mutable CharSequence objects. For example: "Modifying an argument while the method executes results in undefined behaviour."



Related Topics



Leave a reply



Submit