SafeRunnable.java
package com.guinetik.corefun;
/**
* A functional interface for operations that may throw checked exceptions.
* <p>
* {@code SafeRunnable} allows writing lambda expressions for operations that throw
* checked exceptions, which can then be converted to standard {@link Runnable}
* instances with automatic exception wrapping. This eliminates the boilerplate
* of try-catch blocks in lambda expressions.
* </p>
*
* <h2>Problem Solved</h2>
* <p>
* Java's {@link Runnable} interface declares {@code void run()} without any
* checked exceptions. This makes it impossible to use lambdas that throw checked
* exceptions directly with executors or other APIs expecting Runnable.
* </p>
*
* <h2>Example Usage</h2>
* <pre class="language-java"><code>
* // Define an operation that throws checked exceptions
* SafeRunnable task = () -> {
* Files.delete(path); // throws IOException
* };
*
* // Convert to standard Runnable for use with executors
* executor.execute(task.toRunnable());
*
* // Or execute immediately with automatic wrapping
* task.execute(); // throws SafeException on failure
*
* // Create from existing Runnable
* SafeRunnable fromRunnable = SafeRunnable.from(() -> doSomething());
* </code></pre>
*
* @author Guinetik <guinetik@gmail.com>
* @since 0.1.0
* @see SafeCallable
* @see SafeException
* @see SafeExecutor#safelySafe(String, SafeRunnable)
*/
@FunctionalInterface
public interface SafeRunnable {
/**
* Executes the operation, potentially throwing a checked exception.
*
* @throws Exception if the operation fails
*/
void run() throws Exception;
/**
* Converts this SafeRunnable to a standard Runnable.
* Any checked exceptions are wrapped in {@link SafeException}.
*
* @return a Runnable that wraps checked exceptions
*/
default Runnable toRunnable() {
return () -> {
try {
run();
} catch (Exception e) {
throw SafeException.wrap(e);
}
};
}
/**
* Creates a SafeRunnable from a standard Runnable.
*
* @param runnable the Runnable to wrap
* @return a SafeRunnable that delegates to the Runnable
*/
static SafeRunnable from(Runnable runnable) {
return runnable::run;
}
/**
* Executes this SafeRunnable, wrapping any exception.
* Convenience method for immediate execution.
*
* @throws SafeException if execution fails
*/
default void execute() {
toRunnable().run();
}
}