It's because some nested implementation detail API several layers done can take arbitrary streams, and the String based implementation is done by creating a stream for that string, but the stream api allows for IOExceptions in the case of streams from disk or network devices etc.
What reasonable recovery option is there then? You can swallow the exception, because it's impossible for now, but your linter/teammates will complain at you and it could change in future to be possible since it's in the API contract. You could have your application re-raise the exception, propagating the problem further. Neither option is great.
[1]: https://fasterxml.github.io/jackson-databind/javadoc/2.7/com...
try {
....
}
catch (IOException e) { throw new RuntimeException(e); }
It asserts "I believe this error can never happen - so if it does, just re-raise it and it'll get to the top level and the request or program will terminate - which isn't a problem, as, as I've said, this can never happen".As we all know here, sometimes things that can never happen do happen e.g., as you stated, you initially wrote the program knowing it took a stream based on a string, but later that got changed to something that reads from a network. Having that error raised and logged top-level is the ideal outcome if such a mistake is made.
This syntax is verbose and I do wish there were a better syntax (e.g. Lombok @SneakyThrows is a hack which improves the situation somewhat) but the approach is the correct one.
And it also shows that you've thought about the exception. I even often find myself putting a little comment, mainly meant for future developers reading the code to whom it might not be obvious why this could never happen:
// Can never happen: Stream is always a string
catch (IOException e) { throw new RuntimeException(e); } throw new UncheckedIOException(ex);This pattern is equivalent to Rust's `unwrap` and `expect`, than can be called to transform a recoverable error into a panic.
> What reasonable recovery option is there then?
adrianmsmith's answer seems to have it, here are some rather less useful thoughts, for good measure:
The C++-style approach might be to have a boolean template parameter in the Stream API, allowCheckedExceptions, to change the signatures accordingly. As Java lacks specialisation, I don't imagine there's a way to do anything similar, short of having the library offer two very similar Steam APIs, one that permits throwing of checked exceptions and one that doesn't.
edit I suppose the standard library could offer a wrapper around the Stream API, to only accept non-throwing streams, and to return a NonThrowingStream. Internally this wrapper would presumably use the strategy adrianmsmith explained.