The point of
CharSequence is to provide a read-only view to a character sequence, and that's it. This interface does not provide any string manipulation or searching methods. Those are out of scope.
The Interface Segregation Principle suggests that clients of a type should not depend on methods they don't use. Therefore, an interface should declare only the minimal useful set. If a different use case needs different methods, there should be a different interface.
A client that only needs a character source likely does not need search methods.
It is of course possible to overdo this Principle and end up with a thousand little interfaces. That's not good either. So the
CharSequence interface doesn't just contain the minimal
length() methods, but also the deeply related convenience method
subSequence(). (A CharSequence can likely provide a view onto a subsequence without a string copy, which is why this should be an instance method). Specifying
toString() is OK because that method would be inherited anyway from
Object. The methods
codePoints() adapt a
CharSequence to a
Stream interface. Because these are default methods, they do not impose additional requirements for classes implementing
CharSequence type is useful when a method needs a generic character source without specifying a particular implementation (e.g. String vs. CharBuffer vs. StringBuilder). The
String#contains() methods are good examples of using
It is not necessary for
CharSequence to provide a
contains() method because it can be implemented externally. While Java does not have the convenience of C#'s extension methods, a static method is essentially the same thing. So instead of
boolean Editable#contains(CharSequence needle) you would have a
static boolean contains(CharSequence haystack, CharSequence needle). String search algorithms are a well-studied computer science topic. Different algorithms with different tradeoffs are readily available.