Skip to content

Commit b23fb09

Browse files
authored
Add ThrowingRunnable alongside ThrowingSupplier et al
Signed-off-by: Hosam Aly <[email protected]>
1 parent 75e3f44 commit b23fb09

File tree

1 file changed

+120
-0
lines changed

1 file changed

+120
-0
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright 2002-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.util.function;
18+
19+
import java.util.function.BiFunction;
20+
21+
/**
22+
* A {@link Runnable} that allows invocation of code that throws a checked exception.
23+
*
24+
* @author Hosam Aly
25+
*/
26+
public interface ThrowingRunnable extends Runnable {
27+
28+
/**
29+
* Gets a result, possibly throwing a checked exception.
30+
* @throws Exception on error
31+
*/
32+
void runWithException() throws Exception;
33+
34+
/**
35+
* Default {@link Runnable#run()} that wraps any thrown checked exceptions
36+
* (by default in a {@link RuntimeException}).
37+
* @see java.lang.Runnable#run()
38+
*/
39+
@Override
40+
default void run() {
41+
run(RuntimeException::new);
42+
}
43+
44+
/**
45+
* Gets a result, wrapping any thrown checked exceptions using the given
46+
* {@code exceptionWrapper}.
47+
* @param exceptionWrapper {@link BiFunction} that wraps the given message
48+
* and checked exception into a runtime exception
49+
*/
50+
default void run(BiFunction<String, Exception, RuntimeException> exceptionWrapper) {
51+
try {
52+
runWithException();
53+
} catch (RuntimeException ex) {
54+
throw ex;
55+
} catch (Exception ex) {
56+
throw exceptionWrapper.apply(ex.getMessage(), ex);
57+
}
58+
}
59+
60+
/**
61+
* Return a new {@link ThrowingRunnable} where the {@link #run()} method
62+
* wraps any thrown checked exceptions using the given
63+
* {@code exceptionWrapper}.
64+
* @param exceptionWrapper {@link BiFunction} that wraps the given message
65+
* and checked exception into a runtime exception
66+
* @return the replacement {@link ThrowingRunnable} instance
67+
*/
68+
default ThrowingRunnable throwing(BiFunction<String, Exception, RuntimeException> exceptionWrapper) {
69+
return new ThrowingRunnable() {
70+
@Override
71+
public void runWithException() throws Exception {
72+
ThrowingRunnable.this.runWithException();
73+
}
74+
75+
@Override
76+
public void run() {
77+
run(exceptionWrapper);
78+
}
79+
};
80+
}
81+
82+
/**
83+
* Lambda friendly convenience method that can be used to create a
84+
* {@link ThrowingRunnable} where the {@link #run()} method wraps any checked
85+
* exception thrown by the supplied lambda expression or method reference.
86+
* <p>This method can be especially useful when working with method references.
87+
* It allows you to easily convert a method that throws a checked exception
88+
* into an instance compatible with a regular {@link Runnable}.
89+
* <p>For example:
90+
* <pre class="code">
91+
* optional.orElseGet(ThrowingRunnable.of(Example::methodThatCanThrowCheckedException));
92+
* </pre>
93+
* @param runnable the source runnable
94+
* @return a new {@link ThrowingRunnable} instance
95+
*/
96+
static ThrowingRunnable of(ThrowingRunnable runnable) {
97+
return runnable;
98+
}
99+
100+
/**
101+
* Lambda friendly convenience method that can be used to create
102+
* {@link ThrowingRunnable} where the {@link #run()} method wraps any
103+
* thrown checked exceptions using the given {@code exceptionWrapper}.
104+
* <p>This method can be especially useful when working with method references.
105+
* It allows you to easily convert a method that throws a checked exception
106+
* into an instance compatible with a regular {@link Runnable}.
107+
* <p>For example:
108+
* <pre class="code">
109+
* optional.orElseGet(ThrowingRunnable.of(Example::methodThatCanThrowCheckedException, IllegalStateException::new));
110+
* </pre>
111+
* @param runnable the source runnable
112+
* @param exceptionWrapper the exception wrapper to use
113+
* @return a new {@link ThrowingRunnable} instance
114+
*/
115+
static ThrowingRunnable of(
116+
ThrowingRunnable runnable, BiFunction<String, Exception, RuntimeException> exceptionWrapper) {
117+
118+
return runnable.throwing(exceptionWrapper);
119+
}
120+
}

0 commit comments

Comments
 (0)