Say if I want to sort a 2d array. (just reorder the rows, don't touch data within each row).
In following snippet: all 3 cases use the same Arrays.sort(T[] a, Comparator<? super T> c) method signature. Case (a) works fine. However, just by adding a if condition to the second argument, the inference of T changes. I couldn't comprehend why.
// array contains 3 tuples, sort it by the first element, then second element
int[][] array1 = new int[3][2];
array1[0] = new int[]{1,2};
array1[1] = new int[]{2,3};
array1[2] = new int[]{2,4};
// Case (a): compiles good, tuple is inferred as int[]
Arrays.sort(array1, Comparator.comparingInt(tuple -> tuple[0])); // Arrays.sort(T[] a, Comparator<? super T> c) correctly infers that T refers to int[]
// Case (b.1): compile error: incompatible types
// tuple is now inferred as Object, why?
Arrays.sort(array1,
(a1, a2) -> a1[0] == a2[0] ?
Comparator.comparingInt(tuple -> tuple[1]) : Comparator.comparingInt(tuple -> tuple[0]));
// Case (b.2): compile error: incompatible types
Arrays.sort(array1, Comparator.comparingInt(tuple -> tuple[0]).thenComparingInt(tuple -> tuple[1]));
// Case (c): if downcast tuple[0] to ((int[])tuple)[0], then (b) works fine.
Update:
- Enlightened by the comments, I soon realized that case (b.1) is actual not valid.
The lambda in (b.1) suppose to return an integer, not a comparator. E.g.
Arrays.sort(array1, (a1, a2) -> a1[0] == a2[0] ? 0 : 1); - In all other scenarios, I see
Comparator.<int[]>comparingInt(...)forces the inference correctly.