# Java Array

## Create array, assign values

Create and assign in one step:

```java
int[] numArray = {10, 20, 30, 40};
```

Create, then assign values one-by-one:

```java
String[] namesArray = new String[3];
namesArray[0] = "Alice";
namesArray[1] = "Bob";
namesArray[2] = "Carol";
```

Fill array with identical elements:

```java
import java.util.Arrays;

int[] scores = new int[5];
Arrays.fill(scores, 0); // {0, 0, 0, 0, 0}
```

Copy, resize array:

```java
import java.util.Arrays;

int[] original = {1, 2, 3};
int[] expanded = Arrays.copyOf(original, 5); // {1, 2, 3, 0, 0}
```

## Get length of array

```java
char[] letters = {'a', 'b', 'c'};
int numberOfLetters = letters.length; // 3
```

## Read a specific element of array

```java
char[] letters = {'a', 'b', 'c'};
char thirdLetter = letters[2]; // 'c'
```

Alternative way - avoid ArrayIndexOutOfBoundsException if index doesn't exist:

```java
int[] numbers = {5, 10, 15};
int index = 4;
int value = (index >= 0 && index < numbers.length) ? numbers[index] : -1; // -1
```

## Search for a specific element in an array

```java
import java.util.Arrays;

String[] distros = {"Debian", "Arch", "Fedora"};
int archIndex = Arrays.binarySearch(distros, "Arch"); // 1
```

## Modify element

Modify a specific element:

```java
int[] numbers = {5, 10, 15};
numbers[1] = 8; // {5, 8, 15}
```

Modify all elements using a provided logic (e.g. add 1 to each):

```java
import java.util.Arrays;

int[] numbers = {5, 10, 15};
Arrays.setAll(numbers, i -> numbers[i] + 1); // {6, 11, 16}
```

## Delete an element

Set element to null (only works if array has object elements):

```java
String[] fruits = {"apple", "banana", "cherry"};
fruits[1] = null; // {"apple", null, "cherry"}
```

Create a copy of the array with a specific item removed:

```java
int[] src = {1, 2, 3, 4};
int removeAt = 1; // drop value 2
int[] trimmed = new int[src.length - 1];
// Copy `removeAt` number of elements from `src` starting at index 0,
// to `trimmed` starting at index 0
System.arraycopy(src, 0, trimmed, 0, removeAt);
// Copy `src.length - removeAt - 1` number of elements
// from `src` starting at index `removeAt + 1`,
// to `trimmed` starting at index `removeAt`
System.arraycopy(src, removeAt + 1, trimmed, removeAt, src.length - removeAt - 1);
// trimmed => {1,3,4}
```

## Convert array

To String:

```java
import java.util.Arrays;

String[] distros = {"Debian", "Arch", "Fedora"};
String distrosString = Arrays.toString(distros); // "[Debian, Arch, Fedora]"
```

To List:

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

String[] distros = {"Debian", "Arch", "Fedora"};
List<String> distrosList = Arrays.asList(distros);
```

## Sort array

Ascending order:

```java
import java.util.Arrays;

String[] distros = {"Debian", "Arch", "Fedora"};
Arrays.sort(distros);
// {"Arch", "Debian", "Fedora"}
```

Descending order - for object arrays:

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

String[] distros = {"Debian", "Arch", "Fedora"};
Arrays.sort(distros, Collections.reverseOrder());
// {"Fedora", "Debian", "Arch"}
```

Sorting primitive arrays in descending order requires some custom code, there's no direct way to do it.

## Copy array

### Shallow copy

Changing original array also affects the copied one.

Assigning array to another variable:

```java
String[] distros = {"Debian", "Arch", "Fedora"};
String[] distributions = distros;
distros[2] = "Gentoo";
// both `distros` and `distributions` become {"Debian", "Arch", "Gentoo"}
// because `distributions` is only a reference to `distros`, not another array!
```

### Deep copy

Changing original array doesn't affect the copied one.

Using for loop:

```java
String[] distros = {"Debian", "Arch", "Fedora"};
String[] distributions = new String[3];
for (int i = 0; i < distros.length; i++) {
  distributions[i] = distros[i];
}
distros[2] = "Gentoo";
// Only `distros` changes to {"Debian", "Arch", "Gentoo"},
// `distributions` remains {"Debian", "Arch", "Fedora"},
// because it's a completely separate array
```

Using clone() method of the array:

```java
String[] distros = {"Debian", "Arch", "Fedora"};
String[] distributions = distros.clone();
distros[2] = "Gentoo";
// `distros` will be {"Debian", "Arch", "Gentoo"}
// `distributions` will be {"Debian", "Arch", "Fedora"}
```

Using System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length):

```java
String[] distros = {"Debian", "Arch", "Gentoo"};
String[] distributions = new String[distros.length];
String[] hardDistros = new String[2];

// Copy all elements: Copy `distros.length` number of elements
// from `distros` starting at index 0,
// to `distributions` starting at index 0
System.arraycopy(distros, 0, distributions, 0, distros.length);

// Copy only 2 elements: Copy 2 elements
// from `distros` starting at index 1,
// to `hardDistros` starting at index 0
System.arraycopy(distros, 1, hardDistros, 0, 2);

// `distributions` will be {"Debian", "Arch", "Gentoo"}
// `hardDistros` will be {"Arch", "Gentoo"}
```

Using Arrays.copyOf(anytype\[\] original, int newLength):

```java
import java.util.Arrays;

String[] distros = {"Debian", "Arch", "Gentoo"};
String[] distrosWithManyForks = Arrays.copyOf(distros, 2);
String[] distrosExtended = Arrays.copyOf(distros, 5);
// `distrosWithManyForks` will be {"Debian", "Arch"}
// `distrosExtended` will be {"Debian", "Arch", "Gentoo", null, null}
```

Using Arrays.copyOfRange(anytype\[\] original, int from, int to):

```java
import java.util.Arrays;

String[] distros = {"Debian", "Arch", "Gentoo"};

// Copy all elements: Copy elements of `distros`
// between indices 0 and `distros.length`
String[] distributions = Arrays.copyOfRange(distros, 0, distros.length);

// Copy elements of `distros` between indices 1 and 3
String[] hardDistros = Arrays.copyOfRange(distros, 1, 3);

// `distributions` will be {"Debian", "Arch", "Gentoo"}
// `hardDistros` will be {"Arch", "Gentoo"}
```

## Iterate over array

For loop:

```java
int[] numbers = {21, 34, 45};
for (int i = 0; i < numbers.length; i++) {
  System.out.println(numbers[i]);
}
```

For-each loop (enhanced for loop):

```java
int[] numbers = {21, 34, 45};
for (int number : numbers) {
  System.out.println(number);
}
```

While loop:

```java
int[] numbers = {21, 34, 45};
int i = 0;
while (i < numbers.length) {
  System.out.println(numbers[i]);
  i++;
}
```

Iterator - only works with arrays of non-primitive types:

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

Integer[] numbers = {21, 34, 45};
Iterator<Integer> iter = Arrays.asList(numbers).iterator();
while (iter.hasNext()) {
  System.out.println(iter.next());
}
```

Arrays.stream().forEach():

```java
import java.util.Arrays;

int[] numbers = {21, 34, 45};
Arrays.stream(numbers).forEach(System.out::println);
```

Arrays.asList().forEach() - only works with arrays of non-primitive types:

```java
import java.util.Arrays;

Integer[] numbers = {21, 34, 45};
Arrays.asList(numbers).forEach(System.out::println);
```

## Multidimensional array

```java
int[][] matrix = { {1, 2, 3}, {1, 2, 3} };
int matrixRowOneLength = matrix[0].length; // 3
int matrixRowOneElementTwo = matrix[0][1]; // 2

for (int row = 0; row < matrix.length; row++) {
  for (int col = 0; col < matrix[row].length; col++) {
    System.out.println("matrix[" + row + "][" + col + "] = " + matrix[row][col]);
  }
}

for (int[] row : matrix) {
  for (int number : row) {
    System.out.println(number);
  }
}
```
