1. Overview of List collection
Basically, a list collection stores elements by insertion order (either at the end or at a specific position in the list). A list maintains indices of its elements so it allows adding, retrieving, modifying, removing elements by an integer index (zero-based index; the first element is at 0-index, the second at 1-index, the third at 2-index, and so on). The following picture illustrates a list that stores some String elements:- ArrayList: An implementation that stores elements in a backing array. The array’s size will be automatically expanded if there isn’t enough room when adding new elements into the list. It’s possible to set the default size by specifying an initial capacity when creating a new ArrayList. Basically, an ArrayList offers constant time for the following operations: size, isEmpty, get, set, iterator, and listIterator; amortized constant time for the add operation; and linear time for other operations. Therefore, this implementation can be considered if we want fast, random access of the elements.
- LinkedList: An implementation that stores elements in a doubly-linked list data structure. It offers constant time for adding and removing elements at the end of the list; and linear time for operations at other positions in the list. Therefore, we can consider using a LinkedList if fast adding and removing elements at the end of the list is required.
- ArrayList quick example:1234567
List<String> listStrings =
new
ArrayList<String>();
listStrings.add(
"One"
);
listStrings.add(
"Two"
);
listStrings.add(
"Three"
);
listStrings.add(
"Four"
);
System.out.println(listStrings);
- LinkedList quick example:1234567
List<String> listStrings =
new
LinkedList<String>();
listStrings.add(
"Five"
);
listStrings.add(
"Six"
);
listStrings.add(
"Seven"
);
listStrings.add(
"Eight"
);
System.out.println(listStrings);
2. Creating a new list
It’s a good practice to declare a list instance with a generic type parameter, for example:
1
2
3
4
| List<Object> listAnything = new ArrayList<Object>(); List<String> listWords = new ArrayList<String>(); List<Integer> listNumbers = new ArrayList<Integer>(); List<String> linkedWords = new LinkedList<String>(); |
1
2
| List<Integer> listNumbers = new ArrayList<>(); List<String> linkedWords = new LinkedList<>(); |
1
| List<Integer> listNumbers = new ArrayList<>( 1000 ); |
1
2
3
| List<Integer> listNumberOne; // existing collection List<Integer> listNumberTwo = new ArrayList<>(listNumberOne); |
3. Basic operations: adding, retrieving, updating, removing elements
Adding elements
1
2
3
4
5
6
7
8
9
| List<String> listStrings = new ArrayList<String>(); // OK to add Strings: listStrings.add( "One" ); listStrings.add( "Two" ); listStrings.add( "Three" ); // But this will cause compile error listStrings.add( 123 ); |
1
2
3
4
5
6
| List<Number> linkedNumbers = new LinkedList<>(); linkedNumbers.add( new Integer( 123 )); linkedNumbers.add( new Float( 3.1415 )); linkedNumbers.add( new Double( 299.988 )); linkedNumbers.add( new Long( 67000 )); |
1
| listStrings.add( 1 , "Four" ); |
1
| listStrings.addAll(listWords); |
1
| listStrings.addAll( 2 , listWords); |
1
2
| String element = listStrings.get( 1 ); Number number = linkedNumbers.get( 3 ); |
1
2
3
4
5
6
| LinkedList<Number> numbers = new LinkedList<Number>(); // add elements to the list... // get the first and the last elements: Number first = numbers.getFirst(); Number last = numbers.getLast(); |
1
| listStrings.set( 2 , "Hi" ); |
- Remove the element at the 3rd position in the list:1
listStrings.remove(
2
);
- Remove the String element “Two” in the list:1
listStrings.remove(
"Two"
);
- Remove the element at the 3rd position in the list:
- It compares the specified object with the elements in the list using their equals() method, so if you use your own defined object type, make sure it implements the equals() method correctly.
- It only removes the first occurrence of the specified element in the list (i.e. if a list contains duplicate elements, only the first element is removed).
- It returns true if the list contained the specified element, or falseotherwise. Thus it’s recommended to check return value of this method, for example:12345
if
(listStrings.remove(
"Ten"
)) {
System.out.println(
"Removed"
);
}
else
{
System.out.println(
"There is no such element"
);
}
1
| listStrings.clear(); |
4. Iterating over a list
Basically, we can use the enhanced for loop to iterate through all elements in the list, as follows:
1
2
3
| for (String element : listStrings) { System.out.println(element); } |
1
2
3
4
5
| Iterator<String> iterator = listStrings.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } |
1
2
3
4
5
| Iterator<Number> iterator = linkedNumbers.listIterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } |
1
| listStrings.forEach(s -> System.out.println(s)); |
5. Searching for an element in a list
To search for position of a specific element in the list or to know if the list contains the specified element, the following methods can be used:- boolean contains(Object): returns true if the list contains the specified element.
- int indexOf(Object): returns the index of the first occurrence of the specified element in the list, or -1 if the element is not found.
- int lastIndexOf(Object): returns the index of the last occurrence of the specified element in the list, or -1 if the element is not found.
1
2
3
4
5
6
7
8
9
| if (listStrings.contains( "Hello" )) { System.out.println( "Found the element" ); } else { System.out.println( "There is no such element" ); } int firstIndex = linkedNumbers.indexOf( 1234 ); int lastIndex = listStrings.indexOf( "Hello" ); |
6. Sorting a list
The simplest way to sort out elements in a list is using the Collections.sort() static method which sorts the specified list into ascending order, based on the natural ordering of its elements. Here’s an example:
1
2
3
4
5
6
7
8
9
10
11
12
| List<String> listStrings = new ArrayList<String>(); listStrings.add( "D" ); listStrings.add( "C" ); listStrings.add( "E" ); listStrings.add( "A" ); listStrings.add( "B" ); System.out.println( "listStrings before sorting: " + listStrings); Collections.sort(listStrings); System.out.println( "listStrings after sorting: " + listStrings); |
1
2
| listStrings before sorting: [D, C, E, A, B] listStrings after sorting: [A, B, C, D, E] |
7. Copying one list into another
The Collections.copyList(dest, src) static method allows us to copy all elements from the source list into the destination one. Note that the destination list must be large enough to contain the entire source list. Here’s an example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| List<String> sourceList = new ArrayList<String>(); sourceList.add( "A" ); sourceList.add( "B" ); sourceList.add( "C" ); sourceList.add( "D" ); List<String> destList = new ArrayList<String>(); destList.add( "V" ); destList.add( "W" ); destList.add( "X" ); destList.add( "Y" ); destList.add( "Z" ); System.out.println( "destList before copy: " + destList); Collections.copy(destList, sourceList); System.out.println( "destList after copy: " + destList); |
1
2
| destList before copy: [V, W, X, Y, Z] destList after copy: [A, B, C, D, Z] |
8. Shuffling elements in a list
To randomly permute elements in a list, use the Collections.shuffle() static method. Here’s a quick example:
1
2
3
4
5
6
7
8
| List<Integer> numbers = new ArrayList<Integer>(); for ( int i = 0 ; i <= 10 ; i++) numbers.add(i); System.out.println( "List before shuffling: " + numbers); Collections.shuffle(numbers); System.out.println( "List after shuffling: " + numbers); |
1
2
| List before shuffling: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] List after shuffling: [6, 4, 5, 0, 1, 3, 9, 7, 2, 10, 8] |
9. Reversing elements in a list
To reverse order of elements in a list, use the Collections.reverse() static method. Here’s a quick example:
1
2
3
4
5
6
7
8
| List<Integer> numbers = new ArrayList<Integer>(); for ( int i = 0 ; i <= 10 ; i++) numbers.add(i); System.out.println( "List before reversing: " + numbers); Collections.reverse(numbers); System.out.println( "List after reversing: " + numbers); |
1
2
| List before reversing: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] List after reversing: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] |
10. Extracting a portion of a list
The subList(fromIndex, toIndex) allows us to get a portion of the list between the specified fromIndex (inclusive) andtoIndex (exclusive). Here’s an example:
1
2
3
4
5
| List<String> listNames = Arrays.asList( "Tom" , "John" , "Mary" , "Peter" , "David" , "Alice" ); System.out.println( "Original list: " + listNames); List<String> subList = listNames.subList( 2 , 5 ); System.out.println( "Sub list: " + subList); |
1
2
| Original list: [Tom, John, Mary, Peter, David, Alice] Sub list: [Mary, Peter, David] |
11. Converting between Lists and arrays
The Java Collection Framework allows us to easily convert between lists and arrays.
1
2
3
4
5
6
| List<String> listNames = Arrays.asList( "John" , "Peter" , "Tom" , "Mary" , "David" , "Sam" ); List<Integer> listNumbers = Arrays.asList( 1 , 3 , 5 , 7 , 9 , 2 , 4 , 6 , 8 ); System.out.println(listNames); System.out.println(listNumbers); |
1
2
| [John, Peter, Tom, Mary, David, Sam] [1, 3, 5, 7, 9, 2, 4, 6, 8] |
1
2
3
4
| List<String> listWords = new ArrayList<String>(); // add elements to the list Object[] arrayWords = listWords.toArray(); |
1
2
| String[] words = listWords.toArray( new String[ 0 ]); Integer[] numbers = listNumbers.toArray( new Integer[ 0 ]); |
12. Concurrent lists
By default, ArrayList and LinkedList are not thread-safe, so if you want to use them in concurrent context, you have to synchronize them externally using the Collections.synchronizedList() static method which returns a synchronized list that wraps the specified list. For example:
1
2
| List<Object> unsafeList = new ArrayList<Object>(); List<Object> safeList = Collections.synchronizedList(unsafeList); |
1
2
3
4
5
6
| synchronized (safeList) { Iterator<Object> it = safeList.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } |