Skip to content

Commit 886a226

Browse files
feat: Added Defer
1 parent 8293867 commit 886a226

1 file changed

Lines changed: 86 additions & 0 deletions

File tree

src/main/java/gentle/Defer.java

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package gentle;
2+
3+
import lombok.AccessLevel;
4+
import lombok.NoArgsConstructor;
5+
import lombok.NonNull;
6+
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
10+
/**
11+
* A scoped defer stack, similar to the <code>defer</code> statement in Go.
12+
* <p>
13+
* <code>Defer</code> allows registering cleanup actions that are executed
14+
* automatically when the scope is exited (via {@link #close()}), typically by
15+
* using a {@code try}-with-resources block.
16+
*
17+
* <p>Deferred actions are executed in <strong>reverse order</strong> of registration,
18+
* ensuring proper cleanup behavior (LIFO).
19+
*
20+
* <p>Example:
21+
* <pre>{@code
22+
* try (Defer d = Defer.create()) {
23+
* d.defer(() -> System.out.println("cleanup 1"));
24+
* d.defer(() -> System.out.println("cleanup 2"));
25+
* System.out.println("doing work");
26+
* }
27+
*
28+
* // Output:
29+
* // doing work
30+
* // cleanup 2
31+
* // cleanup 1
32+
* }</pre>
33+
*
34+
* <p><strong>Error Handling:</strong><br>
35+
* If deferred actions throw exceptions, they are caught and suppressed silently.
36+
* This ensures that all cleanup actions are attempted.
37+
*/
38+
@NoArgsConstructor (access = AccessLevel.PRIVATE)
39+
public final class Defer implements AutoCloseable {
40+
/**
41+
* The stack of deferred actions.
42+
* Executed in reverse order when {@link #close()} is called.
43+
*/
44+
private final List<Runnable> stack = new ArrayList<>();
45+
46+
/**
47+
* Creates a new, empty defer stack.
48+
* <p>
49+
* Intended to be used with {@code try}-with-resources:
50+
* <pre>{@code
51+
* try (Defer d = Defer.create()) {
52+
* ...
53+
* }
54+
* }</pre>
55+
*
56+
* @return a new {@link Defer} instance
57+
*/
58+
public static Defer create() {
59+
return new Defer();
60+
}
61+
62+
/**
63+
* Registers a new action to be executed when this {@code Defer} is closed.
64+
* The action will be executed after all previously registered actions.
65+
*
66+
* @param r the action to defer
67+
*/
68+
public void defer(@NonNull Runnable r) {
69+
stack.add(r);
70+
}
71+
72+
/**
73+
* Executes all deferred actions in reverse order.
74+
* <p>
75+
* Any exceptions thrown by deferred actions are caught and ignored, allowing
76+
* all actions to run regardless of failures.
77+
*/
78+
@Override
79+
public void close() {
80+
for (int i = stack.size() - 1; i >= 0; i--) {
81+
try {
82+
stack.get(i).run();
83+
} catch (Exception _) {}
84+
}
85+
}
86+
}

0 commit comments

Comments
 (0)