The relevant code of substring is:
1965 int subLen = endIndex - beginIndex;
1966 if (subLen < 0) {
1967 throw new StringIndexOutOfBoundsException(subLen);
1968 }
If you see -4 in the exception's message, this means endIndex - beginIndex == -4.
Obviously, endIndex should be larger than or equal to beginIndex, so that the difference won't be negative.
Looking at the full method (this version of the code seems to match your version, based on the line number - 1967 - in which the exception was thrown):
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
you can see that you would have gotten -1 in the error message if beginIndex was -1.
But if beginIndex is non-negative, and endIndex is not too large, the number you get in the exception's message is endIndex - beginIndex.