81

Consider a class User

public class User{
  int userId;
  String name;
  Date date;
}

Now I have a List<User> of size 20, how can I find the max date in the list without using manual iterator?

Rodrigo
  • 483
  • 8
  • 14
user2783484
  • 889
  • 1
  • 6
  • 10
  • 1
    Your question is unclear for me. Can you please elaborate more on this? – Maroun Jan 08 '14 at 12:28
  • 5
    Sort your list using a custom comparator and take the first result. – Alexis C. Jan 08 '14 at 12:29
  • 2
    What do you mean by "manual iterator". Does `Collections.max(yourList, yourComparator)` counts as "manual"? – Pshemo Jan 08 '14 at 12:36
  • I tried Using Comparator! It works fine! but i am looking some thing like lambdaj approach but not lambdaj!! – user2783484 Jan 08 '14 at 12:37
  • If you are asking us to recommend you a tool or library then your question is off-topic on SO (take a look at point 5 [here](http://stackoverflow.com/help/on-topic) ) – Pshemo Jan 08 '14 at 12:40

7 Answers7

201

Since you are asking for lambdas, you can use the following syntax with Java 8:

Date maxDate = list.stream().map(u -> u.date).max(Date::compareTo).get();

or, if you have a getter for the date:

Date maxDate = list.stream().map(User::getDate).max(Date::compareTo).get();
assylias
  • 321,522
  • 82
  • 660
  • 783
  • Thank you, also did the job for me! This solution avoids the use of a `Comparator`, which can be annoying because it not recognizes the type of objects in the `Stream`. – bashoogzaad Jun 02 '15 at 13:40
  • You need to use map first in order to get an stream of dates – Wilson Campusano Sep 09 '16 at 14:32
  • 4
    It's a safer way to use the orElse(null) then .get(); – Jimmy Geers Nov 30 '16 at 09:47
  • @zeroke in general I agree that one shouldn't call `get` directly - in this case however, if you know that the list is not empty then you'er safe. So it's context dependent I suppose. – assylias Nov 30 '16 at 13:12
  • 27
    I found this by searching for a similar problem, but I would need in your example the user with the max date. For that case there is another nice thing: `Optional user = users.stream().max(Comparator.comparing(User::getDate));` – adebasi Mar 30 '17 at 10:04
  • 8
    If you want the object with the max date and not just the date itself you can do: `User user = Collections.max(list, Comparator.comparing(User::getDate))` – Spacejockey May 07 '19 at 13:41
  • I get "non-static method cannot be referenced from a static context" from Date::compareTo – Steve Waters Jun 23 '20 at 10:53
  • @SteveWaters Works fine here: https://ideone.com/lz5lNt - you may want to ask a separate question with more details about the code you are running. – assylias Jun 23 '20 at 11:57
13

A small improvement from the accepted answer is to do the null check and also get full object.

public class DateComparator {

public static void main(String[] args) throws ParseException {
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

    List<Employee> employees = new ArrayList<>();
    employees.add(new Employee(1, "name1", addDays(new Date(), 1)));
    employees.add(new Employee(2, "name2", addDays(new Date(), 3)));
    employees.add(new Employee(3, "name3", addDays(new Date(), 6)));
    employees.add(new Employee(4, "name4", null));
    employees.add(new Employee(5, "name5", addDays(new Date(), 4)));
    employees.add(new Employee(6, "name6", addDays(new Date(), 5)));
    System.out.println(employees);
    Date maxDate = employees.stream().filter(emp -> emp.getJoiningDate() != null).map(Employee::getJoiningDate).max(Date::compareTo).get();
    System.out.println(format.format(maxDate));
    //Comparator<Employee> comparator = (p1, p2) -> p1.getJoiningDate().compareTo(p2.getJoiningDate());
    Comparator<Employee> comparator = Comparator.comparing(Employee::getJoiningDate);
    Employee maxDatedEmploye = employees.stream().filter(emp -> emp.getJoiningDate() != null).max(comparator).get();
    System.out.println(" maxDatedEmploye : " + maxDatedEmploye);

    Employee minDatedEmployee = employees.stream().filter(emp -> emp.getJoiningDate() != null).min(comparator).get();
    System.out.println(" minDatedEmployee : " + minDatedEmployee);

}

public static Date addDays(Date date, int days) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);
    cal.add(Calendar.DATE, days); // minus number would decrement the days
    return cal.getTime();
}
}

You would get below results :

 [Employee [empId=1, empName=name1, joiningDate=Wed Mar 21 13:33:09 EDT 2018],
Employee [empId=2, empName=name2, joiningDate=Fri Mar 23 13:33:09 EDT 2018],
Employee [empId=3, empName=name3, joiningDate=Mon Mar 26 13:33:09 EDT 2018],
Employee [empId=4, empName=name4, joiningDate=null],
Employee [empId=5, empName=name5, joiningDate=Sat Mar 24 13:33:09 EDT 2018],
Employee [empId=6, empName=name6, joiningDate=Sun Mar 25 13:33:09 EDT 2018]
]
2018-03-26
 maxDatedEmploye : Employee [empId=3, empName=name3, joiningDate=Mon Mar 26 13:33:09 EDT 2018]

 minDatedEmployee : Employee [empId=1, empName=name1, joiningDate=Wed Mar 21 13:33:09 EDT 2018]

Update : What if list itself is empty ?

        Date maxDate = employees.stream().filter(emp -> emp.getJoiningDate() != null).map(Employee::getJoiningDate).max(Date::compareTo).orElse(new Date());
    System.out.println(format.format(maxDate));
    Comparator<Employee> comparator = Comparator.comparing(Employee::getJoiningDate);
    Employee maxDatedEmploye = employees.stream().filter(emp -> emp.getJoiningDate() != null).max(comparator).orElse(null);
    System.out.println(" maxDatedEmploye : " + maxDatedEmploye);
Jajikanth pydimarla
  • 1,512
  • 13
  • 11
8
Comparator<User> cmp = new Comparator<User>() {
    @Override
    public int compare(User user1, User user2) {
        return user1.date.compareTo(user2.date);
    }
};

Collections.max(list, cmp);
giannis christofakis
  • 8,201
  • 4
  • 54
  • 65
5
LocalDate maxDate = dates.stream()
                            .max( Comparator.comparing( LocalDate::toEpochDay ) )
                            .get();

LocalDate minDate = dates.stream()
                            .min( Comparator.comparing( LocalDate::toEpochDay ) )
                            .get();
Mike Moreira
  • 113
  • 1
  • 7
2

Just use Kotlin!

val list = listOf(user1, user2, user3)
val maxDate = list.maxBy { it.date }?.date
Kirill Groshkov
  • 1,535
  • 1
  • 22
  • 23
0

troubleshooting-friendly style

You should not call .get() directly. Optional<>, that Stream::max returns, was designed to benefit from .orElse... inline handling.

If you are sure your arguments have their size of 2+:

list.stream()
    .map(u -> u.date)
    .max(Date::compareTo)
    .orElseThrow(() -> new IllegalArgumentException("Expected 'list' to be of size: >= 2. Was: 0"));

If you support empty lists, then return some default value, for example:

list.stream()
    .map(u -> u.date)
    .max(Date::compareTo)
    .orElse(new Date(Long.MIN_VALUE));

CREDITS to: @JimmyGeers, @assylias from the accepted answer.

epox
  • 9,236
  • 1
  • 55
  • 38
0

self-explanatory style

import static java.util.Comparator.naturalOrder;
...

    list.stream()
        .map(User::getDate)
        .max(naturalOrder())
        .orElse(null)          // replace with .orElseThrow() is the list cannot be empty
epox
  • 9,236
  • 1
  • 55
  • 38