From 1e7471a2b3359d995a77797e8f36f0b99ca3bcc7 Mon Sep 17 00:00:00 2001 From: Eugene Kovko <37694937+eukovko@users.noreply.github.com> Date: Mon, 18 Sep 2023 19:36:58 +0200 Subject: [PATCH] BAEL-6822: Difference between Arrays.sort() and Collections.sort() (#14787) --- .../NonStableSortExample.java | 26 +++++++ .../ObjectOverheadBenchmark.java | 56 +++++++++++++++ .../PerformanceBenchmark.java | 51 +++++++++++++ .../StableSortExample.java | 23 ++++++ .../baeldung/collectionsvsarrays/Task.java | 30 ++++++++ .../baeldung/collectionsvsarrays/Tasks.java | 30 ++++++++ .../sorting/MergeSort.java | 47 ++++++++++++ .../sorting/Quicksort.java | 72 +++++++++++++++++++ 8 files changed, 335 insertions(+) create mode 100644 core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/NonStableSortExample.java create mode 100644 core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/ObjectOverheadBenchmark.java create mode 100644 core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/PerformanceBenchmark.java create mode 100644 core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/StableSortExample.java create mode 100644 core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/Task.java create mode 100644 core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/Tasks.java create mode 100644 core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/sorting/MergeSort.java create mode 100644 core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/sorting/Quicksort.java diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/NonStableSortExample.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/NonStableSortExample.java new file mode 100644 index 0000000000..cd754489a6 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/NonStableSortExample.java @@ -0,0 +1,26 @@ +package com.baeldung.collectionsvsarrays; + +import com.baeldung.collectionsvsarrays.sorting.Quicksort; +import java.util.Comparator; +import java.util.List; + +public class NonStableSortExample { + + + + public static void main(String[] args) { + List tasks = Tasks.supplier.get(); + Quicksort.sort(tasks, Comparator.comparingInt(Task::getPriority)); + System.out.println("After sorting by priority:"); + for (Task task : tasks) { + System.out.println(task); + } + Quicksort.sort(tasks, Comparator.comparing(Task::getDueDate)); + System.out.println("\nAfter sorting by due date:"); + for (Task task : tasks) { + System.out.println(task); + } + } + + +} diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/ObjectOverheadBenchmark.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/ObjectOverheadBenchmark.java new file mode 100644 index 0000000000..9a8adff507 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/ObjectOverheadBenchmark.java @@ -0,0 +1,56 @@ +package com.baeldung.collectionsvsarrays; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@Measurement(iterations = 2, time = 10, timeUnit = TimeUnit.MINUTES) +@Warmup(iterations = 5, time = 10) +@Fork(value = 2) +public class ObjectOverheadBenchmark { + + private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current(); + + @State(Scope.Benchmark) + public static class Input { + public Supplier> randomNumbers = () -> RANDOM.ints().limit(10000).boxed().collect(Collectors.toList()); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void sortingPrimitiveArray(Input input, Blackhole blackhole) { + final int[] array = input.randomNumbers.get().stream().mapToInt(Integer::intValue).toArray(); + Arrays.sort(array); + final List result = Arrays.stream(array).boxed().collect(Collectors.toList()); + blackhole.consume(result); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void sortingObjectArray(Input input, Blackhole blackhole) { + final Integer[] array = input.randomNumbers.get().toArray(new Integer[0]); + Arrays.sort(array); + blackhole.consume(array); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void sortingObjects(Input input, Blackhole blackhole) { + final List list = input.randomNumbers.get(); + Collections.sort(list); + blackhole.consume(list); + } +} diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/PerformanceBenchmark.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/PerformanceBenchmark.java new file mode 100644 index 0000000000..6e645b0fb9 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/PerformanceBenchmark.java @@ -0,0 +1,51 @@ +package com.baeldung.collectionsvsarrays; + +import com.baeldung.collectionsvsarrays.sorting.MergeSort; +import com.baeldung.collectionsvsarrays.sorting.Quicksort; +import java.util.Random; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import java.util.stream.IntStream; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Warmup; + +@Measurement(iterations = 2, time = 10, timeUnit = TimeUnit.MINUTES) +@Warmup(iterations = 5, time = 10) +public class PerformanceBenchmark { + + private static final Random RANDOM = new Random(); + private static final int ARRAY_SIZE = 10000; + private static final int[] randomNumbers = RANDOM.ints(ARRAY_SIZE).toArray(); + private static final int[] sameNumbers = IntStream.generate(() -> 42).limit(ARRAY_SIZE).toArray(); + public static final Supplier randomNumbersSupplier = randomNumbers::clone; + public static final Supplier sameNumbersSupplier = sameNumbers::clone; + + @Benchmark + @BenchmarkMode(Mode.Throughput) + @Fork(value = 1, jvmArgs = {"-Xlog:gc:file=gc-logs-quick-sort-same-number-%t.txt,filesize=900m -Xmx6gb -Xms6gb"}) + public void quickSortSameNumber() { + Quicksort.sort(sameNumbersSupplier.get()); + } + @Benchmark + @BenchmarkMode(Mode.Throughput) + @Fork(value = 1, jvmArgs = {"-Xlog:gc:file=gc-logs-quick-sort-random-number-%t.txt,filesize=900m -Xmx6gb -Xms6gb"}) + public void quickSortRandomNumber() { + Quicksort.sort(randomNumbersSupplier.get()); + } + @Benchmark + @BenchmarkMode(Mode.Throughput) + @Fork(value = 1, jvmArgs = {"-Xlog:gc:file=gc-logs-merge-sort-same-number-%t.txt,filesize=900m -Xmx6gb -Xms6gb"}) + public void mergeSortSameNumber() { + MergeSort.sort(sameNumbersSupplier.get()); + } + @Benchmark + @BenchmarkMode(Mode.Throughput) + @Fork(value = 1, jvmArgs = {"-Xlog:gc:file=gc-logs-merge-sort-random-number-%t.txt,filesize=900m -Xmx6gb -Xms6gb"}) + public void mergeSortRandomNumber() { + MergeSort.sort(randomNumbersSupplier.get()); + } +} diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/StableSortExample.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/StableSortExample.java new file mode 100644 index 0000000000..336673bac8 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/StableSortExample.java @@ -0,0 +1,23 @@ +package com.baeldung.collectionsvsarrays; + + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class StableSortExample { + + public static void main(String[] args) { + final List tasks = Tasks.supplier.get(); + Collections.sort(tasks, Comparator.comparingInt(Task::getPriority)); + System.out.println("After sorting by priority:"); + for (Task task : tasks) { + System.out.println(task); + } + Collections.sort(tasks, Comparator.comparing(Task::getDueDate)); + System.out.println("\nAfter sorting by due date:"); + for (Task task : tasks) { + System.out.println(task); + } + } +} diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/Task.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/Task.java new file mode 100644 index 0000000000..133c39ccd2 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/Task.java @@ -0,0 +1,30 @@ +package com.baeldung.collectionsvsarrays; + +public class Task { + private final long id; + private final int priority; + private final String dueDate; + + public Task(final long id, int priority, String dueDate) { + this.id = id; + this.priority = priority; + this.dueDate = dueDate; + } + + @Override + public String toString() { + return String.format("Task: #%-2d | Priority: %d | Due Date: %s", getId(), getPriority(), getDueDate()); + } + + public int getPriority() { + return priority; + } + + public String getDueDate() { + return dueDate; + } + + private long getId() { + return id; + } +} diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/Tasks.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/Tasks.java new file mode 100644 index 0000000000..fc413f549f --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/Tasks.java @@ -0,0 +1,30 @@ +package com.baeldung.collectionsvsarrays; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +public class Tasks { + + private static final List tasks; + public static final Supplier> supplier; + + static { + tasks = new ArrayList<>(); + tasks.add(new Task(1, 1, "2023-09-01")); + tasks.add(new Task(2, 2, "2023-08-30")); + tasks.add(new Task(3, 1, "2023-08-29")); + tasks.add(new Task(4, 2, "2023-09-02")); + tasks.add(new Task(5, 3, "2023-09-05")); + tasks.add(new Task(6, 1, "2023-09-03")); + tasks.add(new Task(7, 3, "2023-08-28")); + tasks.add(new Task(8, 2, "2023-09-01")); + tasks.add(new Task(9, 1, "2023-08-28")); + tasks.add(new Task(10, 2, "2023-09-04")); + tasks.add(new Task(11, 3, "2023-08-31")); + tasks.add(new Task(12, 1, "2023-08-30")); + tasks.add(new Task(13, 3, "2023-09-02")); + + supplier = () -> new ArrayList<>(tasks); + } +} diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/sorting/MergeSort.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/sorting/MergeSort.java new file mode 100644 index 0000000000..6078db50e0 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/sorting/MergeSort.java @@ -0,0 +1,47 @@ +package com.baeldung.collectionsvsarrays.sorting; + +public class MergeSort { + + public static void sort(int[] a) { + sort(a, a.length); + } + public static void sort(int[] a, int n) { + if (n < 2) { + return; + } + int mid = n / 2; + int[] l = new int[mid]; + int[] r = new int[n - mid]; + + for (int i = 0; i < mid; i++) { + l[i] = a[i]; + } + for (int i = mid; i < n; i++) { + r[i - mid] = a[i]; + } + sort(l, mid); + sort(r, n - mid); + + merge(a, l, r, mid, n - mid); + } + private static void merge( + int[] a, int[] l, int[] r, int left, int right) { + + int i = 0, j = 0, k = 0; + while (i < left && j < right) { + if (l[i] <= r[j]) { + a[k++] = l[i++]; + } + else { + a[k++] = r[j++]; + } + } + while (i < left) { + a[k++] = l[i++]; + } + while (j < right) { + a[k++] = r[j++]; + } + } + +} diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/sorting/Quicksort.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/sorting/Quicksort.java new file mode 100644 index 0000000000..eab47b901b --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/collectionsvsarrays/sorting/Quicksort.java @@ -0,0 +1,72 @@ +package com.baeldung.collectionsvsarrays.sorting; + +import java.util.Comparator; +import java.util.List; + +public class Quicksort { + + public static void sort(int arr[]) { + sort(arr, 0, arr.length - 1); + } + public static void sort(int arr[], int begin, int end) { + if (begin < end) { + int partitionIndex = partition(arr, begin, end); + + sort(arr, begin, partitionIndex-1); + sort(arr, partitionIndex+1, end); + } + } + private static int partition(int arr[], int begin, int end) { + int pivot = arr[end]; + int i = (begin-1); + + for (int j = begin; j < end; j++) { + if (arr[j] <= pivot) { + i++; + + int swapTemp = arr[i]; + arr[i] = arr[j]; + arr[j] = swapTemp; + } + } + + int swapTemp = arr[i+1]; + arr[i+1] = arr[end]; + arr[end] = swapTemp; + + return i+1; + } + + public static void sort(List list, Comparator comparator) { + sort(list, 0, list.size() - 1, comparator); + } + public static void sort(List list, int low, int high, Comparator comparator) { + if (low < high) { + int partitionIndex = partition(list, low, high, comparator); + + sort(list, low, partitionIndex - 1, comparator); + sort(list, partitionIndex + 1, high, comparator); + } + } + + private static int partition(List list, int begin, int end, Comparator comparator) { + T pivot = list.get(end); + int i = (begin-1); + + for (int j = begin; j < end; j++) { + if (comparator.compare(list.get(j), pivot) <= 0) { + i++; + + T swapTemp = list.get(i); + list.set(i, list.get(j)); + list.set(j, swapTemp); + } + } + + T swapTemp = list.get(i+1); + list.set(i+1,list.get(end)); + list.set(end, swapTemp); + + return i+1; + } +}