How to Sort an Array in Ascending Order in Java
Sorting is one of the most foundational operations in computer science, and Java gives you two very different paths to achieve it: writing the algorithm yourself from scratch (essential for learning and interviews), or calling the built-in, highly optimized Arrays.sort() method (essential for production code). This guide covers both, plus the modern stream-based approach, so you understand not just how to sort but why each method exists.
Problem Statement
Given an unsorted array like {5, 2, 9, 1, 5, 6}, the goal is to rearrange its elements so they appear in non-decreasing order:
{1, 2, 5, 5, 6, 9}
Method 1: Bubble Sort (Manual Implementation)
Bubble sort is the classic teaching algorithm for sorting, valued for how clearly it demonstrates the core idea of comparison-and-swap:
public class BubbleSortAscending {
public static void main(String[] args) {
int[] numbers = {5, 2, 9, 1, 5, 6};
for (int i = 0; i < numbers.length - 1; i++) {
for (int j = 0; j < numbers.length - 1 - i; j++) {
if (numbers[j] > numbers[j + 1]) {
int temp = numbers[j];
numbers[j] = numbers[j + 1];
numbers[j + 1] = temp;
}
}
}
System.out.println(java.util.Arrays.toString(numbers));
}
}
Method 2: Arrays.sort() (Built-in, Recommended for Production)
import java.util.Arrays;
int[] numbers = {5, 2, 9, 1, 5, 6};
Arrays.sort(numbers);
System.out.println(Arrays.toString(numbers)); // [1, 2, 5, 5, 6, 9]
Java's built-in Arrays.sort() for primitive arrays uses a highly tuned Dual-Pivot Quicksort, offering O(n log n) average-case performance—dramatically faster than bubble sort's O(n²) for large arrays.
Method 3: Java Streams
import java.util.Arrays;
int[] sorted = Arrays.stream(numbers)
.sorted()
.toArray();
This produces a new sorted array without modifying the original—useful when you need to preserve the original order elsewhere in your program.
Step-by-Step Bubble Sort Walkthrough
Bubble sort works by repeatedly stepping through the array, comparing adjacent elements, and swapping them if they're in the wrong order. After each full pass, the largest remaining unsorted element "bubbles up" to its correct final position at the end of the array.
Outer Loop (i)
Controls how many full passes are made. After each pass, one more element at the end is guaranteed to be in its final sorted position, so the inner loop can safely shrink.
Inner Loop (j)
Compares each pair of adjacent elements (numbers[j] and numbers[j + 1]), swapping them if the left one is bigger than the right one.
The Swap
Uses a temporary variable temp to hold one value momentarily while the exchange happens, since directly assigning numbers[j] = numbers[j + 1] would overwrite the original value before it could be moved into numbers[j + 1].
First Pass Example
Tracing through {5, 2, 9, 1, 5, 6}:
- Compare
5, 2→ swap →{2, 5, 9, 1, 5, 6} - Compare
5, 9→ no swap - Compare
9, 1→ swap →{2, 5, 1, 9, 5, 6} - Compare
9, 5→ swap →{2, 5, 1, 5, 9, 6} - Compare
9, 6→ swap →{2, 5, 1, 5, 6, 9}
After just one pass, the largest value (9) has "bubbled" to the end.
Internal Working (Memory View)
Bubble sort operates entirely in-place, meaning it rearranges elements directly within the original array's heap memory rather than allocating a new array. Only a single extra int temp variable is needed on the stack during each swap, giving bubble sort O(1) extra space complexity, despite its poor O(n²) time complexity.
Arrays.sort() for primitives also sorts in-place, but its internal Dual-Pivot Quicksort implementation uses a much more sophisticated partitioning strategy, achieving far better average-case performance while still modifying the array directly.
Real-Life Analogy
Picture a line of people of different heights, and you're asked to arrange them from shortest to tallest by repeatedly comparing two neighbors and swapping them if they're in the wrong order. After walking down the line once, the tallest person has been pushed to the very end (like a bubble rising to the surface). Repeat this walk enough times, and eventually everyone is in order—that's bubble sort in a nutshell.
Best Practices
- Use
Arrays.sort()for real production code because it is heavily optimized and battle-tested. - Implement bubble sort (or another simple sort) manually only for learning purposes or when explicitly asked in an interview.
- Use
Arrays.stream(arr).sorted().toArray()when you need a sorted copy without modifying the original array. - For sorting objects by custom criteria, use
Arrays.sort(objectArray, Comparator...)rather than reinventing comparison logic manually.
Common Mistakes
- Forgetting the temporary variable during a swap, which overwrites data instead of exchanging it.
- Using incorrect inner loop bounds, such as not shrinking the inner loop range as passes complete, leading to redundant comparisons.
- Using bubble sort for large datasets in production, where its O(n²) complexity becomes a significant performance bottleneck.
- Forgetting that
Arrays.sort()modifies the array in-place, unexpectedly losing the original unsorted order.
Expert Tips
- Bubble sort can be optimized with an early-exit flag. If no swaps occur during a full pass, the array is already sorted, and the algorithm can stop early.
- For sorting arrays of objects (not primitives),
Arrays.sort()uses a stable, modified merge sort called TimSort, which guarantees O(n log n) worst-case performance and preserves the relative order of equal elements. - If you need descending order using
Arrays.sort(), you must either sort in ascending order and reverse the array manually, or useArrays.sort(objectArray, Collections.reverseOrder())for object arrays. This approach does not work directly with primitive arrays.
Comparison Table
| Algorithm/Method | Time Complexity | Space Complexity | Stable? | Recommended Use |
|---|---|---|---|---|
| Bubble Sort (manual) | O(n²) | O(1) | Yes | Learning and teaching |
| Arrays.sort() (primitives) | O(n log n) average | O(log n) | N/A | Production code |
| Arrays.sort() (objects) | O(n log n) | O(n) | Yes (TimSort) | Production code with objects |
Streams .sorted() |
O(n log n) | O(n) | Yes | Functional programming and immutable operations |
Frequently Asked Questions
What is the fastest way to sort an array in Java?
Arrays.sort() is the fastest and recommended approach for most applications because it uses highly optimized sorting algorithms internally.
Why should I learn bubble sort if Arrays.sort() already exists?
Bubble sort helps you understand the basic comparison-and-swap concept behind sorting algorithms and is frequently discussed in coding interviews.
Does Arrays.sort() modify the original array?
Yes. It sorts the original array in-place. If you need to preserve the original array, use Arrays.stream(arr).sorted().toArray().
What is the time complexity of bubble sort?
Bubble sort has a time complexity of O(n²) in both the average and worst cases, making it unsuitable for large datasets.
Can I sort an array of Strings using Arrays.sort()?
Yes. Arrays.sort(stringArray) sorts strings lexicographically according to their natural ordering.
Is bubble sort a stable sorting algorithm?
Yes. Bubble sort is stable because equal elements retain their original relative order after sorting.
How do I sort only a portion of an array?
Use Arrays.sort(array, fromIndex, toIndex) to sort only a specified range of the array.
Which sorting algorithm does Arrays.sort() use internally?
For primitive arrays, Java uses a Dual-Pivot Quicksort. For object arrays, it uses TimSort to guarantee stable sorting.