JAVA / LOOPS AND ARRAYS
Sorting, searching and filling with Arrays helpers
Use Arrays.fill, Arrays.sort and Arrays.binarySearch to set, order and look up array elements in place, and decode a failed search's negative result.
What you will learn
- Preset a whole array or a half-open [from, to) slice with Arrays.fill
- Reorder an array in place with Arrays.sort, which returns void, not a new array
- Turn a negative binarySearch result into an insertion index with -result - 1
- Spot the silent bug of calling binarySearch on data that is not sorted yet
Understanding Sorting, searching and filling with Arrays helpers
java.util.Arrays is a holder for static methods that operate on an array you pass in, and the three used most in everyday code are fill, sort and binarySearch. fill and sort return void: they rewrite the elements of the array object itself, so the variable you passed already sees the new contents and there is nothing to assign. Sorting in place is why no second copy of the data is needed, and also why any other variable referring to that same array suddenly sees a different order. Under the hood sort uses a dual-pivot quicksort for primitive arrays and a stable merge sort for object arrays, because two equal ints are indistinguishable while two equal-ranking objects may carry other fields whose original order you want preserved.
binarySearch is fast because it assumes the array is already sorted: it compares the middle element and discards half of the remaining range each time, so a million elements need about twenty comparisons. That assumption is never verified, so on unsorted data you get a number back just as quickly and the number is simply wrong. A miss returns -(insertionPoint) - 1 rather than a plain -1, offset by one so that "would belong at index 0" stays distinguishable from "found at index 0"; decode it with -result - 1 and test for success with result >= 0.
fill is the counterpart to sort: Arrays.fill(a, v) writes v into every slot, and Arrays.fill(a, from, to, v) writes only from index from up to but not including to. Since new int[n] already gives zeros and new String[n] gives nulls, fill earns its keep when you want a different starting value, or when you reuse one array across iterations instead of allocating a fresh one. One trap follows directly from how references work: on an object array, fill evaluates its value argument once and stores that single reference in every slot, so filling an int[3][] with new int[2] gives three views of one row rather than three rows.
import java.util.Arrays;
public class ArrayHelpers {
public static void main(String[] args) {
int[] scores = new int[6];
Arrays.fill(scores, 50);
System.out.println("filled: " + Arrays.toString(scores));
int[] raw = {42, 7, 91, 7, 15, 63};
Arrays.sort(raw);
System.out.println("sorted: " + Arrays.toString(raw));
System.out.println("find 63: " + Arrays.binarySearch(raw, 63));
System.out.println("find 40: " + Arrays.binarySearch(raw, 40));
Arrays.fill(raw, 1, 4, 0);
System.out.println("blanked: " + Arrays.toString(raw));
}
}Arrays.fill and Arrays.sort rewrite the array you hand them in place, and Arrays.binarySearch only returns a meaningful answer if that array is already sorted.
Worked examples
Searching before sorting
Shows that binarySearch on unsorted data returns a confident wrong answer instead of throwing.
import java.util.Arrays;
public class UnsortedSearch {
public static void main(String[] args) {
int[] data = {50, 10, 90, 30, 70};
System.out.println("contains 10? " + Arrays.binarySearch(data, 10));
Arrays.sort(data);
System.out.println("after sort: " + Arrays.toString(data));
System.out.println("contains 10? " + Arrays.binarySearch(data, 10));
}
}Example explained
Line 1The first search probes index 2 (90), concludes 10 must lie to the left, and never inspects index 1 where 10 actually sits.
Line 2It returns -1, which decodes as "absent, insert at index 0" - a wrong answer produced without any exception.
Line 3Arrays.sort(data) reorders that same array object, which is why data itself is different on the next line and no result is captured.
Line 4The identical call now returns 0 because the ordering that binarySearch assumed is finally true.
fill stores one reference, not copies
Demonstrates why filling an array of arrays with a single new row makes every row change together.
import java.util.Arrays;
public class FillReferences {
public static void main(String[] args) {
int[][] grid = new int[3][];
Arrays.fill(grid, new int[]{0, 0});
grid[0][1] = 9;
System.out.println("shared: " + Arrays.deepToString(grid));
int[][] safe = new int[3][2];
safe[0][1] = 9;
System.out.println("own: " + Arrays.deepToString(safe));
}
}Example explained
Line 1new int[3][] creates three row slots that are all null, so the rows must still come from somewhere.
Line 2Arrays.fill(grid, new int[]{0, 0}) evaluates the new array expression once and copies that one reference into all three slots.
Line 3grid[0][1] = 9 writes through the shared reference, so all three printed rows show the change.
Line 4new int[3][2] allocates a distinct two-element row per index, which is why only the first row of safe is affected.
Sorting strings uses code-unit order
Shows that Arrays.sort on a String[] follows String.compareTo, so case affects both the order and the search result.
import java.util.Arrays;
public class SortStrings {
public static void main(String[] args) {
String[] names = {"delta", "Echo", "alpha", "Bravo"};
Arrays.sort(names);
System.out.println("sorted: " + Arrays.toString(names));
System.out.println("find alpha: " + Arrays.binarySearch(names, "alpha"));
System.out.println("find Delta: " + Arrays.binarySearch(names, "Delta"));
}
}Example explained
Line 1Arrays.sort compares with String.compareTo, which compares UTF-16 code units, so B (66) and E (69) come before a (97) and d (100).
Line 2"alpha" is found at index 2, the position it holds in that code-unit ordering rather than the alphabetical position you might expect.
Line 3"Delta" is absent and belongs between "Bravo" and "Echo", so the insertion point is 1 and the method returns -(1) - 1 = -2.
Line 4The search only works because it uses the same ordering the sort used; mixing a custom comparator into one call and not the other breaks it.
Resetting a reused array between passes
Uses a range fill to clear part of a buffer instead of allocating a new array each round.
import java.util.Arrays;
public class ResetBuffer {
public static void main(String[] args) {
int[] buffer = new int[5];
for (int pass = 1; pass <= 2; pass++) {
Arrays.fill(buffer, pass * 10);
Arrays.fill(buffer, 3, 5, -1);
System.out.println("pass " + pass + ": " + Arrays.toString(buffer));
}
}
}Example explained
Line 1One array is allocated before the loop, and each pass overwrites it rather than creating a new one.
Line 2Arrays.fill(buffer, pass * 10) resets all five slots, wiping whatever the previous pass left behind.
Line 3Arrays.fill(buffer, 3, 5, -1) touches indices 3 and 4 only; toIndex 5 is excluded, which is also why 5 is legal here for a length-5 array.
Line 4Because fill mutates in place, the second pass starts from a fully known state, so no leftover values leak between passes.
Important notes
The from/to forms of fill and sort are half-open: fromIndex is included, toIndex is not, and fromIndex > toIndex throws IllegalArgumentException rather than quietly doing nothing.
When a key occurs several times, binarySearch may return any of the matching indices, not guaranteed the first, so step left from the hit if you need the earliest occurrence.
Common mistakes
Writing int[] sorted = Arrays.sort(raw); sort is void, so this fails to compile with "void cannot be converted to int[]" - and raw itself was already going to be reordered.
Testing a search with if (Arrays.binarySearch(a, k) != -1); only a key belonging at index 0 returns -1, so most genuine misses return -2, -3, -4 and wrongly pass the test. Compare with >= 0 instead.
Using a negative result as an index, as in a[Arrays.binarySearch(a, k)], which throws ArrayIndexOutOfBoundsException; convert it first with -result - 1.
Try it yourself
Change, predict, then run
In a browser editor create int[] temps = {18, 25, 7, 25, 31, 12}, sort it and print it with Arrays.toString, then print Arrays.binarySearch(temps, 20) next to the insertion index you compute as -result - 1. Confirm by eye that the insertion index is exactly the slot where 20 would keep the array sorted.
Open the Java workspaceCheck your understanding
An int[] holds {4, 9, 16, 25} and Arrays.binarySearch(a, 12) returns -3. What does -3 tell you?
- 12 is absent and would be inserted at index 3
- 12 was found at index 3, counted from the right
- 12 is absent and belongs at index 2, between 9 and 16
- The array was not sorted, so the search reported failure as -3
Show answer
A miss returns -(insertionPoint) - 1, so -3 means the insertion point is 2, putting 12 between 9 and 16. Reading the 3 directly as the index is the tempting error: the extra -1 exists so that a key belonging at index 0 returns -1 instead of 0, which would be indistinguishable from a real hit at index 0. binarySearch also never checks or reports whether the array was sorted.