1
+ package org .jooq .lambda ;
2
+
3
+ import org .jooq .lambda .tuple .Tuple2 ;
4
+
5
+ import java .util .NoSuchElementException ;
6
+ import java .util .Objects ;
7
+ import java .util .Optional ;
8
+ import java .util .concurrent .Callable ;
9
+ import java .util .concurrent .ExecutionException ;
10
+ import java .util .concurrent .Future ;
11
+ import java .util .concurrent .RunnableFuture ;
12
+ import java .util .concurrent .TimeUnit ;
13
+ import java .util .function .BiConsumer ;
14
+ import java .util .function .BiFunction ;
15
+ import java .util .function .Consumer ;
16
+ import java .util .function .Supplier ;
17
+ import java .util .stream .Stream ;
18
+
19
+ /**
20
+ * Mix of {@link Optional}, {@link Callable}, {@link Tuple2} and {@link Future}
21
+ * to represent (potentially failed to acquire) "optional" result.
22
+ *
23
+ * @param <T> the type of value
24
+ */
25
+ @ SuppressWarnings ("OptionalUsedAsFieldOrParameterType" )
26
+ public final class Either <T > implements Callable <T >, Supplier <T > {
27
+
28
+ private final Optional <T > value ;
29
+ private final Throwable throwable ;
30
+
31
+
32
+ /** Return this Either as {@link Optional} */
33
+ public Optional <T > optional () {
34
+ return value ;
35
+ }
36
+
37
+ /*@Nullable*/ public Throwable throwable () {
38
+ return throwable ;
39
+ }
40
+
41
+ public Tuple2 <T ,Throwable > tuple () {
42
+ return new Tuple2 <>(value .orElse (null ), throwable );
43
+ }
44
+
45
+ public Tuple2 <Optional <T >,Throwable > optTuple () {
46
+ return new Tuple2 <>(value , throwable );
47
+ }
48
+
49
+ // Callable
50
+
51
+ @ Override @ SuppressWarnings ("RedundantThrows" )
52
+ /*@Nullable*/ public T call () throws Exception {
53
+ if (throwable != null ) {
54
+ SeqUtils .sneakyThrow (throwable );// throws Exception or Error!
55
+ }
56
+ return value .orElse (null );
57
+ }//Callable.call
58
+
59
+ @ SuppressWarnings ("RedundantThrows" )
60
+ public Optional <T > optCall () throws Exception {
61
+ if (throwable != null ) {
62
+ SeqUtils .sneakyThrow (throwable );// throws Exception or Error!
63
+ }
64
+ return value ;
65
+ }
66
+
67
+ // Supplier
68
+
69
+ @ Override
70
+ public T get () throws IllegalStateException , NoSuchElementException {
71
+ if (throwable != null ) {
72
+ throw new IllegalStateException ("Throwable instead of value" , throwable );
73
+
74
+ } else if (value .isEmpty ()) {
75
+ throw new NoSuchElementException ("No value present" );
76
+ }
77
+ return value .get ();
78
+ }//Supplier.get
79
+
80
+ // creation
81
+
82
+ private Either (Optional <T > nonNullOptionalAsValue , Throwable nullableThrowable ) {
83
+ value = nonNullOptionalAsValue ;
84
+ throwable = nullableThrowable ;
85
+ }//new
86
+
87
+
88
+ public static <T > Either <T > success (T value ) {
89
+ return new Either <>(Optional .ofNullable (value ), null );
90
+ }
91
+
92
+ public static <T > Either <T > success (Optional <T > optValue ) {
93
+ return new Either <>(optValue , null );
94
+ }
95
+
96
+ public static <T > Either <T > failure (Throwable t ) {
97
+ return new Either <>(Optional .empty (), Objects .requireNonNull (t ));
98
+ }
99
+
100
+ //
101
+
102
+ public boolean isSuccess () {
103
+ return throwable == null ;
104
+ }
105
+
106
+ public boolean isFailure () {
107
+ return throwable != null ;
108
+ }
109
+
110
+ /**
111
+ * If a value is present (success and not empty), returns {@code true}, otherwise {@code false}.
112
+ *
113
+ * @return {@code true} if a value is present, otherwise {@code false}
114
+ */
115
+ public boolean isPresent () {
116
+ return isSuccess () && value .isPresent ();
117
+ }
118
+
119
+ /**
120
+ * If a value is not present (failure or null), returns {@code true}, otherwise {@code false}.
121
+ *
122
+ * @return {@code true} if a value is not present, otherwise {@code false}
123
+ */
124
+ public boolean isEmpty () {
125
+ return isFailure () || value .isEmpty ();
126
+ }
127
+
128
+ /** Success, but null */
129
+ public boolean isNull () {
130
+ return isSuccess () && value .isEmpty ();
131
+ }
132
+
133
+
134
+ public Either <T > throwIfFailure () throws IllegalStateException {
135
+ if (isFailure ()) {
136
+ throw new IllegalStateException ("Throwable instead of value" , throwable );
137
+ }
138
+ return this ;
139
+ }
140
+
141
+ public Either <T > throwIfEmpty () throws IllegalStateException , NoSuchElementException {
142
+ if (isFailure ()) {
143
+ throw new IllegalStateException ("Throwable instead of value" , throwable );
144
+ } else if (value .isEmpty ()) {
145
+ throw new NoSuchElementException ("No value present" );
146
+ }
147
+ return this ;
148
+ }
149
+
150
+ public Either <T > throwIfNull () throws NoSuchElementException {
151
+ if (isNull ()) {
152
+ throw new NoSuchElementException ("No value present" );
153
+ }
154
+ return this ;
155
+ }
156
+
157
+ public Either <T > optIfPresent (Consumer <Optional <? super T >> action ) {
158
+ if (isPresent ()) {
159
+ action .accept (value );
160
+ }
161
+ return this ;
162
+ }
163
+
164
+ public Optional <T > optIfPresent (Optional <T > elseValue ) {
165
+ if (isPresent ()) {
166
+ return value ;
167
+ }
168
+ return elseValue ;
169
+ }
170
+
171
+ public Either <T > ifPresent (Consumer <? super T > action ) {
172
+ if (isPresent ()) {
173
+ //noinspection OptionalGetWithoutIsPresent
174
+ action .accept (value .get ());
175
+ }
176
+ return this ;
177
+ }
178
+
179
+ public T ifPresent (T elseValue ) {
180
+ if (isPresent ()) {
181
+ //noinspection OptionalGetWithoutIsPresent
182
+ value .get ();
183
+ }
184
+ return elseValue ;
185
+ }
186
+
187
+
188
+ public Either <T > ifNull (Runnable nullAction ) {
189
+ if (isNull ()) {
190
+ nullAction .run ();
191
+ }
192
+ return this ;
193
+ }
194
+
195
+ public Either <T > ifEmpty (Runnable nullAction ) {
196
+ if (isEmpty ()) {
197
+ nullAction .run ();
198
+ }
199
+ return this ;
200
+ }
201
+
202
+ public Either <T > ifEmpty (Consumer <Throwable > failureOrNullAction ) {
203
+ if (isEmpty ()) {
204
+ failureOrNullAction .accept (throwable );
205
+ }
206
+ return this ;
207
+ }
208
+
209
+ public Either <T > ifSuccess (Consumer <? super T > nullSafeAction ) {
210
+ if (isSuccess ()) {
211
+ nullSafeAction .accept (value .orElse (null ));
212
+ }
213
+ return this ;
214
+ }
215
+
216
+ public T ifSuccess (T elseValue ) {
217
+ if (isSuccess ()) {
218
+ return value .orElse (null );
219
+ }
220
+ return elseValue ;
221
+ }
222
+
223
+ public Either <T > optIfSuccess (Consumer <Optional <? super T >> action ) {
224
+ if (isSuccess ()) {
225
+ action .accept (value );
226
+ }
227
+ return this ;
228
+ }
229
+
230
+ public Optional <T > optIfSuccess (Optional <T > elseValue ) {
231
+ if (isSuccess ()) {
232
+ return value ;
233
+ }
234
+ return elseValue ;
235
+ }
236
+
237
+ public Either <T > ifFailure (Consumer <Throwable > failureAction ) {
238
+ if (isFailure ()) {
239
+ failureAction .accept (throwable );
240
+ }
241
+ return this ;
242
+ }
243
+
244
+ public Optional <Throwable > ifFailure () {
245
+ return Optional .ofNullable (throwable );
246
+ }
247
+
248
+ public void consume (BiConsumer <? super T ,Throwable > consumer ) {
249
+ consumer .accept (value .orElse (null ), throwable );
250
+ }
251
+
252
+ public void optConsume (BiConsumer <Optional <? super T >,Throwable > consumer ) {
253
+ consumer .accept (value , throwable );
254
+ }
255
+
256
+ public <R > R map (BiFunction <? super T ,Throwable ,? extends R > fun ) {
257
+ return fun .apply (value .orElse (null ), throwable );
258
+ }
259
+
260
+ public <R > R optMap (BiFunction <Optional <? super T >,Throwable ,? extends R > fun ) {
261
+ return fun .apply (value , throwable );
262
+ }
263
+
264
+ /**
265
+ * If a value is present, returns a sequential {@link Stream} containing
266
+ * only that value, otherwise returns an empty {@code Stream}.
267
+ * <p>
268
+ * This method can be used to transform a {@code Stream} of optional
269
+ * elements to a {@code Stream} of present value elements:
270
+ * <pre>{@code
271
+ * Stream<Optional<T>> os = ..
272
+ * Stream<T> s = os.flatMap(Optional::stream)
273
+ * }</pre>
274
+ *
275
+ * @return the optional value as a {@code Stream}
276
+ */
277
+ public Stream <T > stream () {
278
+ if (isEmpty ()) {
279
+ return Stream .empty ();
280
+ } else {
281
+ //noinspection OptionalGetWithoutIsPresent
282
+ return Stream .of (value .get ());
283
+ }
284
+ }
285
+
286
+ public Stream <Optional <T >> optStream () {
287
+ if (isFailure ()) {
288
+ return Stream .empty ();
289
+ } else {
290
+ return Stream .of (value );
291
+ }
292
+ }
293
+
294
+
295
+ /**
296
+ * Indicates whether some other object is "equal to" this {@code Optional}.
297
+ * The other object is considered equal if:
298
+ * <ul>
299
+ * <li>it is also an {@code Optional} and;
300
+ * <li>both instances have no value present or;
301
+ * <li>the present values are "equal to" each other via {@code equals()}.
302
+ * </ul>
303
+ *
304
+ * @param obj an object to be tested for equality
305
+ * @return {@code true} if the other object is "equal to" this object
306
+ * otherwise {@code false}
307
+ */
308
+ @ Override
309
+ public boolean equals (Object obj ) {
310
+ if (this == obj ) {
311
+ return true ;
312
+ }
313
+
314
+ if (obj instanceof Either <?>) {
315
+ Either <?> o = (Either <?>) obj ;
316
+ return Objects .equals (value , o .value ) && Objects .equals (throwable , o .throwable );
317
+
318
+ } else if (obj instanceof Optional <?>) {
319
+ Optional <?> o = (Optional <?>) obj ;
320
+ return Objects .equals (value , o .orElse (null ));
321
+
322
+ } else if (obj instanceof Throwable ) {
323
+ Throwable o = (Throwable ) obj ;
324
+ return Objects .equals (throwable , o );
325
+ }
326
+
327
+ return false ;
328
+ }
329
+
330
+ /**
331
+ * Returns the hash code of the value, if present, otherwise {@code 0}
332
+ * (zero) if no value is present.
333
+ *
334
+ * @return hash code value of the present value or {@code 0} if no value is
335
+ * present
336
+ */
337
+ @ Override public int hashCode () {
338
+ return value .hashCode () ^ Objects .hashCode (throwable );
339
+ }
340
+
341
+ /**
342
+ * Returns a non-empty string representation of this {@code Either}
343
+ * suitable for debugging.
344
+ *
345
+ * @return the string representation of this instance
346
+ */
347
+ @ Override public String toString () {
348
+ if (isFailure ()) {
349
+ return "Either.Failure(" + throwable +')' ;
350
+
351
+ } else if (value .isPresent ()) {
352
+ return "Either(" + value .get () +')' ;
353
+ }
354
+ return "Either.Empty" ;
355
+ }
356
+
357
+ //java.util.concurrent.Future
358
+
359
+ public Future <T > future () {
360
+ return new RunnableFuture <>() {
361
+ @ Override public boolean isCancelled () {
362
+ return isFailure ();
363
+ }
364
+
365
+ @ Override public boolean isDone () {
366
+ return isSuccess ();
367
+ }
368
+
369
+ @ Override
370
+ /*@Nullable*/ public T get () throws InterruptedException , ExecutionException {
371
+ if (throwable instanceof InterruptedException ) {
372
+ throw (InterruptedException ) throwable ;
373
+ } else if (throwable != null ) {
374
+ throw new ExecutionException (throwable );
375
+ }
376
+ return value .orElse (null );
377
+ }
378
+
379
+ @ Override
380
+ /*@Nullable*/ public T get (long timeout , TimeUnit unit ) throws InterruptedException , ExecutionException {
381
+ return get ();
382
+ }
383
+
384
+ @ Override public boolean cancel (boolean mayInterruptIfRunning ) {
385
+ return false ; // NOOP
386
+ }
387
+
388
+ @ Override public void run () {}
389
+
390
+ @ Override public String toString () {
391
+ return Either .this + ".Future" ;
392
+ }
393
+ };
394
+ }
395
+
396
+ }
0 commit comments