Skip to content

Commit 79dd5a7

Browse files
authored
refactor: Eliminate Optional from fields and parameters for async method invocation (#2830)
1 parent 846dea2 commit 79dd5a7

6 files changed

Lines changed: 53 additions & 47 deletions

File tree

async-method-invocation/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ public interface AsyncResult<T> {
5757

5858
```java
5959
public interface AsyncCallback<T> {
60-
void onComplete(T value, Optional<Exception> ex);
60+
void onComplete(T value);
61+
void onError(Exception ex);
6162
}
6263
```
6364

async-method-invocation/etc/async-method-invocation.urm.puml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ package com.iluwatar.async.method.invocation {
99
+ main(args : String[]) {static}
1010
}
1111
interface AsyncCallback<T> {
12-
+ onComplete(T, Optional<Exception>) {abstract}
12+
+ onComplete(T) {abstract}
13+
+ onError(Exception) {abstract}
1314
}
1415
interface AsyncExecutor {
1516
+ endProcess(AsyncResult<T>) : T {abstract}
@@ -32,20 +33,23 @@ package com.iluwatar.async.method.invocation {
3233
~ COMPLETED : int {static}
3334
~ FAILED : int {static}
3435
~ RUNNING : int {static}
35-
~ callback : Optional<AsyncCallback<T>>
36+
~ callback : AsyncCallback<T>
3637
~ exception : Exception
3738
~ lock : Object
3839
~ state : int
3940
~ value : T
4041
~ CompletableResult<T>(callback : AsyncCallback<T>)
4142
+ await()
4243
+ getValue() : T
44+
~ hasCallback() : boolean
4345
+ isCompleted() : boolean
4446
~ setException(exception : Exception)
4547
~ setValue(value : T)
4648
}
4749
}
50+
ThreadAsyncExecutor ..|> AsyncCallback
51+
ThreadAsyncExecutor ..|> AsyncResult
52+
ThreadAsyncExecutor ..|> AsyncExecutor
4853
CompletableResult ..+ ThreadAsyncExecutor
49-
ThreadAsyncExecutor ..|> AsyncExecutor
50-
CompletableResult ..|> AsyncResult
51-
@enduml
54+
CompletableResult ..|> AsyncResult
55+
@enduml

async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,16 @@ private static <T> Callable<T> lazyval(T value, long delayMillis) {
118118
* @return new async callback
119119
*/
120120
private static <T> AsyncCallback<T> callback(String name) {
121-
return (value, ex) -> {
122-
if (ex.isPresent()) {
123-
log(name + " failed: " + ex.map(Exception::getMessage).orElse(""));
124-
} else {
121+
return new AsyncCallback<>() {
122+
@Override
123+
public void onComplete(T value) {
125124
log(name + " <" + value + ">");
126125
}
126+
127+
@Override
128+
public void onError(Exception ex) {
129+
log(name + " failed: " + ex.getMessage());
130+
}
127131
};
128132
}
129133

async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncCallback.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
*/
2525
package com.iluwatar.async.method.invocation;
2626

27-
import java.util.Optional;
28-
2927
/**
3028
* AsyncCallback interface.
3129
*
@@ -34,10 +32,16 @@
3432
public interface AsyncCallback<T> {
3533

3634
/**
37-
* Complete handler which is executed when async task is completed or fails execution.
35+
* Complete handler which is executed when async task is completed.
36+
*
37+
* @param value the evaluated value from async task
38+
*/
39+
void onComplete(T value);
40+
41+
/**
42+
* Error handler which is executed when async task fails execution.
3843
*
39-
* @param value the evaluated value from async task, undefined when execution fails
40-
* @param ex empty value if execution succeeds, some exception if executions fails
44+
* @param ex exception which was thrown during async task execution(non-null)
4145
*/
42-
void onComplete(T value, Optional<Exception> ex);
46+
void onError(Exception ex);
4347
}

async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,19 @@ private static class CompletableResult<T> implements AsyncResult<T> {
8181
static final int COMPLETED = 3;
8282

8383
final Object lock;
84-
final Optional<AsyncCallback<T>> callback;
84+
final AsyncCallback<T> callback;
8585

8686
volatile int state = RUNNING;
8787
T value;
8888
Exception exception;
8989

9090
CompletableResult(AsyncCallback<T> callback) {
9191
this.lock = new Object();
92-
this.callback = Optional.ofNullable(callback);
92+
this.callback = callback;
93+
}
94+
95+
boolean hasCallback() {
96+
return callback != null;
9397
}
9498

9599
/**
@@ -101,7 +105,9 @@ private static class CompletableResult<T> implements AsyncResult<T> {
101105
void setValue(T value) {
102106
this.value = value;
103107
this.state = COMPLETED;
104-
this.callback.ifPresent(ac -> ac.onComplete(value, Optional.empty()));
108+
if (hasCallback()) {
109+
callback.onComplete(value);
110+
}
105111
synchronized (lock) {
106112
lock.notifyAll();
107113
}
@@ -116,7 +122,9 @@ void setValue(T value) {
116122
void setException(Exception exception) {
117123
this.exception = exception;
118124
this.state = FAILED;
119-
this.callback.ifPresent(ac -> ac.onComplete(null, Optional.of(exception)));
125+
if (hasCallback()) {
126+
callback.onError(exception);
127+
}
120128
synchronized (lock) {
121129
lock.notifyAll();
122130
}

async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,8 @@
2525
package com.iluwatar.async.method.invocation;
2626

2727
import static java.time.Duration.ofMillis;
28-
import static org.junit.jupiter.api.Assertions.assertEquals;
29-
import static org.junit.jupiter.api.Assertions.assertFalse;
30-
import static org.junit.jupiter.api.Assertions.assertNotNull;
31-
import static org.junit.jupiter.api.Assertions.assertSame;
32-
import static org.junit.jupiter.api.Assertions.assertTimeout;
33-
import static org.junit.jupiter.api.Assertions.assertTrue;
34-
import static org.junit.jupiter.api.Assertions.fail;
35-
import static org.mockito.ArgumentMatchers.eq;
36-
import static org.mockito.ArgumentMatchers.isNull;
28+
import static org.junit.jupiter.api.Assertions.*;
29+
import static org.mockito.ArgumentMatchers.*;
3730
import static org.mockito.Mockito.timeout;
3831
import static org.mockito.Mockito.verify;
3932
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -58,7 +51,7 @@
5851
class ThreadAsyncExecutorTest {
5952

6053
@Captor
61-
private ArgumentCaptor<Optional<Exception>> optionalCaptor;
54+
private ArgumentCaptor<Exception> exceptionCaptor;
6255

6356
@Mock
6457
private Callable<Object> task;
@@ -118,11 +111,8 @@ void testSuccessfulTaskWithCallback() {
118111
verify(task, times(1)).call();
119112

120113
// ... same for the callback, we expect our object
121-
verify(callback, times(1)).onComplete(eq(result), optionalCaptor.capture());
122-
123-
final var optionalException = optionalCaptor.getValue();
124-
assertNotNull(optionalException);
125-
assertFalse(optionalException.isPresent());
114+
verify(callback, times(1)).onComplete(eq(result));
115+
verify(callback, times(0)).onError(exceptionCaptor.capture());
126116

127117
// ... and the result should be exactly the same object
128118
assertSame(result, asyncResult.getValue());
@@ -200,11 +190,8 @@ void testLongRunningTaskWithCallback() {
200190

201191
// Our task should only execute once, but it can take a while ...
202192
verify(task, timeout(3000).times(1)).call();
203-
verify(callback, timeout(3000).times(1)).onComplete(eq(result), optionalCaptor.capture());
204-
205-
final var optionalException = optionalCaptor.getValue();
206-
assertNotNull(optionalException);
207-
assertFalse(optionalException.isPresent());
193+
verify(callback, timeout(3000).times(1)).onComplete(eq(result));
194+
verify(callback, times(0)).onError(isA(Exception.class));
208195

209196
// Prevent timing issues, and wait until the result is available
210197
asyncResult.await();
@@ -295,14 +282,12 @@ void testNullTaskWithCallback() {
295282
assertNotNull(asyncResult, "The AsyncResult should not be 'null', even though the task was 'null'.");
296283
asyncResult.await(); // Prevent timing issues, and wait until the result is available
297284
assertTrue(asyncResult.isCompleted());
298-
verify(callback, times(1)).onComplete(isNull(), optionalCaptor.capture());
285+
verify(callback, times(0)).onComplete(any());
286+
verify(callback, times(1)).onError(exceptionCaptor.capture());
299287

300-
final var optionalException = optionalCaptor.getValue();
301-
assertNotNull(optionalException);
302-
assertTrue(optionalException.isPresent());
303-
304-
final var exception = optionalException.get();
288+
final var exception = exceptionCaptor.getValue();
305289
assertNotNull(exception);
290+
306291
assertEquals(NullPointerException.class, exception.getClass());
307292

308293
try {
@@ -347,4 +332,4 @@ void testNullTaskWithNullCallback() {
347332

348333
}
349334

350-
}
335+
}

0 commit comments

Comments
 (0)