问题
I am creating a little Spring REST service. I have a findById()
call:
@GetMapping("/items/{id}")
MyItem one(@PathVariable String id) {
return repository.findById(id).orElseThrow(() -> new MyItemNotFoundException(id));
}
If there is no MyItem object with the given id
, I am throwing an exception using the Optional<T>.orElseThrow()
method. This is very useful and quite simple.
Now I added a findAll()
call from the PagingAndSorting<T, ID>
repository:
@GetMapping("/items")
List<MyItem> all() {
return repository.findAll();
}
Is there a simple way to handle empty list outputs in a similar way as it can be done with single items? Or do I need to create something like:
@GetMapping("/items")
List<MyItem> all() {
List<MyItem> items = repository.findAll();
if (items.isEmpty())
throw new MyItemNotFoundException();
return items;
}
(The real use case handles some request parameters to filter the whole list)
回答1:
The reasoning behind the Optional
in findById
is that it avoids returning a null
.
Empty collections on the other hand are safe to iterate and handle, so there's no special .throwIfEmpty()
mechanism built-in. An empty collection is essentially an Optional in itself. It's not null, and may or may not contain elements.
If in your business logic no results means error, then it's up to you to handle it.
回答2:
The solution could be a utility fuction wrapping the findAll
call.
public class MyItemNotFoundException ... {
public static <T> List<T> requireNotEmpty(List<T> items) throws MyItemNotFoundException {
if (items.isEmpty()) {
throw new MyItemNotFoundException();
}
return items;
}
}
@GetMapping("/items")
List<MyItem> all() {
return MyItemNotFoundException.requireNotEmpty(repository.findAll());
}
Placing the function in the MyItemNotFoundException is not very readable. A better name still feels artificial:
return MyItemNotFoundException.whenEmpty(repository.findAll());
But you'll find a place, maybe in some base class/interface.
(In some systems the repository findAll may return null (very ugly), and with such a wrapping function that can be dealt with too.)
回答3:
You could stream the list, get an Optional
with findAny
and map back to the list if the result is non-empty:
items.stream().findAny().map((e) -> items).orElseThrow(NotFoundException::new);
But you should consider if this really needs to result in an Exception. My expectation as consumer of a search function would be an empty result, of no element matches my criteria.
回答4:
By REST this is what you should return:
- Single element not found: throw an exception - 404 response code mapped
- Empty list: return empty list with - 200 status code
来源:https://stackoverflow.com/questions/57989531/handling-empty-results-on-findall-is-there-a-orelsethrow-for-lists