Is it OK to use exceptions to check for array boundaries?
Asked Answered
S

1

6

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?

Soninlaw answered 18/9, 2013 at 12:50 Comment(2)
This reminds me of item 57 in "Effective Java": Use exceptions only for exceptional conditions. There's an example which looks pretty much like yours ;-)Layoff
Before casting negative votes on this question please note that this is a self-answered question.Soninlaw
S
13

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.

Soninlaw answered 18/9, 2013 at 12:50 Comment(3)
“The exception-based code runs about 700 times faster than the normal straight-up array size check” Why are you reversing your statement at this point? The exception-based code is still slower.Incurvate
what about a use case, where the exception occurs once in say 1 million accesses ?Isogamete
EDIT: tested that (very rare exception scenario, like 1:500.000) => try catch is significantly faster compared to bounds check, once JIT kicks in difference is not that big anymoreIsogamete

© 2022 - 2024 — McMap. All rights reserved.