В 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
, которое представляет бинарную функцию, получает два элемента и
выполняет над ними операцию. Результат операции сохраняется и передается в следующий вызов бинарной функции.