In Java API methods like:
String.substring(int beginIndex, int endIndex)
String.subSequence(int beginIndex, int endIndex)
Th problem is that they didn't use the C/C++ syntax. I think the C syntax is more readable. Example if you want to take a substring with lenght 2 starting from the 3rd element of a List X, you write
X.subList(2,3).
In Java, if you want to take a sublist with ONLY the 3rd element of a List X, you need to write X.subList(2,3). That is really ugly, it seems that you are taking a sublist of 2 elements. On the other hand, X.subList(2,2) is an empty list - quite confusing.
int startIndex = calculateStartIndex();
int endIndex = calculateEndIndex();
X.subList(startIndex, endIndex);
Actually, if (startIndex == endIndex) → empty list.
Your question was: why, so here is my answer. What would happen if both parameters in Java were inclusive? you would have a problem when you need to take an empty list in case you calculate the second index. Because in most of cases the indexes are calculated and we don't write directly numbers in functions.
In order to have an empty list, unless you use a convenction (example: in case of negative or lower endIndex return empty list) - but such convenction could hide errors in coding (there is no difference if the second parameter is -1 or -100!):
int startIndex = calculateStartIndex(); // return 0
int endIndex = calculateEndIndex(); // return 0
X.subList(startIndex, endIndex); // this would return the 1st element of the list; how to get an empty list? Convenction needed!
// use a negative number to get empty list? And what if endIndex is negative because of a bug?
I this case, C wins; more readable in any case, it's a pity they changed that. But this is just an additional comment you can ingore.