I just stumbled over a weird piece of code while refactoring. It looks like a candidate for factoring out the common part of both readString()-methods, only it seems to be impossible (it’s a freaking brain teaser for me):
private final StringBuilder readStringBuilder = new StringBuilder(128);
@Override
public String readString() throws IOException {
final int l = readInt();
if (l <= 0) {
switch (l) {
case -1: return null;
case 0: return "";
default: throw new IOException("invalid string length encoding: " + l);
}
}
readStringBuilder.setLength(0);
for (int i=0; i<l; ++i) {
readStringBuilder.append(readChar());
}
return readStringBuilder.toString();
}
@Override
public String readString(final StringCache cache) throws IOException {
final int l = readInt();
if (l <= 0) {
switch (l) {
case -1: return null;
case 0: return "";
default: throw new IOException("invalid string length encoding: " + l);
}
}
readStringBuilder.setLength(0);
for (int i=0; i<l; ++i) {
readStringBuilder.append(readChar());
}
return cache.get(readStringBuilder, readStringBuilder);
}
You see that both methods do almost the same, the method body is completely identical, except for the return statement. But since there are early termination exits, I can’t find a method signature that can take the main body – natuarally the returns type would be StringBuilder, only in the early termination case it would be String…
Any ideas how to factor the body into a separate method? (and take note that toString() on an empty StringBuilder does create a new String instead of returning a constant string literal)
EDIT: Definition of the StringCache is:
public interface StringCache {
public String get(final CharSequence charSeq, final CharSequence notFoundResult);
}
Looks like having
readStringBuilderas an instance field is some form of (premature?) optimization. Assuming this is the case, how about something like this: