22
22
import java .util .List ;
23
23
import java .util .concurrent .atomic .AtomicBoolean ;
24
24
import java .util .concurrent .atomic .AtomicReference ;
25
+ import java .util .function .BiConsumer ;
25
26
import java .util .function .Consumer ;
26
27
import java .util .function .Supplier ;
27
28
@@ -115,6 +116,15 @@ below, SHOULD be used (for consistency, and ease of comparison/review).
115
116
async (1 , c );
116
117
}).finish (callback );
117
118
});
119
+ /*
120
+ Code review checklist for async code:
121
+
122
+ 1. Is everything inside the boilerplate?
123
+ 2. Is "callback" supplied to "finish"?
124
+ 3. In each block and nested block, is that same block's "c" always passed/completed at the end of execution?
125
+ 4. Is any c.complete followed by a return, to end execution?
126
+ 5. Do any sync methods still need to be converted to async?
127
+ */
118
128
}
119
129
120
130
@ Test
@@ -610,10 +620,11 @@ void testTryCatchWithVariables() {
610
620
611
621
@ Test
612
622
void testTryCatchWithConditionInCatch () {
613
- assertBehavesSameVariations (8 ,
623
+ assertBehavesSameVariations (12 ,
614
624
() -> {
615
625
try {
616
626
sync (plainTest (0 ) ? 1 : 2 );
627
+ sync (3 );
617
628
} catch (Throwable t ) {
618
629
sync (5 );
619
630
if (t .getMessage ().equals ("exception-1" )) {
@@ -626,6 +637,8 @@ void testTryCatchWithConditionInCatch() {
626
637
(callback ) -> {
627
638
beginAsync ().thenRun (c -> {
628
639
async (plainTest (0 ) ? 1 : 2 , c );
640
+ }).thenRun (c -> {
641
+ async (3 , c );
629
642
}).onErrorIf (t -> true , (t , c ) -> {
630
643
beginAsync ().thenRun (c2 -> {
631
644
async (5 , c2 );
@@ -793,6 +806,94 @@ void testInvalid() {
793
806
});
794
807
}
795
808
809
+ @ Test
810
+ void testDerivation () {
811
+ // Demonstrates the progression from nested async to the API.
812
+
813
+ // Stand-ins for sync-async methods; these "happily" do not throw
814
+ // exceptions, to avoid complicating this demo async code.
815
+ Consumer <Integer > happySync = (i ) -> {
816
+ invocationTracker .getNextOption (1 );
817
+ listener .add ("affected-success-" + i );
818
+ };
819
+ BiConsumer <Integer , SingleResultCallback <Void >> happyAsync = (i , c ) -> {
820
+ happySync .accept (i );
821
+ c .complete ();
822
+ };
823
+
824
+ // Standard nested async, no error handling:
825
+ assertBehavesSameVariations (1 ,
826
+ () -> {
827
+ happySync .accept (1 );
828
+ happySync .accept (2 );
829
+ },
830
+ (callback ) -> {
831
+ happyAsync .accept (1 , (v , e ) -> {
832
+ happyAsync .accept (2 , callback );
833
+ });
834
+ });
835
+
836
+ // When both methods are naively extracted, they are out of order:
837
+ assertBehavesSameVariations (1 ,
838
+ () -> {
839
+ happySync .accept (1 );
840
+ happySync .accept (2 );
841
+ },
842
+ (callback ) -> {
843
+ SingleResultCallback <Void > second = (v , e ) -> {
844
+ happyAsync .accept (2 , callback );
845
+ };
846
+ SingleResultCallback <Void > first = (v , e ) -> {
847
+ happyAsync .accept (1 , second );
848
+ };
849
+ first .onResult (null , null );
850
+ });
851
+
852
+ // We create an "AsyncRunnable" that takes a callback, which
853
+ // decouples any async methods from each other, allowing them
854
+ // to be declared in a sync-like order, and without nesting:
855
+ assertBehavesSameVariations (1 ,
856
+ () -> {
857
+ happySync .accept (1 );
858
+ happySync .accept (2 );
859
+ },
860
+ (callback ) -> {
861
+ AsyncRunnable first = (SingleResultCallback <Void > c ) -> {
862
+ happyAsync .accept (1 , c );
863
+ };
864
+ AsyncRunnable second = (SingleResultCallback <Void > c ) -> {
865
+ happyAsync .accept (2 , c );
866
+ };
867
+ // This is a simplified variant of the "then" methods;
868
+ // it has no error handling. It takes methods A and B,
869
+ // and returns C, which is B(A()).
870
+ AsyncRunnable combined = (c ) -> {
871
+ first .unsafeFinish ((r , e ) -> {
872
+ second .unsafeFinish (c );
873
+ });
874
+ };
875
+ combined .unsafeFinish (callback );
876
+ });
877
+
878
+ // This combining method is added as a default method on AsyncRunnable,
879
+ // and a "finish" method wraps the resulting methods. This also adds
880
+ // exception handling and monadic short-circuiting of ensuing methods
881
+ // when an exception arises (comparable to how thrown exceptions "skip"
882
+ // ensuing code).
883
+ assertBehavesSameVariations (3 ,
884
+ () -> {
885
+ sync (1 );
886
+ sync (2 );
887
+ },
888
+ (callback ) -> {
889
+ beginAsync ().thenRun (c -> {
890
+ async (1 , c );
891
+ }).thenRun (c -> {
892
+ async (2 , c );
893
+ }).finish (callback );
894
+ });
895
+ }
896
+
796
897
// invoked methods:
797
898
798
899
private void plain (final int i ) {
0 commit comments