Data Setup

@Getter
@AllArgsConstructor
@ToString
class People {
    String name;
    String city;
}
  • Initial Data
int[] arr = {6, 5, 7, 1, 4, 9, 2};
 
List<People> list = Arrays.asList(new People("John", "Boston"),
                new People("Mary", "Boston"),
                new People("Anthony", "Boston"),
                new People("Monica", "Amsterdam"),
                new People("Seth", "São Paulo"));

Sorting Arrays

Arrays.sort(arr);
Arrays.sort(arr, fromIndex, toIndex);
 
// reverse sorting example
// since custom Comparator not supported
private void reverseArray(int[] arr) {
    int N = arr.length;
    int i = 0;
    int j = N - 1;
    while (i < j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
        i++;
        j--;
    }
}
  • Object Array
Arrays.sort(T[]);
Arrays.sort(T[], Comparator);
Arrays.sort(T[], fromIndex, toIndex, Comparator);
 
//print
System.out.println(Arrays.toString(arr));

Sorting Collections

Collections.sort(List<>);
Collections.sort(List<>, Comparator);
 
// print
System.out.println(list);

Comparable

  • package: java.lang
  • Interface: Comparable<T>
    • int compareTo(T o)
  • Return: negative (), zero (), positive ()
  • Defines the natural ordering for objects of a class implementing it
class People implements Comparable<People> {
    String name;
    String city;
 
    @Override
    public int compareTo(People o) {
        return this.name.compareTo(o.getName());
    }
}
  • Execute
Collections.sort(list); // internally naturalOrder
// or 
list.sort(Comparator.naturalOrder());
// or
list.stream().sorted().toList(); // internally naturalOrder
// or
list.stream().sorted(Comparator.naturalOrder()).toList();
 
System.out.println(list);

Comparator

  • package: java.util
  • Functional Interface: Comparator<T>
    • int compare(T o1, T o2)
  • An object that implements the Comparator interface is called a comparator
  • Return: negative (), zero (), positive ()
class NameComparator implements Comparator<People> {
    @Override
    public int compare(People p1, People p2) {
        return p1.getName().compareTo(p2.getName());
    }
}
 
// object
Comparator<People> comparator = new NameComparator();
 
// lambda
Comparator<People> comparator = (p1, p2) -> {
    return p1.getName().compareTo(p2.getName());
};
 
// utility
Comparator.comparing(People::getName);

Comparator Utilities

  • Comparator.naturalOrder()
  • Comparator.reverseOrder() also same as Collections.reverseOrder()
  • Comparator.reversed()
  • Comparator.comparing()
    • Comparator.comparingInt()
    • Comparator.comparingLong()
    • Comparator.comparingDouble()
  • Comparator.thenComparing()
    • Comparator.thenComparingInt()
    • Comparator.thenComparingLong()
    • Comparator.thenComparingDouble()
  • Comparator.nullsFirst()
  • Comparator.nullsLast()

Examples

  • Reverse
list.stream()
    .sorted(Comparator.reverseOrder())
    .forEach(System.out::println); 
  • Custom comparator
list.stream()
    .sorted(Comparator.comparing(People::getCity))
    .map(People::getName)
    .forEach(System.out::println);
  • Multiple comparing
list.stream()
        .sorted(Comparator.comparing(People::getCity)
                .thenComparing(People::getName))
        .map(People::getName)
        .forEach(System.out::println);
  • Ascending then descending
list.stream()
        .sorted(Comparator.comparing(People::getCity)
                    .thenComparing(Comparator.comparing(People::getName)
                    .reversed()))
        .map(People::getName)
        .forEach(System.out::println);