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 .function .BiConsumer ;
10
+ import java .util .function .Consumer ;
11
+ import java .util .stream .Stream ;
12
+
13
+ /**
14
+ * Mix of {@link Tuple2}, {@link Optional} and {@link Callable}
15
+ * to represent (potentially failed to acquire) "optional" result in functional (Stream API) chain.
16
+ * <br>
17
+ * {@link #v1} - nullable returned value<br>
18
+ * {@link #v2} - {@link Throwable} in case of failure (null otherwise)
19
+ *
20
+ * @param <T> the type of value
21
+ *
22
+ * @author Andrej Fink
23
+ */
24
+ public class Either <T > extends Tuple2 <T ,Throwable > implements Callable <T > {
25
+
26
+ private static final Either <?> EMPTY = new Either <>(null ,null );
27
+
28
+ public static <T > Either <T > empty () {
29
+ return Wrap .castUnsafe (EMPTY );
30
+ }
31
+
32
+
33
+ /** Return this Either as {@link Optional} */
34
+ public Optional <T > optValue () {
35
+ return Optional .ofNullable (v1 );
36
+ }
37
+
38
+ public Optional <Throwable > optThrowable () {
39
+ return Optional .ofNullable (v2 );
40
+ }
41
+
42
+ /*@Nullable*/ public Object either () {
43
+ return v2 != null ? v2 : v1 ;
44
+ }
45
+
46
+ // Callable
47
+
48
+ @ Override @ SuppressWarnings ("RedundantThrows" )
49
+ /*@Nullable*/ public T call () throws Exception {
50
+ if (v2 != null ) {
51
+ SeqUtils .sneakyThrow (v2 );// throws Exception or Error!
52
+ }
53
+ return v1 ;
54
+ }//Callable.call
55
+
56
+
57
+ // creation
58
+
59
+ private Either (T nullableValue , Throwable nullableThrowable ) {
60
+ super (nullableValue , nullableThrowable );
61
+ }//new
62
+
63
+
64
+ public static <T > Either <T > success (/*@Nullable*/ T value ) {
65
+ return new Either <>(value , null );
66
+ }
67
+
68
+ public static <T > Either <T > failure (Throwable t ) {
69
+ return new Either <>(null , Objects .requireNonNull (t ));
70
+ }
71
+
72
+
73
+ public boolean isSuccess () {
74
+ return v2 == null ;
75
+ }
76
+
77
+ public boolean isFailure () {
78
+ return v2 != null ;
79
+ }
80
+
81
+ /**
82
+ * If a value is present (success and not empty), returns {@code true}, otherwise {@code false}.
83
+ *
84
+ * @return {@code true} if a value is present, otherwise {@code false}
85
+ */
86
+ public boolean isPresent () {
87
+ return isSuccess () && v1 != null ;
88
+ }
89
+
90
+ /**
91
+ * If a value is not present (failure or null), returns {@code true}, otherwise {@code false}.
92
+ *
93
+ * @return {@code true} if a value is not present, otherwise {@code false}
94
+ */
95
+ public boolean isEmpty () {
96
+ return isFailure () || v1 == null ;
97
+ }
98
+
99
+ /** Success, but null */
100
+ public boolean isNull () {
101
+ return isSuccess () && v1 == null ;
102
+ }
103
+
104
+
105
+ public Either <T > throwIfFailure () throws IllegalStateException {
106
+ if (isFailure ()) {
107
+ throw new IllegalStateException ("Throwable instead of value" , v2 );
108
+ }
109
+ return this ;
110
+ }
111
+
112
+ public Either <T > throwIfEmpty () throws IllegalStateException , NoSuchElementException {
113
+ if (isFailure ()) {
114
+ throw new IllegalStateException ("Throwable instead of value" , v2 );
115
+ } else if (v1 == null ) {
116
+ throw new NoSuchElementException ("No value present" );
117
+ }
118
+ return this ;
119
+ }
120
+
121
+ public Either <T > throwIfNull () throws NoSuchElementException {
122
+ if (isNull ()) {
123
+ throw new NoSuchElementException ("No value present" );
124
+ }
125
+ return this ;
126
+ }
127
+
128
+
129
+ public Either <T > ifPresent (Consumer </*@Nullable*/ ? super T > action ) {
130
+ if (isPresent ()) {
131
+ action .accept (v1 );
132
+ }
133
+ return this ;
134
+ }
135
+
136
+
137
+ public Either <T > ifNull (Runnable nullAction ) {
138
+ if (isNull ()) {
139
+ nullAction .run ();
140
+ }
141
+ return this ;
142
+ }
143
+
144
+ public Either <T > ifEmpty (Consumer </*@Nullable*/ Throwable > failureOrNullAction ) {
145
+ if (isEmpty ()) {
146
+ failureOrNullAction .accept (v2 );
147
+ }
148
+ return this ;
149
+ }
150
+
151
+ public Either <T > ifSuccess (Consumer </*@Nullable*/ ? super T > nullSafeAction ) {
152
+ if (isSuccess ()) {
153
+ nullSafeAction .accept (v1 );
154
+ }
155
+ return this ;
156
+ }
157
+
158
+
159
+ public Either <T > ifFailure (Consumer <Throwable > failureAction ) {
160
+ if (isFailure ()) {
161
+ failureAction .accept (v2 );
162
+ }
163
+ return this ;
164
+ }
165
+
166
+
167
+ public void consume (BiConsumer </*@Nullable*/ ? super T ,Throwable > consumer ) {
168
+ consumer .accept (v1 , v2 );
169
+ }
170
+
171
+
172
+ /**
173
+ * If a value is present, returns a sequential {@link Stream} containing
174
+ * only that value, otherwise returns an empty {@code Stream}.
175
+ * <p>
176
+ * This method can be used to transform a {@code Stream} of optional
177
+ * elements to a {@code Stream} of present value elements:
178
+ * <pre>{@code
179
+ * Stream<Optional<T>> os = ..
180
+ * Stream<T> s = os.flatMap(Optional::stream)
181
+ * }</pre>
182
+ *
183
+ * @return the optional value as a {@code Stream}
184
+ */
185
+ public Stream <T > stream () {
186
+ if (isEmpty ()) {
187
+ return Stream .empty ();
188
+ } else {
189
+ return Stream .of (v1 );
190
+ }
191
+ }
192
+
193
+
194
+ @ Override
195
+ public boolean equals (Object obj ) {
196
+ if (this == obj ) {
197
+ return true ;
198
+ }
199
+
200
+ if (obj instanceof Tuple2 <?,?>) {
201
+ Tuple2 <?,?> o = (Tuple2 <?,?>) obj ;
202
+ return Objects .equals (v1 , o .v1 ) && Objects .equals (v2 , o .v2 );
203
+
204
+ } else if (isSuccess () && obj instanceof Optional <?>) {
205
+ Optional <?> o = (Optional <?>) obj ;
206
+ return Objects .equals (v1 , o ) || Objects .equals (v1 , o .orElse (null ));
207
+
208
+ } else if (isSuccess ()) {
209
+ return Objects .equals (v1 , obj );
210
+
211
+ } else if (isFailure () && obj instanceof Throwable ) {
212
+ return Objects .equals (v2 , obj );
213
+ }
214
+ return false ;
215
+ }
216
+
217
+
218
+ /**
219
+ * Returns a non-empty string representation of this {@code Either}
220
+ * suitable for debugging.
221
+ *
222
+ * @return the string representation of this instance
223
+ */
224
+ @ Override public String toString () {
225
+ if (isFailure ()) {
226
+ return "Either.Failure(" + v2 +')' ;
227
+
228
+ } else if (isPresent ()) {
229
+ return "Either(" + v1 +')' ;
230
+ }
231
+ return "Either.Empty" ;
232
+ }
233
+ }
0 commit comments