I have a List of objects that have this structure
List<Employee> empList = new ArrayList<>();
empList.add(new Employee(1, "2022-07-07", "15:31"));
empList.add(new Employee(2, "2022-07-07", "12:15"));
empList.add(new Employee(3, "2021-04-05", "20:55"));
empList.add(new Employee(4, "2021-03-05", "17:14"));
Is it possible to use Stream API to find the object with the latest date and time? In this case, I would get the first object.
I know that it is possible to do this, but in this case I'm only filtering by date, and I'm not sure if duplicates dates can be a problem.
Comparator<Employee> employeeComparator =
Comparator.comparing(Employee::getDate);
Employee emp = getEmployeeList().stream()
.max(employeeComparator)
.get();
CodePudding user response:
You can simply add thenComparing()
to your comparator to compare by both date
and time
:
Comparator<Employee> employeeComparator = Comparator
.comparing(Employee::getDate)
.thenComparing(Employee::getTime);
Kind of self-explanatory, it would sort by date
and then by time
if two dates are identical.
You are correct that if you omit this, you shouldn't make any assumptions on which of the two elements having "2022-07-07"
you would get.
CodePudding user response:
Never use strings to represent date-time information. Instead, use Java 8 classes from java.time
package like LocalDateTime
.
Assuming that Employee
is reimplemented like that:
public class Employee {
private String name;
private LocalDateTime date;
// constructor, getters, etc.
}
The comparator would be:
Comparator<Employee> byDate = Comparator.comparing(Employee::getDate);
To learn how to build comparators using Java-8 method have look at this tutorial.
The second thing - avoid invoking get()
on the optional object, unless you didn't check the presence of the result (which in many cases is inconvenient and if you're finding yourself performing this check that might indicate that you're not leveraging Optional
API to its full power).
If you have a look at the documentation of Java 10 and above, you'll see the following API note in the description of get()
:
The preferred alternative to this method is
orElseThrow()
.
Method get()
will produce NoSuchElementException
in case of the empty optional, if you're OK with such outcome then apply orElseThrow()
instead, it acts in the same way and makes your intention obvious to the reader of the code.
This method also has an overloaded version which allows you to specify the type of exception to throw.
Employee emp = getEmployeeList().stream()
.max(employeeComparator)
.orElseThrow();
You're not limited to using the methods mentioned above, Optional
offers you other possibilities, for instance, you can provide a default value using orElse()
.