Search code examples
javaexceptionindexoutofboundsexceptionrange-checking

Is it OK to use exceptions to check for array boundaries?


I want to check whether the given coordinates are withing an array or not.

public boolean checkBounds(int x, int y) {
    try {
        Object val = array[x][y];
        return true;
    } catch (ArrayIndexOutOfBoundsException e) {
        return false;
    }
}

Can I do it like that? Is it an efficient way to do it?


Solution

  • What happens when we use exceptions to perform boundary checks?

    Using exceptions for handling operations like null checking, bounds checking, file existance checking introduces a lot of overhead whenever the exception is thrown.

    What you would have done if you simply checked the bounds:

    • check the size of an array against 0 and against the
    • return result

    What you actually are doing when using exception-based checking:

    • check the bounds of the array
    • initiate java exceptions mechanism (with all its overhead)
    • create a new Exception object
    • dump entire stack trace
    • fill the newly created object with all stack data
    • catch the exception
    • return the result

    Performance comparison

    With this simple test program, I have measured the speed of both types of array boundary checks.

    public class BoundsCheckTest {
    
        final static int[] array = new int[1];
        final static Random gen = new Random();
    
        public static void main(String[] args){
    
            boolean ret = false;
            int tries = 100000000;
            long timestart = System.nanoTime();
    
            for (int a=0; a< tries; a++) {
                ret = method1();
            }
            long timeend1 = System.nanoTime();
            System.out.println();
    
            for (int a=0; a< tries; a++) {
                ret = metod2();
            }
            long timeend2 = System.nanoTime();
            System.out.println();
    
    
            long t1 = timeend1-timestart;
            long t2 = timeend2-timeend1;
            System.out.println("\ntime 1=["+t1+"]\n     2=["+t2+"]"+
                     "\ndiff=["+Math.abs(t1-t2)+"] percent diff=["+(100d*t2/t1-100)+"]");
    
        }
    
        private static boolean metod2() {
            try {
                int val = array[gen.nextInt(2)];
                return true;
            } catch (Exception e) {
                return false;
            }
        }
    
        private static boolean method1() {
            return array.length < gen.nextInt(2);
        }
    
    }
    

    The results:

    JDK 7, eclipse Run as mode:

    time check=[911620628]
           exc=[1192569638]
    diff=[280949010] percent diff=[30.818632375220886]
    

    JDK 7, eclipse Debug mode:

    time check=[931243924]
           exc=[651480777121]
    diff=[650549533197] percent diff=[69858.12378809143]
    

    The speed loss with debugging disabled is not very significant, though it is visible: code without exceptions is about 30% faster (for roughly 50% of false returns). The speed loss in debug mode is astonishing. The exception-based code runs about 700 times slower than the normal straight-up array size check.

    Philosophy of exceptions

    The general idea behind exceptions is to allow a way to handle exceptiona conditions. In this case, there is no exceptional condition at all - the range check is just a normal part of code. For that reason alone the exception should not be used in this situation.