A small cohesive module, leveraging Java 8 functional capabilities to remove most of the boiler-plate of handling checked exceptions.
What’s inside?
- Types equivalent to those found in java.util.function but with checked methods (declaring Throwable)
- A small family of unchecked exceptions; reflective operation, security, interrupt, etc.
- Static helper Exceptional:
- Convert checked method handles to java.util.functional interfaces
- Invoke checked functional types without try-catch
- Dirty compiler trick; throwing a checked exception as unchecked
- Factories for some common types where the constructor declares a checked exception (e.g. java.net.URI, java.net.URL)
- Convert checked exceptions to unchecked equivalents
- Swallow exceptions (accepts throwables, but only swallows exceptions - errors are rethrown)
- Unwrap reflective exceptions
- Static helper Closing:
- Concise IO stream usage (re-read as terse one-liner), condenses create-operate-close - arguably laconic over expressive
- Does all the dirty work for I-don’t-care-but-IOExceptions-on-AutoCloseable-are-destroying-my-branch-coverage
- Simple mirror EmeticStream:
- wraps java.util.stream.Stream providing equivalent methods taking checked functional types (terminates immediately on exception)
Usage
The intended use of this library is to make code more concise by removing the need to handle checked exceptions. It should really only be used for the impossible (logically we know this cannot occur) or fatal (unrecoverable, cannot degrade with grace, game over) cases.
Please use responsibly; first consider if a raised exception can actually be handled, and if not, then could it be propagated with a more contextual type/message? Be considerate to readers of logs, unlucky users and your future self.
Brief note on try-with-resources branch coverage
A nice side effect is the removal of, potential but often unrealistic, branches; a typical try-with-resources block for IO streams typically result in 8 branches - the causes of which are often misunderstood (see this old StackOverflow post - I’ve added a rambling answer with more detail).
Migration from versions 0.* to 1.*
What changed
A generic type parameter was added to the functional types for the Throwable on method declarations; so:
interface CheckedFunction<T, R> { public abstract R apply(T t) throws Throwable; }
Has become:
interface CheckedFunction<T, R, E extends Throwable> { public abstract R apply(T t) throws E; }
Why
This allows users to declare specific subtypes of Throwable, and therefore supported cases where the consumer of a checked functional type demanded matching of specific exception type e.g. AutoCloseable’s close() method declares that it throws Exception. Previously you could assign the autocloseable::close handle to a checked functional type, but not the other way round.
Upgrade path
For existing code, currently dependent on v0.y,z, the impact is nonexistent if the only use is Exceptional or EmeticStream. Otherwise, where using the checked equivalents of java.util.function.*, then appending a wildcard type parameter of <?> is sufficient (this will set the new type parameter to the upper bound of Throwable which is equivalent to the unparameterised form of v0.y.z).
Deprecated methods (such as Exceptional.closing(...)) have been removed, their alternatives are documented in previous versions.