```
public class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
int m, n;
if ((m = matrix.length) == 0 || (n = matrix[0].length) == 0) {
return new ArrayList<>();
}
List<Integer> order = new ArrayList<>();
// bounds of top, right, bottom and left (in spiral order)
int[] bounds = new int[]{0, n - 1, m - 1, 0};
// directions: 0 for right, 1 for down, 2 for left and 3 for up
int direction = 0;
while (bounds[0] <= bounds[2] && bounds[1] >= bounds[3]) {
// start and end bounds are stored in bounds[last direction] and bounds[next direction], respectively.
int start = bounds[(direction + 4 - 1) % 4];
int end = bounds[(direction + 4 + 1) % 4];
while (true) {
if (direction % 2 == 0) {
order.add(matrix[bounds[direction]][start]);
} else {
order.add(matrix[start][bounds[direction]]);
}
if (start == end) {
break;
}
start += start > end ? -1 : 1;
}
// update bound
bounds[direction] += direction == 0 || direction == 3 ? 1 : -1;
// turn direction
direction = (direction + 1) % 4;
}
return order;
}
}
```