В JDK 8 к классу Arrays было добавлено ряд методов, которые позволяют в параллельном режиме совершать обработку элементов массива. И хотя данные методы формально не входят в Stream API, но реализуют схожую функциональность, что и параллельные потоки:
parallelPrefix(): вычисляет некоторое значение для элементов массива (например, сумму элементов)
parallelSetAll(): устанавливает элементы массива с помощью лямбда-выражения
parallelSort(): сортирует массив
Используем метод parallelSetAll() для установки элементов массива:
import java.util.Arrays;
public class Program {
public static void main(String[] args) {
int[] numbers = initializeArray(6);
for(int i: numbers)
System.out.println(i);
}
public static int[] initializeArray(int size) {
int[] values = new int[size];
Arrays.parallelSetAll(values, i -> i*10);
return values;
}
}
В метод Arrays.parallelSetAll передается два параметра: изменяемый массив и функция, которая устанавливает элементы массива. Эта
функция перебирает все элементы и в качестве параметра получает индекс текущего перебираемого элемента. Выражение i -> i*10 означает,
что по каждому индексу в массиве будет хранится число, равное i * 10. В итоге мы получим следующий вывод:
0 10 20 30 40 50
Рассмотрим более сложный пример. Пусть у нас есть следующий класс Phone:
class Phone{
private String name;
private int price;
public Phone(String name, int price){
this.name=name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String val) {
this.name=val;
}
public int getPrice() {
return price;
}
public void setPrice(int val) {
this.price=val;
}
}
Теперь произведем манипуляции с массивом объектов Phone:
Phone[] phones = new Phone[]{new Phone("iPhone 8", 54000),
new Phone("Pixel 2", 45000),
new Phone("Samsung Galaxy S9", 40000),
new Phone("Nokia 9", 32000)};
Arrays.parallelSetAll(phones, i -> {
phones[i].setPrice(phones[i].getPrice()-10000);
return phones[i];
});
for(Phone p: phones)
System.out.printf("%s - %d \n", p.getName(), p.getPrice());
Теперь лямбда-выражение в методе Arrays.parallelSetAll представляет блок кода. И так как лямбда-выражение должно возвращать объект, то нам надо явным образом использовать
оператор return. В этом лямбда-выражении опять же функция получает индексы перебираемых элементов, и по этим индексам мы можем обратиться
к элементам массива и их изменить. Конкретно в данном случае происходит уменьшение цены смартфонов на 10000 единиц. В итоге мы получим следующий
консольный вывод:
iPhone 8 - 44000 Pixel 2 - 35000 Samsung Galaxy S9 - 30000 Nokia 9 - 22000
Отсортируем массив чисел в параллельном режиме:
int[] nums = {30, -4, 5, 29, 7, -8};
Arrays.parallelSort(nums);
for(int i: nums)
System.out.println(i);
Метод Arrays.parallelSort() в качестве параметра принимает массив и сортирует его по возрастанию:
-8 -4 5 7 29 30
Если же нам надо как-то по-другому отсортировать объекты, например, по модулю числа, или у нас более сложные объекты, то мы можем создать свой компаратор и передать его в качестве второго параметра в
Arrays.parallelSort(). Например, возьмем выше определенный класс Phone и создадим для него компаратор:
import java.util.Arrays;
import java.util.Comparator;
public class Program {
public static void main(String[] args) {
Phone[] phones = new Phone[]{new Phone("iPhone 8", 54000),
new Phone("Pixel 2", 45000),
new Phone("Samsung Galaxy S9", 40000),
new Phone("Nokia 9", 32000)};
Arrays.parallelSort(phones,new PhoneComparator());
for(Phone p: phones)
System.out.println(p.getName());
}
}
class PhoneComparator implements Comparator<Phone>{
public int compare(Phone a, Phone b){
return a.getName().toUpperCase().compareTo(b.getName().toUpperCase());
}
}
Метод parallelPrefix() походит для тех случаев, когда надо получить элемент массива или объект того же типа, что и элементы массива, который обладает некоторыми признаками.
Например, в массиве чисел это может быть максимальное, минимальное значения и т.д. Например, найдем произведение чисел:
int[] numbers = {1, 2, 3, 4, 5, 6};
Arrays.parallelPrefix(numbers, (x, y) -> x * y);
for(int i: numbers)
System.out.println(i);
Мы получим следующий результат:
1 2 6 24 120 720
То есть, как мы видим из консольного вывода, лямбда-выражение из Arrays.parallelPrefix, которое представляет бинарную функцию, получает два элемента и
выполняет над ними операцию. Результат операции сохраняется и передается в следующий вызов бинарной функции.