Reputation: 65
I have a piece of code where am doing something like:
Optional<College> college = Optional.ofNullable(student)
.map(stud -> stud.getCollege())
.get()
.stream()
.filter(college -> Objects.nonNull(college.getCollegeName()))
.findFirst();
Now, while writing an unit test, I got a catch that what if student comes as null
?
It would be effectively like:
Optional.empty() // the same as the student is null
.map(stud -> stud.getCollege())
.get()
.stream()
.filter(college -> Objects.nonNull(college.getCollegeName()))
.findFirst();
Which I think is not fine because I am getting Exception
expected<com.src.exceptions.CollegeNotFoundException> but
was<java.util.NoSuchElementException>
#Update
Updating the question details for clarifications
Upvotes: 1
Views: 9586
Reputation: 44496
Calling Optional::get
with no previous check Optional::isPresent
is dangerous because it might produce CollegeNotFoundException
. And it is not the way the Optional
shall be used. The idea of Optional
is mapping/filtering the values and providing a default value if the Optional
ends up with no element (empty).
Assuming Student::getCollege
returns List<College>
having method College::getCollegeName
, you can do the following:
College college = Optional.ofNullable(student)
.map(stud -> stud.getCollege())
// if Optional is empty, then use an empty collection
.orElse(Collections.emptyList())
.stream()
.filter(c -> Objects.nonNull(c.getCollegeName()))
.findFirst()
// get the value or else college is null
.orElse(null);
As long as stud.getCollege()
returns null
, the Optional
becomes empty and an empty list will be streamed. And again the same principle is applied: As long as the list is empty, the filter
and findFirst
are not be called and null
is safely returned (or any default value you wish).
Also note that the line .filter(c -> Objects.nonNull(c.getCollegeName()))
might also produce NullPointerException
as long as there is not guaranteed stud.getCollege()
doesn't return a list with a null
element (remember the list is not null
itself so Optional
treats it as a "valuable" item). The safe code actually looks like:
Optional<College> college = Optional.ofNullable(student)
.map(stud -> stud.getCollege())
.orElse(Collections.emptyList())
.stream()
.filter(c -> c != null && c.getCollegeName() != null)
.findFirst();
Actually, I prefer to return either a null-object, null
or Optional
itself.
Upvotes: 1
Reputation: 2262
I agree with @Nikolas approach except that you should not return null
, returning null
at last is against using Optional
What about this one:
Optional<College> optional = Optional.ofNullable(student)
.map(stud -> stud.getCollegeList())
.orElse(Collections.emptyList())
.stream()
.filter(c -> Objects.nonNull(c.getCollegeName()))
.findFirst();
Upvotes: 3