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