Reputation: 4109
I want to construct an Employee object using an employeeId and if the employeeId is not found, just print a message. Based on my understanding, I came up with following:
private Optional<Employee> createEmployee(SearchParams params) {
Optional<String> employeeId = searchEmpId(params);
Optional<Employee> employeeOptional = employeeId.map(epmId -> new Employee());
employeeOptional.ifPresent(employee -> {
employee.setName(getEmpName(employeeId));
employee.setSalary(getEmpSalary(employeeId));
});
employeeOptional.orElseGet(() -> {
LOG.warn("No emp records found for params {}.", params);
return null;
});
return employeeOptional;
}
Is there a way to simplify/optimize the above code? I believe there should be a simple way to do that. Any help is much appreciated.
Upvotes: 0
Views: 667
Reputation: 2107
You can go further and implement Martin Fowler's Special case pattern for Employee
entity. But, main drawback here is that all Employee
related stuff should be done within somof its methods, because only appropriate Employee
instance should decide what to do in particaular case and this behaviour should not be externalized.
Upvotes: 0
Reputation: 11122
Basically this way
Optional<Employee> createEmployee(SearchParams params) {
return searchEmpId(params).map(id -> {
Employee e = new Employee();
e.setName(getEmpName(id));
e.setSalary(getEmpSalary(id));
return e;
})
The case with an empty employee is an exception to your happy flow and should be implemented and dealt with that way. The point of doing that is to avoid explicit calls to
if(!empOptional.isPresent() {...}
to either write a log statement or return an empty optional because you have to deal with the empty optional later in the control flow in any case.
So better define an exceptional flow, for example
try {
Employee e = createEmployee(params).orElseThrow(() -> new EmployeeNotFoundException());
e.practice("java");
} catch(EmployeeNotFoundExceptione e){
LOG.info("not found, 404, whatever", e);
}
Of course you could handle that exception on an upper layer as well, just as it's appropriate to your case.
Upvotes: 1
Reputation: 17435
The way to make it cleaner is to not use the optional internally, since you don't use it in any useful way.
If you want to return an optional to the invoker, so that they can react accordingly, then fine. But the way you're using it internally doesn't make the code clearer in any form. So here's a suggestion:
private Optional<Employee> createEmployee(SearchParams params) {
String employeeId = searchEmpId(params);
if (employeeId == null) {
LOG.warn("No emp records found for params {}.", params);
return Optional.empty();
}
Employee employee = new Employee());
employee.setName(getEmpName(employeeId));
employee.setSalary(getEmpSalary(employeeId));
return Optional.of(employee);
}
As an aside nitpick: if you want to return an Optional
to the invoking class, that basically tells the invoking class 'this could be empty, and it's up to you to handle that'. In that case I would consider it bad form to log a warning youself. It's implied that the calling code will handle this issue, so do the logging. I would do internal logging here on debug level.
Upvotes: 0
Reputation: 782
Assuming you have a constructor that accept an id in the Employee class:
Optional<Employee> employee = employeeId.map(Employee::new)
.map(employee -> employee.setName(...))
.map(employee -> employee.setSalary(...));
if (!employee.isPresent()) {
// log
}
return employee;
Upvotes: 0