# Java Lists

## Create list

**ArrayList** - better performance for read operations but worse for add operations:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> emptyList = new ArrayList<>();
List<String> languages = new ArrayList<>(Arrays.asList("English", "German", "French"));
List<String> languages2 = new ArrayList<>(){{ add("English"); add("French"); add("German"); }};
```

**LinkedList** - better performance for add operations but worse for read operations:

```java
import java.util.List;
import java.util.LinkedList;
import java.util.Arrays;

List<String> emptyList = new LinkedList<>();
List<String> languages = new LinkedList<>(Arrays.asList("English", "German", "French"));
List<String> languages2 = new LinkedList<>(){{ add("English"); add("French"); add("German"); }};
```

**Immutable List** - from Java 9:

```java
import java.util.List;
import java.util.Collections;
import java.util.Arrays;

List<String> languages = List.of("English", "German", "French");
List<String> languages2 = Collections.unmodifiableList(Arrays.asList("English", "German", "French"));
```

**Singleton List** - immutable, must contain exactly one element - [lightweight, useful for API methods requiring List arguments](https://zetcode.com/java/collections-singletonlist/):

```java
import java.util.List;
import java.util.Collections;

List<String> myFavoriteColor = Collections.singletonList("blue");
```

The rest of the cheatsheet will use ArrayList, but the operations are also applicable to LinkedList, and operations which don't change the (original) List also work on immutable and singleton List, unless indicated otherwise.

## Add item

To the end of List:

```java
import java.util.List;
import java.util.ArrayList;

List<String> colors = new ArrayList<>();
colors.add("red");
```

To a specific index:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
colors.add(1, "purple"); // "red", "purple", "green", "blue"
```

LinkedList implements Queue and Deque, thus it can also supports addition operations provided by those interfaces. See [Stacks and Queues Cheatsheet](https://fosseryweb.codeberg.page/@beta/cheatsheets/java/queue-stack-deque.html).

## Add all items of another List (or any Collection)

To the end of List:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
List<String> colors2 = new ArrayList<>(Arrays.asList("purple", "yellow", "orange"));
colors.addAll(colors2); // "red", "green", "blue", "purple", "yellow", "orange"
```

To a specific index:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
List<String> colors2 = new ArrayList<>(Arrays.asList("purple", "yellow", "orange"));
colors.addAll(1, colors2); // "red", "purple", "yellow", "orange", "green", "blue"
```

## Read item

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
String firstColor = colors.get(0); // "red"
```

LinkedList implements Queue and Deque, thus it can also supports read operations provided by those interfaces. See [Stacks and Queues Cheatsheet](https://fosseryweb.codeberg.page/@beta/cheatsheets/java/queue-stack-deque.html).

## Get size of List

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
int numberOfColors = colors.size(); // 3
```

## Check if List contains an item

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
boolean containsRed = colors.contains("red"); // true
```

## Check if List contains all items of another List (or any Collection)

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
List<String> colors2 = new ArrayList<>(Arrays.asList("red", "orange"));
boolean containsRedAndOrange = colors.containsAll(colors2); // false
```

## Get index of an item

Find first occurrence:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "red", "blue", "red"));
int firstRed = colors.indexOf("red"); // 0
```

Find last occurrence:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "red", "blue", "red"));
int lastRed = colors.lastIndexOf("red"); // 4
```

## Check if List is identical to another List (or any Object)

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
List<String> colors2 = new ArrayList<>(Arrays.asList("red", "green", "blue"));
boolean isIdentical = colors.equals(colors2); // true
```

## Check if List is empty

```java
import java.util.List;
import java.util.ArrayList;

List<String> colors = new ArrayList<>();
boolean listEmpty = colors.isEmpty(); // true
```

## Update item

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
colors.set(2, "purple"); // "red", "green", "purple"
```

## Update all items based on a specified logic

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
colors.replaceAll(color -> color.toUpperCase()); // "RED", "GREEN", "BLUE"
```

## Remove item(s)

### Remove a single item

By value:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
colors.remove("green"); // also returns true value if the element was removed, false if it wasn't found
// `colors` will be "red", "blue"
```

By index:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
colors.remove(1); // also returns the removed element
// `colors` will be "red", "blue"
```

> **Warning:** int argument of remove() is always considered an index, even when it's called on an Integer List!

LinkedList implements Queue and Deque, thus it can also supports removal operations provided by those interfaces. See [Stacks and Queues Cheatsheet](https://fosseryweb.codeberg.page/@beta/cheatsheets/java/queue-stack-deque.html).

### Remove multiple items

Remove all items:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
colors.clear();
```

Remove all items of another List from the List:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue", "purple", "yellow", "orange"));
List<String> primaryColors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
colors.removeAll(primaryColors); // also returns true if at least one item was removed, otherwise false
// `colors` will be "purple", "yellow", "orange"
```

Remove all items from a List, except the items which are also present in another List:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue", "purple", "yellow", "orange"));
List<String> primaryColors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
colors.retainAll(primaryColors); // also returns true if at least one item was removed, otherwise false
// `colors` will be "red", "green", "blue"
```

Remove all items for which a condition is met:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue", "purple", "yellow", "orange"));
colors.removeIf(color -> color.length() < 5); // also returns true if at least one item was removed, otherwise false
// `colors` will be "green", "purple", "yellow", "orange"
```

## Sort items

Using Collections.sort():

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

List<String> languages = new ArrayList<>(Arrays.asList("HTML", "CSS", "JavaScript"));
Collections.sort(languages); // "CSS", "HTML", "JavaScript"
Collections.sort(languages, Collections.reverseOrder()); // "JavaScript", "HTML", "CSS"
```

Using sort() method of List:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

List<String> languages = new ArrayList<>(Arrays.asList("HTML", "CSS", "JavaScript"));
langauges.sort(null); // "CSS", "HTML", "JavaScript"
langauges.sort(Collections.reverseOrder()); // "JavaScript", "HTML", "CSS"
```

Using sorted() method of List stream - doesn't change original list:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.stream.Collectors;

List<String> languages = new ArrayList<>(Arrays.asList("HTML", "CSS", "JavaScript"));
List<String> sortedLanguages = languages.stream()
                                        .sorted()
                                        .collect(Collectors.toList());
// "CSS", "HTML", "JavaScript"
List<String> sortedLanguages2 = languages.stream()
                                         .sorted(Collections.reverseOrder())
                                         .collect(Collectors.toList());
// "JavaScript", "HTML", "CSS"
```

> **Warning:** none of the above methods can handle Strings with extended Latin letters (ö, ü, ó, ő, ú, ű, é, á, í, etc.) properly in all cases (they only consider the number and length of hyphens on a letter, so e.g. they incorrectly put ú before ő in ascending order, and ő before ú in descending order!

## Convert List

### To String

Using toString() method of List:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> languages = new ArrayList<>(Arrays.asList("HTML", "CSS", "JavaScript"));
String joinedLanguages = languages.toString(); // "[HTML, CSS, JavaScript]"
```

Using String.join() - delimiter can freely be chosen:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> languages = new ArrayList<>(Arrays.asList("HTML", "CSS", "JavaScript"));
String joinedLanguages = String.join(", ", languages); // "HTML, CSS, JavaScript"
```

### To array

To any primitive or object array:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<Integer> numbers = new ArrayList<>(Arrays.asList(21, 34, 45));
int[] numberArray = new int[numbers.size()];
for (int i = 0; i < numbers.size(); i++) {
  numberArray[i] = numbers.get(i); // auto-unboxing from Integer to int
}
```

To object array:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<Integer> ages = new ArrayList<>(Arrays.asList(21, 34, 45));
Integer[] ageArray = ages.toArray(new Integer[0]);
```

To int/double/long array:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<Integer> ages = new ArrayList<>(Arrays.asList(21, 34, 45));
int[] ageArray = ages.stream().mapToInt(Integer::intValue).toArray();
```

To char array:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<Character> letters = new ArrayList<>(Arrays.asList('a', 'b', 'c'));
char[] letterArray = numbers.stream()
                            .map(Character::charValue)
                            .collect(() -> new StringBuilder(),
                                     StringBuilder::append,
                                     StringBuilder::append)
                            .toString()
                            .toCharArray();
```

## Copy List

Shallow copy - element references remain the same:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

Person john = new Person("John Doe");
Person jane = new Person("Jane Doe");
List<Person> people = new ArrayList<>(Arrays.asList(john, jane));
List<Person> clonedPeople = new ArrayList<>(people);
john.setName("Johnny Doe");
// both `people` and `clonedPeople` become ["Johnny Doe", "Jane Doe"]

Person jonas = new Person("Jonas Doe");
people.set(0, jonas);
// `people` becomes ["Jonas Doe", "Jane Doe"]
// `clonedPeople` remains ["Johnny Doe", "Jane Doe"]

clonedPeople.set(1, jonas);
// `people` remains ["Jonas Doe", "Jane Doe"]
// `clonedPeople` becomes ["Johnny Doe", "Jonas Doe"]
```

Immutable copy:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

Person john = new Person("John Doe");
Person jane = new Person("Jane Doe");
List<Person> people = new ArrayList<>(Arrays.asList(john, jane));
List<Person> clonedPeople = Collections.unmodifiableList(people);
john.setName("Johnny Doe");
// both `people` and `clonedPeople` become ["Johnny Doe", "Jane Doe"]

Person jonas = new Person("Jonas Doe");
people.set(0, jonas);
// both `people` and `clonedPeople` become ["Jonas Doe", "Jane Doe"]

clonedPeople.set(1, jonas); // throws UnsupportedOperationException
```

Deep copy - elements also get copied, don't retain reference:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

Person john = new Person("John Doe");
Person jane = new Person("Jane Doe");
List<Person> people = new ArrayList<>(Arrays.asList(john, jane));
List<Person> clonedPeople = people.stream()
                                  .map(p -> new Person(p.getName()))
                                  .collect(Collectors.toList());
john.setName("Johnny Doe");
// `people` becomes ["Johnny Doe", "Jane Doe"]
// `clonedPeople` remains ["John Doe", "Jane Doe"]

Person jonas = new Person("Jonas Doe");
people.set(0, jonas);
// `people` becomes ["Jonas Doe", "Jane Doe"]
// `clonedPeople` remains ["John Doe", "Jane Doe"]

clonedPeople.set(1, jonas);
// `people` remains ["Jonas Doe", "Jane Doe"]
// `clonedPeople` becomes ["John Doe", "Jonas Doe"]
```

## Sublist

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue", "purple", "yellow", "orange"));
List<String> primaryColors = colors.subList(0, 3); // "red", "green", "blue"
```

## Iterate List

For loop:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
for (int i = 0; i < colors.size(); i++) {
  System.out.println(colors.get(i));
}
```

For-each loop (enhanced for loop):

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
for (String color : colors) {
  System.out.println(color);
}
```

While loop:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
int i = 0;
while (i < colors.size()) {
  System.out.println(colors.get(i));
  i++;
}
```

Iterator:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
Iterator<String> colorsIter = colors.iterator();
while (colorsIter.hasNext()) {
  String color = colorsIter.next();
  System.out.println(color);
}
```

ListIterator:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ListIterator;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
ListIterator<String> colorsIter = colors.listIterator();
while (colorsIter.hasNext()) {
  String color = colorsIter.next();
  System.out.println(color);
}
```

ListIterator from a start index:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ListIterator;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
ListIterator<String> colorsIter = colors.listIterator(1);
while (colorsIter.hasNext()) {
  String color = colorsIter.next();
  System.out.println(color);
}
// only "green" and "blue" will be printed
```

forEach() method of List stream:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
colors.stream().forEach(System.out::println);
```

forEach() method of List:

```java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
colors.forEach(System.out::println);
```
