Sorting is a fundamental operation in computer science. Does sort
work with Comparator
? Yes, the sort
method in Java, specifically Collections.sort()
and Arrays.sort()
, seamlessly integrates with the Comparator
interface, offering powerful and flexible sorting capabilities. At compare.edu.vn, we’ll explore this integration, detailing how to use comparators effectively to customize sorting logic for various data types and objects and offering decision-making insights. You’ll gain insight into custom sorting, sorting algorithms, and comparison functions.
Table of Contents
1. Understanding the Basics of Sorting in Java
- 1.1. Default Sorting with
Comparable
- 1.2. Custom Sorting with
Comparator
2. HowComparator
Works withCollections.sort()
- 2.1. Syntax and Usage
- 2.2. Example: Sorting a List of Objects Using
Comparator
3. HowComparator
Works withArrays.sort()
- 3.1. Syntax and Usage
- 3.2. Example: Sorting an Array of Objects Using
Comparator
4. ImplementingComparator
with Lambda Expressions - 4.1. Syntax and Benefits of Using Lambda Expressions
- 4.2. Example: Sorting with Lambda Expressions
5. Real-World Use Cases forComparator
- 5.1. Sorting by Multiple Criteria
- 5.2. Sorting in Reverse Order
- 5.3. Sorting Custom Objects
6. AdvancedComparator
Techniques - 6.1. Chaining Comparators
- 6.2. Handling Null Values
- 6.3. Using
Comparator
with Streams
7. Performance Considerations When UsingComparator
- 7.1. Impact on Sorting Time
- 7.2. Best Practices for Efficient Sorting
8.Comparable
vs.Comparator
: Choosing the Right Interface - 8.1. When to Use
Comparable
- 8.2. When to Use
Comparator
- 8.3. Combining Both Interfaces
9. Common Mistakes to Avoid When UsingComparator
- 9.1. Incorrect Return Values
- 9.2. Not Handling Edge Cases
- 9.3. Ignoring Performance Implications
10. Best Practices for Writing Effective Comparators - 10.1. Keep it Simple and Readable
- 10.2. Follow the Contract
- 10.3. Test Thoroughly
11. Exploring Different Sorting Algorithms - 11.1. Bubble Sort
- 11.2. Insertion Sort
- 11.3. Merge Sort
- 11.4. Quick Sort
- 11.5. Heap Sort
12. How to Choose the Right Sorting Algorithm - 12.1. Understanding Time Complexity
- 12.2. Space Complexity Considerations
- 12.3. Stability in Sorting Algorithms
13. Java 8 and Beyond: Enhancements to Sorting - 13.1. Introduction of Parallel Sorting
- 13.2. Using
comparing
,thenComparing
, and Other Helper Methods - 13.3. Working with Primitive Types
14. Practical Examples of Sorting in Java - 14.1. Sorting a List of Strings by Length
- 14.2. Sorting a List of Dates
- 14.3. Sorting a List of Employees by Salary and then by Name
15. Debugging Sorting Issues - 15.1. Common Errors and How to Fix Them
- 15.2. Using Logging and Debugging Tools
16. Integrating Sorting with Other Data Structures - 16.1. Sorting Sets
- 16.2. Sorting Maps by Key or Value
17. The Role of Sorting in Data Analysis - 17.1. Preparing Data for Analysis
- 17.2. Improving Search Efficiency
18. Future Trends in Sorting Algorithms and Techniques - 18.1. Advances in Parallel and Distributed Sorting
- 18.2. The Impact of New Hardware
19. Case Studies: Successful Implementations of Sorting - 19.1. E-Commerce Platforms
- 19.2. Financial Systems
20. Frequently Asked Questions (FAQs) about Sorting in Java - 20.1. What is the difference between
sort
andparallelSort
? - 20.2. How can I sort a list in descending order?
- 20.3. Can I use
Comparator
with primitive types?
21. Conclusion - 21.1. Key Takeaways
- 21.2. Encouragement to Further Explore Sorting Techniques
1. Understanding the Basics of Sorting in Java
Sorting is a cornerstone of computer science, involving arranging items in a specific order, which can be numerical, alphabetical, or based on any custom criteria. In Java, sorting is primarily achieved using the Collections.sort()
method for lists and the Arrays.sort()
method for arrays. These methods can sort elements in their natural order or based on a custom order defined by a Comparator
.
1.1. Default Sorting with Comparable
The Comparable
interface is used for objects that have a natural ordering. Classes that implement Comparable
provide a compareTo()
method, which defines how objects of that class are compared to each other. This is useful for simple data types and classes where the sorting criteria are inherently obvious.
For instance, the String
and Integer
classes in Java implement the Comparable
interface. This allows strings to be sorted alphabetically and integers numerically without any additional code. Consider the following example:
List<String> names = new ArrayList<>();
names.add("Charlie");
names.add("Alice");
names.add("Bob");
Collections.sort(names); // Sorts alphabetically: [Alice, Bob, Charlie]
List<Integer> numbers = new ArrayList<>();
numbers.add(3);
numbers.add(1);
numbers.add(2);
Collections.sort(numbers); // Sorts numerically: [1, 2, 3]
In these cases, the sort()
method uses the compareTo()
method implemented by the String
and Integer
classes to determine the order.
1.2. Custom Sorting with Comparator
The Comparator
interface provides a way to define custom sorting logic. This is particularly useful when:
- You want to sort objects of a class that does not implement
Comparable
. - You want to sort objects based on a different criterion than their natural ordering.
- You need multiple sorting strategies for the same class.
A Comparator
is an object that encapsulates a comparison function. It has a compare()
method that takes two objects as arguments and returns an integer:
- Negative if the first object should come before the second object.
- Positive if the first object should come after the second object.
- Zero if the objects are equal in terms of sorting.
Using a Comparator
allows you to sort objects in a variety of ways without modifying the original class. This makes your code more flexible and maintainable.
2. How Comparator
Works with Collections.sort()
The Collections.sort()
method is used to sort lists in Java. It can take a list and an optional Comparator
as arguments. When a Comparator
is provided, the sort()
method uses it to determine the order of elements in the list.
2.1. Syntax and Usage
The syntax for using Collections.sort()
with a Comparator
is as follows:
Collections.sort(list, comparator);
Here, list
is the List
object you want to sort, and comparator
is an instance of a class that implements the Comparator
interface.
The Comparator
interface must implement the compare()
method:
public interface Comparator<T> {
int compare(T obj1, T obj2);
}
The compare()
method defines the sorting logic. It takes two objects of type T
and returns an integer indicating their relative order.
2.2. Example: Sorting a List of Objects Using Comparator
Consider a class Book
with attributes title
and author
. Suppose you want to sort a list of Book
objects by their title. Here’s how you can do it using a Comparator
:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
class Book {
String title;
String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"title='" + title + ''' +
", author='" + author + ''' +
'}';
}
}
class SortByTitle implements Comparator<Book> {
@Override
public int compare(Book b1, Book b2) {
return b1.title.compareTo(b2.title);
}
}
public class Main {
public static void main(String[] args) {
List<Book> books = new ArrayList<>();
books.add(new Book("The Lord of the Rings", "J.R.R. Tolkien"));
books.add(new Book("Pride and Prejudice", "Jane Austen"));
books.add(new Book("1984", "George Orwell"));
Collections.sort(books, new SortByTitle());
for (Book book : books) {
System.out.println(book);
}
}
}
In this example, the SortByTitle
class implements the Comparator<Book>
interface and provides the logic to compare two Book
objects based on their titles. The Collections.sort()
method uses this Comparator
to sort the list of Book
objects alphabetically by title.
Alt: Sorting a list of books by title using the SortByTitle comparator in Java.
3. How Comparator
Works with Arrays.sort()
The Arrays.sort()
method is used to sort arrays in Java. Similar to Collections.sort()
, it can also accept a Comparator
to define custom sorting logic. This is particularly useful when you need to sort arrays of objects that don’t have a natural ordering or when you want to sort them based on a specific criterion.
3.1. Syntax and Usage
The syntax for using Arrays.sort()
with a Comparator
is as follows:
Arrays.sort(array, comparator);
Here, array
is the array you want to sort, and comparator
is an instance of a class that implements the Comparator
interface.
The Comparator
interface, as mentioned earlier, must implement the compare()
method:
public interface Comparator<T> {
int compare(T obj1, T obj2);
}
The compare()
method defines the sorting logic by returning an integer that indicates the relative order of the two objects being compared.
3.2. Example: Sorting an Array of Objects Using Comparator
Suppose you have an array of Employee
objects, and you want to sort them based on their employee ID. Here’s how you can achieve this using a Comparator
:
import java.util.Arrays;
import java.util.Comparator;
class Employee {
int id;
String name;
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + ''' +
'}';
}
}
class SortById implements Comparator<Employee> {
@Override
public int compare(Employee e1, Employee e2) {
return Integer.compare(e1.id, e2.id);
}
}
public class Main {
public static void main(String[] args) {
Employee[] employees = new Employee[3];
employees[0] = new Employee(3, "Charlie");
employees[1] = new Employee(1, "Alice");
employees[2] = new Employee(2, "Bob");
Arrays.sort(employees, new SortById());
for (Employee employee : employees) {
System.out.println(employee);
}
}
}
In this example, the SortById
class implements the Comparator<Employee>
interface and provides the logic to compare two Employee
objects based on their IDs. The Arrays.sort()
method uses this Comparator
to sort the array of Employee
objects in ascending order of their IDs.
Alt: Demonstrating the sorting of an array of employee objects by ID using Arrays.sort and a custom comparator in Java.
4. Implementing Comparator
with Lambda Expressions
Lambda expressions provide a concise way to implement functional interfaces, including Comparator
. Using lambda expressions can make your code more readable and less verbose, especially when the sorting logic is simple.
4.1. Syntax and Benefits of Using Lambda Expressions
The syntax for a lambda expression is:
(parameters) -> { expression or statements }
For a Comparator
, the lambda expression takes two arguments and returns an integer:
(obj1, obj2) -> {
// Comparison logic
return result;
}
The benefits of using lambda expressions include:
- Conciseness: Reduces the amount of boilerplate code.
- Readability: Makes the code easier to understand, especially for simple comparisons.
- Functional Programming: Supports a functional programming style, making the code more modular and testable.
4.2. Example: Sorting with Lambda Expressions
Let’s revisit the Book
example from Section 2.2. Instead of creating a separate class for the Comparator
, you can use a lambda expression:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class Book {
String title;
String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"title='" + title + ''' +
", author='" + author + ''' +
'}';
}
}
public class Main {
public static void main(String[] args) {
List<Book> books = new ArrayList<>();
books.add(new Book("The Lord of the Rings", "J.R.R. Tolkien"));
books.add(new Book("Pride and Prejudice", "Jane Austen"));
books.add(new Book("1984", "George Orwell"));
Collections.sort(books, (b1, b2) -> b1.title.compareTo(b2.title));
for (Book book : books) {
System.out.println(book);
}
}
}
In this example, the lambda expression (b1, b2) -> b1.title.compareTo(b2.title)
directly implements the Comparator
interface, providing the sorting logic inline. This makes the code more compact and easier to read.
Alt: Example of using a lambda expression for sorting a list of Book objects by title in Java.
5. Real-World Use Cases for Comparator
The Comparator
interface is incredibly versatile and can be used in various real-world scenarios. Here are some common use cases:
5.1. Sorting by Multiple Criteria
Sometimes, you need to sort objects based on multiple criteria. For example, you might want to sort a list of employees first by salary and then by name. This can be achieved by chaining comparators.
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
class Employee {
String name;
double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + ''' +
", salary=" + salary +
'}';
}
}
public class Main {
public static void main(String[] args) {
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("Alice", 50000));
employees.add(new Employee("Bob", 60000));
employees.add(new Employee("Charlie", 50000));
employees.add(new Employee("David", 60000));
Comparator<Employee> sortBySalary = (e1, e2) -> Double.compare(e1.salary, e2.salary);
Comparator<Employee> sortByName = (e1, e2) -> e1.name.compareTo(e2.name);
employees.sort(sortBySalary.thenComparing(sortByName));
for (Employee employee : employees) {
System.out.println(employee);
}
}
}
In this example, the thenComparing()
method is used to chain the comparators. The list is first sorted by salary and then, within each salary group, it is sorted by name.
5.2. Sorting in Reverse Order
You can easily sort objects in reverse order by reversing the logic in the compare()
method or by using the reversed()
method introduced in Java 8.
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(3);
numbers.add(1);
numbers.add(2);
// Using reversed() method
Comparator<Integer> reverseOrder = Comparator.<Integer>naturalOrder().reversed();
numbers.sort(reverseOrder);
for (Integer number : numbers) {
System.out.println(number);
}
}
}
In this example, Comparator.naturalOrder()
provides the natural order for integers, and reversed()
reverses this order, resulting in a descending sort.
5.3. Sorting Custom Objects
Comparator
is particularly useful for sorting custom objects based on specific attributes or logic. Consider a list of Product
objects that you want to sort by price.
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
class Product {
String name;
double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "Product{" +
"name='" + name + ''' +
", price=" + price +
'}';
}
}
public class Main {
public static void main(String[] args) {
List<Product> products = new ArrayList<>();
products.add(new Product("Laptop", 1200));
products.add(new Product("Keyboard", 75));
products.add(new Product("Mouse", 25));
products.sort((p1, p2) -> Double.compare(p1.price, p2.price));
for (Product product : products) {
System.out.println(product);
}
}
}
Here, the list of Product
objects is sorted by price using a lambda expression that compares the price
attribute of the products.
Alt: Sorting a list of Product objects by price using a comparator in Java.
6. Advanced Comparator
Techniques
To further enhance your sorting capabilities, let’s explore some advanced techniques using Comparator
.
6.1. Chaining Comparators
As demonstrated in Section 5.1, chaining comparators allows you to sort objects based on multiple criteria. The thenComparing()
method makes this process straightforward.
Comparator<Employee> sortBySalary = (e1, e2) -> Double.compare(e1.salary, e2.salary);
Comparator<Employee> sortByName = (e1, e2) -> e1.name.compareTo(e2.name);
employees.sort(sortBySalary.thenComparing(sortByName));
You can chain multiple thenComparing()
calls to sort by more than two criteria.
6.2. Handling Null Values
When sorting objects, you might encounter null values. It’s important to handle these values gracefully to avoid NullPointerException
errors. The Comparator
interface provides methods to handle null values:
nullsFirst(Comparator<? super T> comparator)
: Treats null values as smaller than non-null values.nullsLast(Comparator<? super T> comparator)
: Treats null values as larger than non-null values.
Here’s an example:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
class Employee {
String name;
public Employee(String name) {
this.name = name;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + ''' +
'}';
}
}
public class Main {
public static void main(String[] args) {
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("Alice"));
employees.add(new Employee(null));
employees.add(new Employee("Bob"));
Comparator<Employee> sortByName = Comparator.comparing(e -> e.name, Comparator.nullsFirst(String::compareTo));
employees.sort(sortByName);
for (Employee employee : employees) {
System.out.println(employee);
}
}
}
In this example, Comparator.nullsFirst(String::compareTo)
ensures that null names are placed at the beginning of the list.
6.3. Using Comparator
with Streams
Java 8 introduced streams, which provide a powerful way to process collections of data. You can use Comparator
with streams to sort elements as part of a stream pipeline.
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
class Employee {
String name;
int age;
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
public class Main {
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("Alice", 30),
new Employee("Bob", 25),
new Employee("Charlie", 35)
);
List<Employee> sortedEmployees = employees.stream()
.sorted(Comparator.comparingInt(e -> e.age))
.collect(Collectors.toList());
sortedEmployees.forEach(System.out::println);
}
}
In this example, the stream of Employee
objects is sorted by age using Comparator.comparingInt()
, and the sorted elements are collected into a new list.
Alt: Example of sorting a list of Employee objects by age using Comparator with Java Streams.
7. Performance Considerations When Using Comparator
While Comparator
provides flexibility, it’s important to consider the performance implications of custom sorting logic.
7.1. Impact on Sorting Time
The time complexity of sorting algorithms can be affected by the complexity of the Comparator
implementation. Simple comparisons (e.g., comparing integers or strings) are generally fast, while complex comparisons (e.g., involving multiple attributes or calculations) can slow down the sorting process.
7.2. Best Practices for Efficient Sorting
To ensure efficient sorting:
- Keep the
compare()
method simple: Avoid complex calculations or I/O operations within thecompare()
method. - Use primitive types: When possible, use primitive types for comparisons, as they are generally faster than their object counterparts.
- Minimize object creation: Avoid creating new objects within the
compare()
method, as this can add overhead. - Consider caching: If the comparison involves expensive calculations, consider caching the results to avoid redundant computations.
8. Comparable
vs. Comparator
: Choosing the Right Interface
Both Comparable
and Comparator
are used for sorting, but they serve different purposes. Understanding when to use each interface is crucial for writing effective code.
8.1. When to Use Comparable
Use Comparable
when:
- The class has a natural ordering.
- You want to define a default sorting behavior for the class.
- You can modify the class to implement the
Comparable
interface.
8.2. When to Use Comparator
Use Comparator
when:
- The class does not have a natural ordering.
- You need to sort objects based on a different criterion than their natural ordering.
- You cannot modify the class to implement the
Comparable
interface. - You need multiple sorting strategies for the same class.
8.3. Combining Both Interfaces
It’s possible to use both Comparable
and Comparator
in the same class. The Comparable
interface defines the default sorting behavior, while the Comparator
interface provides additional sorting strategies.
For example, a Student
class might implement Comparable
to sort students by their ID by default, but you can also use a Comparator
to sort students by their GPA or name.
9. Common Mistakes to Avoid When Using Comparator
Using Comparator
effectively requires avoiding common pitfalls that can lead to incorrect sorting or runtime errors.
9.1. Incorrect Return Values
The compare()
method should return:
- A negative integer if the first object is less than the second object.
- A positive integer if the first object is greater than the second object.
- Zero if the objects are equal.
Returning incorrect values can lead to unpredictable sorting results.
9.2. Not Handling Edge Cases
Failing to handle edge cases, such as null values or empty strings, can result in NullPointerException
errors or incorrect sorting. Always consider these cases when implementing the compare()
method.
9.3. Ignoring Performance Implications
As mentioned in Section 7, complex comparisons can slow down the sorting process. Be mindful of the performance implications of your Comparator
implementation and follow best practices to ensure efficient sorting.
10. Best Practices for Writing Effective Comparators
Writing effective comparators involves ensuring they are simple, readable, and adhere to the contract defined by the Comparator
interface.
10.1. Keep it Simple and Readable
- Use clear and concise code: Avoid complex logic and unnecessary calculations.
- Use meaningful variable names: Choose variable names that clearly indicate the purpose of each variable.
- Add comments: Document the logic and purpose of the
compare()
method.
10.2. Follow the Contract
- Ensure transitivity: If
compare(a, b) > 0
andcompare(b, c) > 0
, thencompare(a, c)
must be greater than 0. - Ensure symmetry: If
compare(a, b) > 0
, thencompare(b, a)
must be less than 0. - Ensure consistency: The result of
compare(a, b)
should only depend ona
andb
, and not on external factors.
10.3. Test Thoroughly
- Write unit tests: Test the
Comparator
with a variety of inputs, including edge cases. - Use assertions: Verify that the sorting results are correct.
- Consider performance testing: Measure the performance of the
Comparator
with large datasets.
11. Exploring Different Sorting Algorithms
Java’s sort
methods utilize efficient sorting algorithms, but understanding different algorithms can help optimize performance in specific scenarios. Here are some common sorting algorithms:
11.1. Bubble Sort
- Description: Compares adjacent elements and swaps them if they are in the wrong order.
- Time Complexity: O(n^2)
- Use Case: Simple to implement but inefficient for large datasets.
11.2. Insertion Sort
- Description: Builds the sorted array one element at a time by inserting each element into its correct position.
- Time Complexity: O(n^2)
- Use Case: Efficient for small datasets or nearly sorted data.
11.3. Merge Sort
- Description: Divides the array into smaller subarrays, sorts them, and then merges them back together.
- Time Complexity: O(n log n)
- Use Case: Efficient for large datasets and stable sorting.
11.4. Quick Sort
- Description: Selects a pivot element and partitions the array into two subarrays based on the pivot.
- Time Complexity: O(n log n) average, O(n^2) worst case
- Use Case: Generally fast and efficient for large datasets.
11.5. Heap Sort
- Description: Uses a heap data structure to sort the elements.
- Time Complexity: O(n log n)
- Use Case: Efficient and guaranteed O(n log n) time complexity.
12. How to Choose the Right Sorting Algorithm
Choosing the right sorting algorithm depends on factors like dataset size, data characteristics, and performance requirements.
12.1. Understanding Time Complexity
- O(n^2) algorithms: Suitable for small datasets or nearly sorted data.
- O(n log n) algorithms: Suitable for large datasets and general-purpose sorting.
12.2. Space Complexity Considerations
- In-place sorting: Algorithms like Bubble Sort, Insertion Sort, and Heap Sort have low space complexity.
- Out-of-place sorting: Algorithms like Merge Sort require additional space.
12.3. Stability in Sorting Algorithms
- Stable sorting: Preserves the relative order of equal elements (e.g., Merge Sort, Insertion Sort).
- Unstable sorting: Does not guarantee the preservation of the relative order of equal elements (e.g., Quick Sort, Heap Sort).
13. Java 8 and Beyond: Enhancements to Sorting
Java 8 introduced several enhancements to sorting, making it more efficient and convenient.
13.1. Introduction of Parallel Sorting
Java 8 introduced parallelSort()
, which uses multiple threads to sort large arrays, improving performance.
Arrays.parallelSort(array);
13.2. Using comparing
, thenComparing
, and Other Helper Methods
The Comparator
interface includes helper methods like comparing()
and thenComparing()
for creating comparators easily.
Comparator<Employee> sortByAge = Comparator.comparing(e -> e.age);
Comparator<Employee> sortByName = Comparator.comparing(e -> e.name);
employees.sort(sortByAge.thenComparing(sortByName));
13.3. Working with Primitive Types
Java 8 provides specialized comparators for primitive types, such as comparingInt()
, comparingLong()
, and comparingDouble()
, which can improve performance.
Comparator<Employee> sortByAge = Comparator.comparingInt(e -> e.age);
14. Practical Examples of Sorting in Java
Let’s explore some practical examples of sorting in Java using Comparator
.
14.1. Sorting a List of Strings by Length
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> strings = new ArrayList<>();
strings.add("apple");
strings.add("banana");
strings.add("kiwi");
strings.sort((s1, s2) -> Integer.compare(s1.length(), s2.length()));
System.out.println(strings); // Output: [kiwi, apple, banana]
}
}
14.2. Sorting a List of Dates
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<LocalDate> dates = new ArrayList<>();
dates.add(LocalDate.of(2023, 1, 1));
dates.add(LocalDate.of(2022, 12, 31));
dates.add(LocalDate.of(2023, 2, 1));
dates.sort(LocalDate::compareTo);
System.out.println(dates); // Output: [2022-12-31, 2023-01-01, 2023-02-01]
}
}
14.3. Sorting a List of Employees by Salary and then by Name
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
class Employee {
String name;
double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + ''' +
", salary=" + salary +
'}';
}
}
public class Main {
public static void main(String[] args) {
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("Alice", 50000));
employees.add(new Employee("Bob", 60000));
employees.add(new Employee("Charlie", 50000));
employees.add(new Employee("David", 60000));
Comparator<Employee> sortBySalary = Comparator.comparingDouble(e -> e.salary);
Comparator<Employee> sortByName = Comparator.comparing(e -> e.name);
employees.sort(sortBySalary.thenComparing(sortByName));
employees.forEach(System.out::println);
}
}
![Practical Examples of Sorting in Java](https://i