1717 */
1818public final class Eithers {
1919
20- static final Set <Collector .Characteristics > CH_NOID = Set .of ();
20+ private static final Set <Collector .Characteristics > CH_NOID = Set .of ();
2121
22- private Eithers () {
22+ /**
23+ * Returns a {@code Collector} that accumulates the input elements into
24+ * a Right containing all values in the original order,
25+ * but only if there are no Left instances in the stream.
26+ * If the stream does contain a Left instance, it discards the Right instances and
27+ * accumulates a Left instance, which contains the first LHS value in the stream,
28+ * in encounter order.
29+ *
30+ * @param <L> the type of the LHS values in the stream
31+ * @param <R> the type of the RHS values in the stream
32+ * @return a {@code Collector} which collects all the input elements into
33+ * a Right containing all RHS values in the stream, or,
34+ * if an LHS value exists, a Left containing the first LHS value
35+ */
36+ public static <L , R >
37+ Collector <Either <? extends L , ? extends R >, ?, Either <L , List <R >>>
38+ firstFailure () {
39+
40+ BiConsumer <FirstFailureAcc <L , R >, Either <? extends L , ? extends R >> accumulator = (acc , either ) ->
41+ either .ifLeftOrElse (acc ::addLeft , acc ::addRight );
42+
43+ BinaryOperator <FirstFailureAcc <L , R >> combiner = (acc , other ) ->
44+ (FirstFailureAcc <L , R >) acc .combine (other );
45+
46+ return new CollectorImpl <>(FirstFailureAcc ::new , accumulator , combiner , FirstFailureAcc ::finish );
47+ }
48+
49+ /**
50+ * Returns a {@code Collector} that accumulates the input elements into
51+ * a Right containing all values in the original order,
52+ * but only if there are no Left instances in the stream.
53+ * If the stream does contain a Left instance, it discards the Right instances and
54+ * accumulates a Left containing only the LHS values,
55+ * in encounter order.
56+ *
57+ * @param <L> the type of the LHS values in the stream
58+ * @param <R> the type of the RHS values in the stream
59+ * @return a {@code Collector} which collects all the input elements into
60+ * a Right containing all RHS values in the stream,
61+ * or, if an LHS value exists, a Left containing a nonempty list
62+ * of all LHS values in the stream
63+ */
64+ public static <L , R >
65+ Collector <Either <? extends L , ? extends R >, ?, Either <List <L >, List <R >>>
66+ allFailures () {
67+
68+ BiConsumer <AllFailuresAcc <L , R >, Either <? extends L , ? extends R >> accumulator = (acc , either ) ->
69+ either .ifLeftOrElse (acc ::addLeft , acc ::addRight );
70+
71+ BinaryOperator <AllFailuresAcc <L , R >> combiner = (acc , other ) ->
72+ (AllFailuresAcc <L , R >) acc .combine (other );
73+
74+ return new CollectorImpl <>(AllFailuresAcc ::new , accumulator , combiner , AllFailuresAcc ::finish );
75+ }
76+
77+ /**
78+ * Returns a {@code Collector} that accumulates the input elements into
79+ * a new {@code List}. There are no guarantees on the type, mutability,
80+ * serializability, or thread-safety of the {@code List} returned.
81+ * The final list is wrapped in an {@code Optional},
82+ * which is empty if and only if the list is empty.
83+ *
84+ * @see #optionalList(List)
85+ * @param <T> the type of the input elements
86+ * @return a list of the RHS values in the stream,
87+ * or, if an LHS value exists, a nonempty list of all LHS values
88+ */
89+ public static <T > Collector <T , ?, Optional <List <T >>> toOptionalList () {
90+ return Collectors .collectingAndThen (
91+ Collectors .toList (),
92+ Eithers ::optionalList );
93+ }
94+
95+ /**
96+ * If the provided list is empty, returns an empty {@link Optional}.
97+ * Otherwise, returns an {@code Optional} containing the nonempty
98+ * input list.
99+ *
100+ * <p>Note: The resulting {@code Optional} might be used in a
101+ * {@link Either#filter(Function) filter} or
102+ * {@link Either#filterLeft(Function) filterLeft} operation.
103+ *
104+ * @see #toOptionalList()
105+ * @param values a list of objects
106+ * @param <T> the type of the members of {@code values}
107+ * @return an {@code Optional} which is either empty, or
108+ * contains a nonempty list
109+ */
110+ public static <T > Optional <List <T >> optionalList (List <? extends T > values ) {
111+ if (values .isEmpty ()) {
112+ return Optional .empty ();
113+ }
114+ @ SuppressWarnings ("unchecked" )
115+ List <T > result = (List <T >) values ;
116+ return Optional .of (result );
23117 }
24118
25119 /**
@@ -28,7 +122,7 @@ private Eithers() {
28122 * @param <T> the type of elements to be collected
29123 * @param <R> the type of the result
30124 */
31- private static class CollectorImpl <T , A , R > implements Collector <T , A , R > {
125+ private static final class CollectorImpl <T , A , R > implements Collector <T , A , R > {
32126 final Supplier <A > supplier ;
33127 final BiConsumer <A , T > accumulator ;
34128 final BinaryOperator <A > combiner ;
@@ -82,10 +176,12 @@ static abstract class Acc<L, C, R> {
82176 abstract void combineLeft (C otherLeft );
83177
84178 // nullable
85- abstract C left ();
179+ abstract C leftColl ();
180+
181+ abstract void addLeft (L left );
86182
87183 final void addRight (R value ) {
88- if (left () != null ) {
184+ if (leftColl () != null ) {
89185 return ;
90186 }
91187 if (right == null ) {
@@ -95,11 +191,11 @@ final void addRight(R value) {
95191 }
96192
97193 final Acc <L , C , R > combine (Acc <L , C , R > other ) {
98- if (left () != null ) {
99- combineLeft (other .left ());
194+ if (leftColl () != null ) {
195+ combineLeft (other .leftColl ());
100196 return this ;
101197 }
102- if (other .left () != null ) {
198+ if (other .leftColl () != null ) {
103199 return other ;
104200 }
105201 if (other .right == null ) {
@@ -114,33 +210,34 @@ final Acc<L, C, R> combine(Acc<L, C, R> other) {
114210 }
115211
116212 final Either <C , List <R >> finish () {
117- C left = left ();
213+ C left = leftColl ();
118214 return left != null
119215 ? Either .left (left )
120216 : Either .right (right == null ? List .of () : right );
121217 }
122218 }
123219
124- private static class ShortcuttingAcc <L , R > extends Acc <L , L , R > {
220+ private static final class FirstFailureAcc <L , R > extends Acc <L , L , R > {
125221 L left ;
126222
127223 @ Override
128224 void combineLeft (L otherLeft ) {
129225 addLeft (otherLeft );
130226 }
131227
228+ @ Override
132229 void addLeft (L value ) {
133230 if (left == null ) {
134231 left = value ;
135232 }
136233 }
137234
138- L left () {
235+ L leftColl () {
139236 return left ;
140237 }
141238 }
142239
143- private static class FullAcc <L , R > extends Acc <L , List <L >, R > {
240+ private static final class AllFailuresAcc <L , R > extends Acc <L , List <L >, R > {
144241 List <L > left ;
145242
146243 @ Override
@@ -152,6 +249,7 @@ void combineLeft(List<L> otherLeft) {
152249 }
153250 }
154251
252+ @ Override
155253 void addLeft (L value ) {
156254 if (left == null ) {
157255 left = new ArrayList <>();
@@ -160,101 +258,11 @@ void addLeft(L value) {
160258 }
161259
162260 @ Override
163- List <L > left () {
261+ List <L > leftColl () {
164262 return left ;
165263 }
166264 }
167265
168- /**
169- * Returns a {@code Collector} that accumulates the input elements into
170- * a Right containing all values in the original order,
171- * but only if there are no Left instances in the stream.
172- * If the stream does contain a Left instance, it discards the Right instances and
173- * accumulates a Left instance, which contains the first LHS value in the stream,
174- * in encounter order.
175- *
176- * @param <L> the type of the LHS values in the stream
177- * @param <R> the type of the RHS values in the stream
178- * @return a {@code Collector} which collects all the input elements into
179- * a Right containing all RHS values in the stream, or,
180- * if an LHS value exists, a Left containing the first LHS value
181- */
182- public static <L , R > Collector <Either <? extends L , ? extends R >, ?, Either <L , List <R >>> toValidList () {
183-
184- BiConsumer <ShortcuttingAcc <L , R >, Either <? extends L , ? extends R >> accumulate = (acc , either ) ->
185- either .ifLeftOrElse (acc ::addLeft , acc ::addRight );
186-
187- BinaryOperator <ShortcuttingAcc <L , R >> combine = (acc , other ) ->
188- (ShortcuttingAcc <L , R >) acc .combine (other );
189-
190- return new CollectorImpl <>(ShortcuttingAcc ::new , accumulate , combine , ShortcuttingAcc ::finish );
191- }
192-
193- /**
194- * Returns a {@code Collector} that accumulates the input elements into
195- * a Right containing all values in the original order,
196- * but only if there are no Left instances in the stream.
197- * If the stream does contain a Left instance, it discards the Right instances and
198- * accumulates a Left containing only the LHS values,
199- * in encounter order.
200- *
201- * @param <L> the type of the LHS values in the stream
202- * @param <R> the type of the RHS values in the stream
203- * @return a {@code Collector} which collects all the input elements into
204- * a Right containing all RHS values in the stream,
205- * or, if an LHS value exists, a Left containing a nonempty list
206- * of all LHS values in the stream
207- */
208- public static <L , R > Collector <Either <? extends L , ? extends R >, ?, Either <List <L >, List <R >>> toValidListAll () {
209-
210- BiConsumer <FullAcc <L , R >, Either <? extends L , ? extends R >> accumulate = (acc , either ) ->
211- either .ifLeftOrElse (acc ::addLeft , acc ::addRight );
212-
213- BinaryOperator <FullAcc <L , R >> combine = (acc , other ) ->
214- (FullAcc <L , R >) acc .combine (other );
215-
216- return new CollectorImpl <>(FullAcc ::new , accumulate , combine , FullAcc ::finish );
217- }
218-
219- /**
220- * Returns a {@code Collector} that accumulates the input elements into
221- * a new {@code List}. There are no guarantees on the type, mutability,
222- * serializability, or thread-safety of the {@code List} returned.
223- * The resulting list is wrapped in an {@code Optional},
224- * which is empty if and only if the list is empty.
225- *
226- * @see #optionalList(List)
227- * @param <T> the type of the input elements
228- * @return a list of the RHS values in the stream,
229- * or, if an LHS value exists, a nonempty list of all LHS values
230- */
231- public static <T > Collector <T , ?, Optional <List <T >>> toOptionalList () {
232- return Collectors .collectingAndThen (
233- Collectors .toList (),
234- Eithers ::optionalList );
235- }
236-
237- /**
238- * If the provided list is empty, returns an empty {@link Optional}.
239- * Otherwise, returns an {@code Optional} containing the nonempty
240- * input list.
241- *
242- * <p>Note: The resulting {@code Optional} might be used in a
243- * {@link Either#filter(Function) filter} or
244- * {@link Either#filterLeft(Function) filterLeft} operation.
245- *
246- * @see #toOptionalList()
247- * @param values a list of objects
248- * @param <T> the type of the members of {@code values}
249- * @return an {@code Optional} which is either empty, or
250- * contains a nonempty list
251- */
252- public static <T > Optional <List <T >> optionalList (List <? extends T > values ) {
253- if (values .isEmpty ()) {
254- return Optional .empty ();
255- }
256- @ SuppressWarnings ("unchecked" )
257- List <T > result = (List <T >) values ;
258- return Optional .of (result );
266+ private Eithers () {
259267 }
260268}
0 commit comments