The Collections class offers two standard static methods to sort a list:
sort(List<T> list) applicable to lists where T extends Comparable<? super T>, and
sort(List<T> list, Comparator<? super T> c) applicable to lists of any type.
Applying the former requires amending the class of list elements being sorted, which is not always possible. It might also be undesirable as although it provides the default sorting, other sorting orders may be required in different circumstances, or sorting is just a one off task.
Consider we have a task of sorting objects that are instances of the following class:
In order to use Collections.sort(List<User> list) we need to modify the User class to implement the Comparable interface. For example
publicclassUserimplementsComparable<User>{publicfinalLong id;publicfinalString username;publicUser(Long id,String username){this.id = id;this.username = username;}@OverridepublicStringtoString(){returnString.format("%s:%d", username, id);}@Override/** The natural ordering for 'User' objects is by the 'id' field. */publicintcompareTo(User o){return id.compareTo(o.id);}}
(Aside: many standard Java classes such as String, Long, Integer implement the Comparable interface. This makes lists of those elements sortable by default, and simplifies implementation of compare or compareTo in other classes.)
With the modification above, the we can easily sort a list of User objects based on the classes natural ordering. (In this case, we have defined that to be ordering based on id values). For example:
However, suppose that we wanted to sort User objects by name rather than by id. Alternatively, suppose that we had not been able to change the class to make it implement Comparable.
This is where the sort method with the Comparator argument is useful:
Collections.sort(users,newComparator<User>(){@Override/* Order two 'User' objects based on their names. */publicintcompare(User left,User right){return left.username.compareTo(right.username);}});System.out.print(users);// [A:33, B:25, C:28]
In Java 8 you can use a lambda instead of an anonymous class. The latter reduces to a one-liner:
Collect the String values into a List using Collectors.toList()
Creating a List
Giving your list a type
To create a list you need a type (any class, e.g. String(opens new window)). This is the type of your List. The List will only store objects of the specified type. For example:
List<String> strings;
Can store "string1", "hello world!", "goodbye", etc, but it can't store 9.2, however:
List<Double> doubles;
Can store 9.2, but not "hello world!".
Initialising your list
If you try to add something to the lists above you will get a NullPointerException, because strings and doubles both equal null!
There are two ways to initialise a list:
Option 1: Use a class that implements List
List is an interface, which means that does not have a constructor, rather methods that a class must override. ArrayList is the most commonly used List, though LinkedList is also common. So we initialise our list like this:
And our list would contain the two elements.
Now lets say we wanted to add "Program starting!" at the front of the list. We would do this like this:
strings.add(0,"Program starting!");
NOTE: The first element is 0.
Now, if we wanted to remove the "Goodbye world!" line, we could do it like this:
strings.remove("Goodbye world!");
And if we wanted to remove the first line (which in this case would be "Program starting!", we could do it like this:
strings.remove(0);
Note:
Adding and removing list elements modify the list, and this can lead to a `ConcurrentModificationException` if the list is being iterated concurrently.
Adding and removing elements can be `O(1)` or `O(N)` depending on the list class, the method used, and whether you are adding / removing an element at the start, the end, or in the middle of the list.
In order to retrieve an element of the list at a specified position you can use the E get(int index); method of the List API. For example:
strings.get(0);
will return the first element of the list.
You can replace any element at a specified position by using the set(int index, E element);. For example:
strings.set(0,"This is a replacement");
This will set the String "This is a replacement" as the first element of the list.
Note:
The set method will overwrite the element at the position 0. It will not add the new String at the position 0 and push the old one to the position 1.
The int indexOf(Object o); returns the position of the first occurrence of the object passed as argument. If there are no occurrences of the object in the list then the -1 value is returned. In continuation of the previous example if you call:
strings.indexOf("This is a replacement")
the 0 is expected to be returned as we set the String "This is a replacement" in the position 0 of our list.
In case where there are more than one occurrence in the list when int indexOf(Object o); is called then as mentioned the index of the first occurrence will be returned. By calling the int lastIndexOf(Object o) you can retrieve the index of the last occurrence in the list. So if we add another "This is a replacement":
strings.add("This is a replacement");
strings.lastIndexOf("This is a replacement");
This time the 1 will be returned and not the 0;
Iterating over elements in a list
For the example, lets say that we have a List of type String that contains four elements: "hello, ", "how ", "are ", "you?"
The best way to iterate over each element is by using a for-each loop:
publicvoidprintEachElement(List<String> list){for(String s : list){System.out.println(s);}}
Which would print:
hello,
how
are
you?
To print them all in the same line, you can use a StringBuilder:
publicvoidprintAsLine(List<String> list){StringBuilder builder =newStringBuilder();for(String s : list){
builder.append(s);}System.out.println(builder.toString());}
Creating, Adding and Removing element from an ArrayList
ArrayList is one of the inbuilt data structures in Java. It is a dynamic array (where the size of the data structure not needed to be declared first) for storing elements (Objects).
It extends AbstractList class and implements List interface. An ArrayList can contain duplicate elements where it maintains insertion order. It should be noted that the class ArrayList is non-synchronized, so care should be taken when handling concurrency with ArrayList. ArrayList allows random access because array works at the index basis. Manipulation is slow in ArrayList because of shifting that often occurs when an element is removed from the array list.
If we know the index of the element we want to replace, we can simply use set as follows:
strings.set(1,"Hi world");
If we don't know the index, we can search for it first. For example:
int pos = strings.indexOf("Goodbye world!");if(pos >=0){
strings.set(pos,"Goodbye cruel world!");}
Notes:
The set operation will not cause a ConcurrentModificationException.
The set operation is fast ( O(1) ) for ArrayList but slow ( O(N) ) for a LinkedList.
An indexOf search on an ArrayList or LinkedList is slow ( O(N) ).
Making a list unmodifiable
The Collections class provides a way to make a list unmodifiable:
List<String> ls =newArrayList<String>();List<String> unmodifiableList =Collections.unmodifiableList(ls);
If you want an unmodifiable list with one item you can use:
List<String> unmodifiableList =Collections.singletonList("Only string in the list");
Moving objects around in the list
The Collections class allows for you to move objects around in the list using various methods (ls is the List):
Reversing a list:
Collections.reverse(ls);
Rotating positions of elements in a list
The rotate method requires an integer argument. This is how many spots to move it along the line by. An example of this is below:
List<String> ls =newArrayList<String>();
ls.add(" how");
ls.add(" are");
ls.add(" you?");
ls.add("hello,");Collections.rotate(ls,1);for(String line : ls)System.out.print(line);System.out.println();
This will print "hello, how are you?"
Shuffling elements around in a list
Using the same list above, we can shuffle the elements in a list:
Collections.shuffle(ls);
We can also give it a java.util.Random object that it uses to randomly place objects in spots:
Random random =newRandom(12);Collections.shuffle(ls, random);
Syntax
ls.add(E element); //Adds an element
ls.remove(E element); //Removes an element
for(E element : ls){} //Iterates over each element
ls.toArray(new String[ls.length]); //Converts a List of Strings to an array of Strings
ls.get(int index); //Returns the element at the specified index.
ls.set(int index, E element); //Replaces the element at a specified position .
ls.isEmpty(); //Returns true if the array contains no elements, otherwise it returns false.
ls.indexOf(Object o); //Returns the index of the first location of the specified element o, or, if it is not present, returns -1.
ls.lastIndexOf(Object o); //Returns the index of the last location of the specified element o, or, if it is not present, returns -1.
ls.size(); //Returns the number of elements in the List.
Remarks
A list(opens new window) is an object which stores a an ordered collection of values. "Ordered" means the values are stored in a particular order--one item comes first, one comes second, and so on. The individual values are commonly called "elements". Java lists typically provide these features:
Lists may contain zero or more elements.
Lists may contain duplicate values. In other words, an element can be inserted into a list more than once.
Lists store their elements in a particular order, meaning one element comes first, one comes next, and so on.
Each element has an index indicating its position within the list. The first element has index 0, the next has index 1, and so on.
Lists permit inserting elements at the beginning, at the end, or at any index within the list.
Testing whether a list contains a particular value generally means examining each element in the list. This means that the time to perform this check is O(n)(opens new window), proportional to the size of the list.
Adding a value to a list at some point other than the end will move all of the following elements "down" or "to the right". In other words, adding an element at index n moves the element which used to be at index n to index n+1, and so on. For example:
List<String> list =newArrayList<>();
list.add("world");System.out.println(list.indexOf("world"));// Prints "0"// Inserting a new value at index 0 moves "world" to index 1
list.add(0,"Hello");System.out.println(list.indexOf("world"));// Prints "1"System.out.println(list.indexOf("Hello"));// Prints "0"