Bubble Sort with tests I've become a bit rusty in Java. This is an attempt at brushing up my skills.


  Bubble sort, sometimes referred to as sinking sort, is a simple sorting algorithm that repeatedly steps through the list, compares adjacent elements and swaps them if they are in the wrong order. The pass through the list is repeated until the list is sorted. The algorithm, which is a comparison sort, is named for the way smaller or larger elements "bubble" to the top of the list. 


Code

import java.util.Comparator;
import java.util.Objects;

public class Sorting {
    /**
     * Day 07 - Bubble Sort
     * In place sort given array with bubble sort algorithm
     *
     * @param data       array
     * @param comparator implementation of comparator for given data type
     * @param ascending  sort order
     * @param &lt;T&gt;        data type of array elements
     * @return sorted data array
     */
    public static &lt;T&gt; T[] bubbleSort(T[] data, Comparator&lt;T&gt; comparator, boolean ascending) {
        Objects.requireNonNull(data);
        int len = data.length;
        if (len &lt;= 0) return data;
        T temp;
        boolean swapped;
        for (int i = 0; i &lt; len - 1; i++) {
            swapped  = false;
            for (int j = 0; j &lt; len - 1 - i; j++) {
                if ((comparator.compare(data[j], data[j + 1]) * (ascending ? 1 : -1)) &gt; 0) {
                    temp = data[j];
                    data[j] = data[j + 1];
                    data[j + 1] = temp;
                    swapped = true;
                }
            }
            if (!swapped) break;
        }
        return data;
    }
}


Test cases

import org.testng.Assert;
import org.testng.annotations.Test;


public class TestSorting {
    @Test
    public void testBubbleSort() {
        Assert.assertEquals(asc(1, 2, 3), ar(1, 2, 3));
        Assert.assertEquals(asc(3, 2, 1), ar(1, 2, 3));
        Assert.assertEquals(asc(2, 0, -1, 2, 1), ar(-1, 0, 1, 2, 2));

        Assert.assertEquals(dsc(1, 2, 3), ar(3, 2, 1));
        Assert.assertEquals(dsc(3, 2, 1), ar(3, 2, 1));
        Assert.assertEquals(dsc(2, 0, -1, 2, 1), ar(2, 2, 1, 0, -1));

        Assert.assertEquals(asc(2, 1), ar(1, 2));
        Assert.assertEquals(asc(1), ar(1));
        Assert.assertEquals(asc(), ar());
        Assert.assertEquals(dsc(1), ar(1));
        Assert.assertEquals(dsc(), ar());
    }

    @Test(expectedExceptions = {NullPointerException.class})
    public void testNullExcept() {
        Sorting.bubbleSort(null, Integer::compare, true);
    }

    private static Integer[] ar(Integer... objects) {
        return objects;
    }

    private static Integer[] asc(Integer... objects) {
        return Sorting.bubbleSort(objects, Integer::compare, true);
    }

    private static Integer[] dsc(Integer... objects) {
        return Sorting.bubbleSort(objects, Integer::compare, false);
    }
}
Your code looks generally OK in my book (i.e. not being that rusty ;-))

A few pointers though:


Generally keep variable scope as low as possible. T temp and boolean swapped can be declared at the place where they are needed initially.
Though I see the idea of multiplying with 1 or -1, the expression looks too "magic" for me. As Comparators have a reversed() method these days, I recommend to use that.


Putting this advice to use:

public static &lt;T&gt; T[] bubbleSort(T[] data, Comparator&lt;T&gt; comparator, boolean ascending) {
    Objects.requireNonNull(data);
    int len = data.length;
    if (len &lt;= 0) return data;
    Comparator&lt;T&gt; actualComparator = ascending ? comparator : comparator.reversed();

    for (int i = 0; i &lt; len - 1; i++) {
        boolean swapped  = false;
        for (int j = 0; j &lt; len - 1 - i; j++) {
            if (actualComparator.compare(data[j], data[j + 1]) &gt; 0) {
                T temp = data[j];
                data[j] = data[j + 1];
                data[j + 1] = temp;
                swapped = true;
            }
        }
        if (!swapped) break;
    }
    return data;
}