Java 8 - Optional<CustomizedObject> get first element of the list within CustomizedObject

Viewed 1500

I am not sure how to do this

class Department {
    String deptName;
    List<Person> employees;
}

class Person {
    String personName;
}

The problem statement is to fetch the first name of the person working in a particular department. This department can be optional. So this is how my method looks -

String getFirstPerson(Optional<Department> department, String defaultName) {
// TODO: 
}

I know the traditional way of doing this but would like to see some Java 8 + lambda way to simplify this. Still a newbie here - so please pardon if I am not using the correct format.

I also have a default name to use in case we dont find that value.

P.S. I know it is not best practice to send Optional as method parameter. This is not the actual code. I am just trying to simplify it.

3 Answers

You can use the map function on Optional to get the employees list and then use stream get the first name or return defaultName. Even incase if Optional is empty you will get the defaultName

String getFirstPerson(Optional<Department> department, String defaultName) {

   return department.map(d->d.getEmployees().stream().map(Person::getPersonName).findFirst().orElse(defaultName)).orElse(defaultName));
}

If you have a chance of getting null on getEmployees you can use below approach

department.map(Department::getEmployees)
          .filter(Objects::nonNull)
          .map(emp->emp.stream().map(Person::getPersonName).findFirst().orElse(defaultName)).orElse(defaultName)

A simplified way of doing that could be using emptyList for absent department or nullable employees:

String getFirstPerson(Optional<Department> department, String defaultName) {
    return department.map(Department::getEmployees)
            .orElse(Collections.emptyList()) // get rid of this ensuring non null List
            .stream()
            .map(Person::getPersonName)
            .findFirst()
            .orElse(defaultName);
}

Actually in:

department.map(Department::getEmployees)
          .filter(Objects::nonNull)
          .map(emp->emp.stream().map(Person::getPersonName).findFirst().orElse(defaultName)).orElse(defaultName)

we don't have to check non null since .map(Department::getEmployees) will return Optional.empty() if employees are null. See Optional documentation. Correct answer would be without redundant filter:

department.map(Department::getEmployees)
          .map(emp->emp.stream().map(Person::getPersonName).findFirst().orElse(defaultName)).orElse(defaultName)

Or alternatively:

department.map(Department::getEmployees)
          .map(List::stream)
          .map(Stream::findFirst)
          .flatMap(Functions.identity())
          .map(Person::getPersonName)
          .orElse(defaultName);
Related