Difference Between Array and ArrayList in Java
An array is a fixed-size, built-in language structure that stores elements of one type, including primitives, in consecutive memory. An ArrayList is a class from the Collections Framework that wraps an array and grows automatically, offering methods to add, remove, search and sort elements, but it stores only objects.
Both give fast access by index. The choice mostly depends on whether the size is fixed and whether you need primitives or the convenience of the List API.
1. Comparison Table
| Aspect | Array | ArrayList |
|---|---|---|
| Size | Fixed when created | Dynamic; grows by about 50% when full |
| Element types | Primitives and objects | Objects only (primitives are autoboxed) |
| Length / size | arr.length (field) | list.size() (method) |
| Access syntax | arr[i] | list.get(i), list.set(i, x) |
| Adding / removing | Not possible; create a new array | add, remove, insert at any position |
| Type safety | Checked at run time (ArrayStoreException) | Checked at compile time with generics |
| Dimensions | Multidimensional supported directly | One-dimensional (nest lists for more) |
| Performance | Slightly faster, less memory, no boxing | Small overhead; boxing for primitives |
| Utility methods | Via java.util.Arrays | Built in, plus Collections and streams |
| Part of | Java language | Collections Framework (java.util) |
2. Side-by-Side Example
import java.util.*;
public class ArrayVsArrayList {
public static void main(String[] args) {
// Array: fixed size, can hold primitives, length field
int[] scores = new int[3];
scores[0] = 90; scores[1] = 85; scores[2] = 77;
System.out.println("array : " + Arrays.toString(scores) + ", length = " + scores.length);
try {
scores[3] = 60; // no room to grow
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("array grow : " + e.getClass().getSimpleName());
}
// ArrayList: resizable, objects only (autoboxing), size() method, rich API
List<Integer> list = new ArrayList<>(List.of(90, 85, 77));
list.add(60); // grows automatically
list.remove(Integer.valueOf(85)); // remove by value
list.add(1, 99); // insert in the middle
System.out.println("ArrayList : " + list + ", size = " + list.size());
System.out.println("contains 77 : " + list.contains(77) + ", indexOf 60: " + list.indexOf(60));
Collections.sort(list);
System.out.println("sorted : " + list);
}
}
array : [90, 85, 77], length = 3 array grow : ArrayIndexOutOfBoundsException ArrayList : [90, 99, 77, 60], size = 4 contains 77 : true, indexOf 60: 3 sorted : [60, 77, 90, 99]
The array cannot hold a fourth score, while the list grows, inserts in the middle and removes by value. Note list.remove(Integer.valueOf(85)): calling remove(85) would remove the element at index 85.
3. Converting Between Them
import java.util.*;
public class ConvertBetween {
public static void main(String[] args) {
String[] arr = {"java", "spring", "kafka"};
List<String> list = new ArrayList<>(Arrays.asList(arr)); // array -> ArrayList
list.add("docker");
System.out.println("to list : " + list);
String[] back = list.toArray(new String[0]); // ArrayList -> array
System.out.println("to array : " + Arrays.toString(back) + " (" + back.length + ")");
int[] nums = {3, 1, 2};
List<Integer> boxed = new ArrayList<>(Arrays.stream(nums).boxed().toList()); // int[] -> List<Integer>
int[] unboxed = boxed.stream().mapToInt(Integer::intValue).toArray(); // List<Integer> -> int[]
System.out.println("boxed : " + boxed + ", unboxed: " + Arrays.toString(unboxed));
int[][] grid = new int[2][3]; // multidimensional arrays are natural
grid[1][2] = 5;
System.out.println("2D array : " + Arrays.deepToString(grid));
}
}
to list : [java, spring, kafka, docker] to array : [java, spring, kafka, docker] (4) boxed : [3, 1, 2], unboxed: [3, 1, 2] 2D array : [[0, 0, 0], [0, 0, 5]]
Arrays.asListreturns a fixed-size view; wrap it innew ArrayList<>(...)to get a growable list.list.toArray(new String[0])returns a correctly typed array.- For primitives, use streams:
boxed()andmapToInt.
4. Performance and Memory
- Both offer O(1) access by index;
ArrayList.getis essentially an array access plus a bounds check. - An
int[]stores 4 bytes per element; anArrayList<Integer>stores a reference plus anIntegerobject for each value, using several times more memory. - Appending to an
ArrayListis amortised O(1), but each growth step copies the array. Pre-size it withnew ArrayList<>(capacity)when you know the count. - Inserting or removing in the middle of an
ArrayListis O(n), because elements shift.
5. When to Use Which
| Use an array when… | Use an ArrayList when… |
|---|---|
| The size is fixed and known | The number of elements changes |
| You store many primitives and performance or memory matters | You need add, remove, contains, sort and stream conveniences |
| You need multidimensional data (matrices, grids) | You pass data to APIs that expect List or Collection |
| Working with low-level APIs (bytes, I/O buffers) | Writing typical business code |
6. Summary
- Arrays have a fixed size and can hold primitives;
ArrayListresizes automatically and holds objects. - Use
lengthfor arrays andsize()for lists. - Arrays are leaner and faster for primitives;
ArrayListis more flexible and type-safe with generics. - Convert with
Arrays.asList,toArrayor streams.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is the main difference between an array and an ArrayList?
An array has a fixed size and can store primitives; an ArrayList grows dynamically and stores only objects.
Q2. Can an ArrayList store primitive types?
Not directly. Values are autoboxed into wrappers, such as Integer for int.
Q3. Which is faster, an array or an ArrayList?
Arrays are slightly faster and use less memory, especially for primitives. For most application code the difference is negligible.
Q4. How do I get the size of each?
Arrays use the length field; ArrayList uses the size() method.
Q5. Can the size of an array be changed?
No. Create a larger array and copy the elements, for example with Arrays.copyOf.
Q6. How does ArrayList grow?
When full, it allocates a new internal array about 1.5 times larger and copies the elements.
Q7. How do I convert an array to an ArrayList?
new ArrayList<>(Arrays.asList(array)), or Arrays.stream(intArray).boxed().toList() for primitives.
Q8. How do I convert an ArrayList to an array?
list.toArray(new String[0]), or list.stream().mapToInt(Integer::intValue).toArray() for int[].
Q9. Is ArrayList internally an array?
Yes. It is backed by an Object[] that it replaces with a bigger one as needed.
Q10. Can an array be multidimensional?
Yes, such as int[][]. With lists you nest them: List<List<Integer>>.
Q11. Which is type-safe?
Both, differently: arrays check element types at run time; ArrayList<T> checks at compile time through generics.
Q12. Can arrays and ArrayLists hold null?
Object arrays and ArrayLists can contain null; primitive arrays cannot.
Q13. How do I print each?
Arrays.toString(arr) for arrays; System.out.println(list) for lists, which have a readable toString.
Q14. How do I sort each?
Arrays.sort(arr) for arrays; Collections.sort(list) or list.sort(comparator) for lists.
Q15. Is ArrayList thread-safe?
No. Use Collections.synchronizedList or CopyOnWriteArrayList for shared access. Arrays are not thread-safe either.
Q16. Which uses more memory?
ArrayList, because it stores references to objects and may have unused capacity; a primitive array stores values directly.
Q17. What is ArrayStoreException?
An exception thrown when storing an object of the wrong type into an array, possible because arrays are covariant (Object[] o = new String[1]; o[0] = 1;).
Q18. Can I use for-each with both?
Yes. The enhanced for loop works with arrays and with any Iterable such as ArrayList.
Q19. Should method parameters use arrays or lists?
Prefer List (or Collection) in most APIs for flexibility, and arrays for varargs or performance-critical primitive data.
Q20. What is the default capacity of an ArrayList?
10, allocated lazily when the first element is added to a list created with the no-argument constructor.