Array processing with loops
Arrays.fill sets every element, or a range of elements, to one value. In the range form the starting index is included and the ending index is excluded.
Whole-Collection Tasks in Practice
Once a program stores its data in an array, it often needs to do something to the whole collection at once. It may need to reset every slot, display the contents in a readable form, put the values in order, or check whether a particular value is present. Writing a loop by hand for each of these tasks is possible, but the Arrays class provides ready-made methods for them. This article follows four of those methods, which handle filling, text conversion, sorting, and searching.
The Arrays class has several versions of each method, with one version for each kind of array element type. The ideas stay the same from version to version, so learning the behavior of one version gives you most of what you need for the others. The examples below use int arrays, but the same reasoning applies to other element types.
What do you think happens?
You create int[] arr = new int[6]; (all six cells hold 0) and then call Arrays.fill(arr, 2, 5, 9). What is the value at index 5?
Reveal answer
0, because the ending index is excluded
The range form fills indexes 2, 3, and 4. The ending index 5 is not included, so that cell keeps its original value of 0.
Filling Every Cell with One Value
Arrays.fill is the method you reach for when every cell needs the same value, or when a stretch of cells needs to be reset. It comes in two forms. The first form takes an array and a value, and fills the entire array with that value. The second form takes an array, a starting index, an ending index, and a value, and fills only the cells in that range.
[0, 7, 7, 7, 0, 0]- new int[6] creates six cells, each starting at 0
- The range form starts at index 1 and stops before index 4
Arrays.toStringis used only to display the result
The whole-array form of fill has no index arguments. Calling Arrays.fill(scores, 3) would set every one of the six cells to 3. Use the whole-array form when the entire collection should be reset, and the range form when only part of it should change.
Reading the Half-Open Range
The range form deserves a careful reading. The starting index is included in the fill, but the ending index is not. The last cell that receives the value is the one just before the ending index. Many learners assume the range is closed on both ends, so this half-open style is worth committing to memory now. It matches the way Java ranges are described throughout the language.
Tracing a range fill step by step
Start with int[] arr = new int[6]; so every cell is 0. Then run Arrays.fill(arr, 1, 4, 7). Which cells change, and what does the array look like afterward?
- 1Identify the start
The starting index is 1, so index 1 is the first cell that receives the value 7.
- 2Identify the end
The ending index is 4. It is excluded, so the last cell filled is index 3.
- 3Apply the fill
Indexes 1, 2, and 3 are set to 7. Index 0 and indexes 4 and 5 are not part of the range, so they keep their value of 0.
- 4Check the count
The number of cells filled is the ending index minus the starting index, which is 4 minus 1, or 3 cells.
The array becomes [0, 7, 7, 7, 0, 0].
Converting an Array to Readable Text
Arrays.toString takes an array and returns a String that describes its contents. The String lists every value, separates the values with commas, and wraps the whole list in square brackets. Each value is converted to text in the same way it would appear if you printed it, so you do not need to write a loop that builds the text yourself.
[21, 19, 24]- The method returns a String, which can be printed or stored in a variable
- Commas separate the values and square brackets surround the list
Sorting an Array In Place
Arrays.sort rearranges the values in an array so that they end up in increasing order. The change happens in place, which means the same array object is altered rather than a new sorted copy being returned. Like the fill methods, sort has a whole-array form and a range form. The whole-array form sorts every element. The range form sorts only the elements from the starting index up to, but not including, the ending index. The same exclusive-end rule applies here as it did for fill.
int[] nums = {5, 2, 8, 1, 9};Index 0 holds 5, index 1 holds 2, index 2 holds 8, index 3 holds 1, index 4 holds 9
Arrays.sort(nums);
// nums now holds [1, 2, 5, 8, 9]Index 0 holds 1, index 1 holds 2, index 2 holds 5, index 3 holds 8, index 4 holds 9
[5, 1, 2, 8, 9]- The range 1 to 4 covers indexes 1, 2, and 3, holding 2, 8, and 1
- Those three values are sorted into 1, 2, 8
- Index 0 (value 5) and index 4 (value 9) are outside the range and stay in place
What Can Be Sorted
Sorting works on arrays of String values and arrays of the primitive types, with one exception: boolean arrays are not supported. Sorting also has a requirement that is easy to overlook. The method must be able to decide which of any two values is smaller. An array whose values cannot be compared in that way cannot be sorted by this method. The sorting algorithms themselves are covered later in the course, in the chapter that discusses algorithms.
Searching a Sorted Array with binarySearch
Arrays.binarySearch looks for a particular value in an array and reports where it is. It returns an int. If the value is present, the return value is the index of an element that holds it. The method has one firm requirement: the array must already be sorted in increasing order before you call it. The sort step and the search step therefore belong together. Sorting first is what makes the search meaningful. If you search an array that is not sorted, the method's description does not promise a useful answer, so you should not rely on the result.
3
-4- The value 8 is present at index 3, so the return value is that index
- The value 6 is absent, so the method returns a negative number
- The -4 is explained in the next section
Interpreting Negative Return Values
The source describes the absent-value case as returning -1. Java's documented behavior is more precise: when the key is missing, the method returns -(insertion point) - 1, where the insertion point is the index at which the key would be placed to keep the array sorted. The -1 result from the source is what you get when the insertion point is 0, meaning the key is smaller than every element. For any other missing key, the return value is more negative than -1.
return value = -(insertionPoint) - 1- 1Find the insertion point: the index where the missing key would go to keep the array sorted
- 2Negate it and subtract 1, so the result is always negative for a missing key
- 3To recover the insertion point from a negative result r, compute -r - 1
- 4Example: for the value 6 in {1, 2, 5, 8, 9}, the insertion point is 3, the return value is -4, and -(-4) - 1 gives back 3
Mistakes Beginners Make
Common mistake Assuming the fill range includes the ending index
What it looks likeArrays.fill(arr, 1, 4, 7) is expected to change index 4Why it failsThe starting index is included and the ending index is excluded, so the last filled cell is index 3.
Do this insteadCount the filled cells as the ending index minus the starting index.
Common mistake Expecting Arrays.sort to return a new array
What it looks likeint[] sorted = Arrays.sort(nums); with the intention of keeping nums unchangedWhy it failsSorting happens in place, so the original array is rearranged.
Do this insteadCall Arrays.sort(nums) and then use nums, or make a copy first if the original order must be kept.
Common mistake Calling binarySearch on an unsorted array
What it looks likeSearching {5, 2, 8, 1, 9} for 8 without sorting it first
Why it failsThe method requires the array to be sorted in increasing order, and the description does not promise a useful answer otherwise.
Do this insteadSort the array first, then search it.
Common mistake Using a negative search result as an index
What it looks likearr[Arrays.binarySearch(arr, 6)] when the key 6 is missingWhy it failsThe result is negative for a missing key, so it is not a valid index for the array.
Do this insteadCheck whether the result is negative first, then convert it with -(result) - 1 if you need the insertion point.
Common mistake Sorting a boolean array, which Arrays.sort does not support
Predict, Then Trace a Pipeline
These four methods are often used together. A common pattern is to fill or populate an array, sort it so the values are in order, search it with binarySearch, and print the contents with toString. When you read a program, identify which of these steps each call performs. That habit makes the flow of the program much easier to follow.
Start with int[] a = {4, 9, 1, 7}; Before running any code, predict the contents of a after Arrays.sort(a), then predict the return value of Arrays.binarySearch(a, 7) on the sorted array. Then predict the output of Arrays.toString(a) afterward, and check your answers by running the code.
Hints
- Sorting rearranges the values into increasing order, in place.
- Count the sorted positions starting at index 0 and find where 7 lands.
- The expected sorted contents are [1, 4, 7, 9].
Key Takeaways
Arrays.fillsets every element or a range of elements to one value; in the range form the starting index is included and the ending index is excluded.Arrays.toStringreturns a String listing the values separated by commas inside square brackets, without requiring a hand-written loop.Arrays.sortrearranges values into increasing order in place, with a range form that uses the same exclusive-end rule; boolean arrays are not supported.Arrays.binarySearchrequires a sorted array, returns the index of a found value, and returns a negative value for a missing key, which converts back to an insertion point via -(result) - 1.