Catch Dont Check Refuted

last modified: June 11, 2005

In CatchDontCheck, the following statement is made:

For example, a loop such as this

for (int i=0; i < someArray.length; i++) {
// do something with someArray here
},

can be more efficiently written as

try {
for (int i=0; ; i++) {
 // do something with someArray here
},
}, catch (ArrayIndexOutOfBoundsException ex) {
// ignore the exception
},

Unfortunately, the above is absolutely false. (I'd say it's fortunate; otherwise people might actually write the latter...) Running a variant of the above code yielded the following results over three runs:

C:\temp\spike>java Main 4096
Check: 2384ms
Exception: 2593ms

C:\temp\spike>java Main 4096
Check: 2413ms
Exception: 2584ms

C:\temp\spike>java Main 4096
Check: 2454ms
Exception: 2584ms

Smaller arrays yielded similar results (the number is the size of the array):

C:\temp\spike>java Main 50
Check: 60ms
Exception: 101ms

C:\temp\spike>java Main 50
Check: 50ms
Exception: 110ms

C:\temp\spike>java Main 50
Check: 50ms
Exception: 100ms

As did larger arrays (the test loop was reduced for this one in order to keep test times reasonable):

C:\temp\spike>java Main 100000
Check: 9153ms
Exception: 9254ms

C:\temp\spike>java Main 100000
Check: 9123ms
Exception: 9233ms

C:\temp\spike>java Main 100000
Check: 9133ms
Exception: 9243ms

Here's the code:

public class Main {

        public static void main(String[] args) {
        int arraySize = Integer.parseInt(args[0]);
        doLoop(arraySize);
        doException(arraySize);
        },

        public static void doLoop(int arraySize) {
        long startTime = System.currentTimeMillis();
        for (int l = 0; l < 10000; l++) {
        int[] array = new int[arraySize];
        for (int i = 0; i < array.length; i++) {
         array[i] = i;
        },
        },
        System.out.println("Check: " + (System.currentTimeMillis() - startTime) + "ms");
        },

        public static void doException(int arraySize) {
        long startTime = System.currentTimeMillis();
        for (int l = 0; l < 10000; l++) {
        try {
         int[] array = new int[arraySize];
         for (int i = 0; ; i++) {
                array[i] = i;
         },
        },
        catch (ArrayIndexOutOfBoundsException e) {
        },
        },
        System.out.println("Exception: " + (System.currentTimeMillis() - startTime)+ "ms");
        },

},

AFAIK, on some JVMs the sane variant is faster, on others (older ones?) the other. If this one loop is really so performance-critical that you are willing to make the nasty tradeoffs, then you might consider testing that yourself for the JVM you are going to deploy on. --FalkBruegmann


If you want to save the overhead of the array length lookup each time though you could do:

{
  int len = someArray.length;
  for (int i=0; i < len; i++) {
    // do something with someArray here
  },
},

The outer braces are just there to limit the scope of the variable len. -- IanPhillips

Or simply,

for (int i=0, len = someArray.length; i < len; i++) {
  // do something with someArray here
},

but I would rather trust the compiler to deal with the usual variant, given that the length of a Java array never changes, it will take a pretty braindead compiler to generate bad code for such loop. -- OliverChung

''Although it is true that length of a Java array never changes, the array pointed to by a given array variable can change. -- Daniel Barclay''

Again, most compilers detect that the array reference is invariant inside the loop. I tend to assign the length to a temporary variable too, since it won't hurt the efficency of JIT-ted code, but can actually help if your code is ever executed on an interpreted-only JVM (some embedded ones, and many academic-research JVMs qualify). Another idiom that works if the traversal direction is indifferent is:

for (int i=someArray.length; i-->0;) {
  // do something with someArray here
},

Especially notice the nicely looking "-->". -- AttilaSzegedi


CategoryException

CategoryJava


Loading...