I ran a JMH Benchmark with various solutions to the problem. I always consume the 2 offset indizes in a black hole. Here are the results:
Benchmark Mode Cnt Score Error Units
Offset2DBenchmark.doubleLoopWithIf thrpt 3 35425373,827 ± 4242716,439 ops/s
Offset2DBenchmark.loopOverFlatIndex thrpt 3 35929636,197 ± 935681,592 ops/s
Offset2DBenchmark.loopOverIndex thrpt 3 31438051,279 ± 3286314,668 ops/s
Offset2DBenchmark.unrolledLoop thrpt 3 40495297,238 ± 6423961,118 ops/s
Offset2DBenchmark.unrolledLoopWithLambda thrpt 3 27526581,417 ± 1712524,060 ops/s
doubleLoopWithIf = Nested Loops with If to filter 0,0 (TheSorm)
loopOverFlatIndex = Single loop with flattend indizes (Oleg)
loopOverIndex = Single Loop with 2d indizes (Zefick)
unrolledLoop = Completely Unrolled Loop
unrolledLoopWithLambda = Unrolled Loop consuming a Bifunction<Integer, Integer>
So, the unrolled loop is the fastest. Slightly slower are the double loop with the if statement and the flattened array proposed by Oleg. The 2D array by Zefick is even slower than your solution.
Just as a demo, here is what a tests looks like:
@Fork(value = 1)
@Warmup(iterations = 3)
@Measurement(iterations = 3)
@Benchmark
public void unrolledLoopWithLambda(Blackhole bh) {
outerOffsets((x, y) -> {
bh.consume(x);
bh.consume(y);
});
}
private void outerOffsets(BiConsumer<Integer, Integer> consumer) {
consumer.accept(-1, -1);
consumer.accept(-1, 0);
consumer.accept(-1, 1);
consumer.accept(0, -1);
consumer.accept(0, 1);
consumer.accept(1, -1);
consumer.accept(1, 0);
consumer.accept(1, 1);
}
So unless you want to unroll your loop manually, there is not much you can do to improve performance.
Unfortunately you didn't tell use what your code inside the loop looks like. If it is even a bit time consuming, the question how you loop might be neglectible...
But your title states that you want this as offsets for a 2d array. I suspect you might use this in a bigger loop over x and y. You might be able to gain more performance by using a 1d array and calculate the indices yourself.
Instead of:
array[x][y]
use
array[xy] with xy = x + y * xsize
You should be able to avoid doing the multiplication at all.
(This is the first time I ran a benchmark with JMH, so please tell me if I used it completely wrong...)