Several methods called ensureCapacity exist in Xerces XML Parser packages. All of these seem to use ArrayIndexOutOfBoundsExceptions and NullPointerExceptions as normal program flow control, presumably to simplify the code. The example below comes from org.apache.xerces.util.StringPool. This is a poor scheme, as it would be far more efficient to simply perform a few checks and resize the array if needed. The increase in code complexity would be well worth the tradeoff. Also, this technique presents a problem when using Xerces in the IBM Visual Age for Java environment, which allows Exceptions to be caught by the debugger at the point which they are thrown. A developer looking to uncover a legitimate bug must wade through the multitude of exceptions thrown by the ensureCapacity methods before he or she finds the real source of the trouble. I hope you will consider refactoring this questionable implementation. Thanks, John O'Malley SBC Communications 314.235.3969 jo2847@sbc.com private boolean ensureCapacity(int chunk, int index) { try { return fOffset[chunk][index] == 0; } catch (ArrayIndexOutOfBoundsException ex) { if (index == 0) { String[][] newString = new String[chunk * 2][]; System.arraycopy(fString, 0, newString, 0, chunk); fString = newString; StringPool.StringProducer[][] newProducer = new StringPool.StringProducer[chunk * 2][]; System.arraycopy(fStringProducer, 0, newProducer, 0, chunk); fStringProducer = newProducer; int[][] newInt = new int[chunk * 2][]; System.arraycopy(fOffset, 0, newInt, 0, chunk); fOffset = newInt; newInt = new int[chunk * 2][]; System.arraycopy(fLength, 0, newInt, 0, chunk); fLength = newInt; newInt = new int[chunk * 2][]; System.arraycopy(fCharsOffset, 0, newInt, 0, chunk); fCharsOffset = newInt; } else { String[] newString = new String[index * 2]; System.arraycopy(fString[chunk], 0, newString, 0, index); fString[chunk] = newString; StringPool.StringProducer[] newProducer = new StringPool.StringProducer[index * 2]; System.arraycopy(fStringProducer[chunk], 0, newProducer, 0, index); fStringProducer[chunk] = newProducer; int[] newInt = new int[index * 2]; System.arraycopy(fOffset[chunk], 0, newInt, 0, index); fOffset[chunk] = newInt; newInt = new int[index * 2]; System.arraycopy(fLength[chunk], 0, newInt, 0, index); fLength[chunk] = newInt; newInt = new int[index * 2]; System.arraycopy(fCharsOffset[chunk], 0, newInt, 0, index); fCharsOffset[chunk] = newInt; return true; } } catch (NullPointerException ex) { } fString[chunk] = new String[INITIAL_CHUNK_SIZE]; fStringProducer[chunk] = new StringPool.StringProducer [INITIAL_CHUNK_SIZE]; fOffset[chunk] = new int[INITIAL_CHUNK_SIZE]; fLength[chunk] = new int[INITIAL_CHUNK_SIZE]; fCharsOffset[chunk] = new int[INITIAL_CHUNK_SIZE]; return true; }
I spoke with a JIT compiler developer on IBM's JDK's. He indicated that (at least on IBM's JDK's), there were cases in which using try-catch could be more efficient than using the logically equivalent if-else, if exceptions didn't get thrown very often. I've changed some instances in which if-else should be superior; in some cases in which try-catch would be better, I've instead tried to reduce the number of exceptions actually thrown, without increasing memory usage by too much. The changes aren't complete, so I won't mark the bug as "FIXED", but I hope what I've done thus far improves the situation. These changes are available in the Xerces-J 1.4.2.
.