View Javadoc
1   /*
2      Copyright 2011 Atlassian
3   
4      Licensed under the Apache License, Version 2.0 (the "License");
5      you may not use this file except in compliance with the License.
6      You may obtain a copy of the License at
7   
8          http://www.apache.org/licenses/LICENSE-2.0
9   
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15   */
16  package io.atlassian.fugue;
17  
18  import java.util.Collections;
19  import java.util.function.Function;
20  import java.util.function.Predicate;
21  import java.util.function.Supplier;
22  import java.util.stream.Collector;
23  import java.util.stream.Collectors;
24  
25  import static io.atlassian.fugue.Iterables.collect;
26  import static io.atlassian.fugue.Iterables.map;
27  import static io.atlassian.fugue.Suppliers.compose;
28  import static io.atlassian.fugue.Suppliers.ofInstance;
29  
30  /**
31   * Utility functions for Eithers.
32   *
33   * @since 1.2
34   */
35  public class Eithers {
36  
37    // /CLOVER:OFF
38  
39    private Eithers() {}
40  
41    // /CLOVER:ON
42  
43    /**
44     * Extracts an object from an Either, regardless of the side in which it is
45     * stored, provided both sides contain the same type. This method will never
46     * return null.
47     *
48     * @param <T> the type for both the LHS and the RHS
49     * @param either use whichever side holds the value to return
50     * @return the value from whichever side holds it
51     */
52    public static <T> T merge(final Either<T, T> either) {
53      if (either.isLeft()) {
54        return either.left().get();
55      }
56      return either.right().get();
57    }
58  
59    /**
60     * Creates an Either based on a boolean expression. If predicate is true, a
61     * Right will be returned containing the supplied right value; if it is false,
62     * a Left will be returned containing the supplied left value.
63     *
64     * @param <L> the LHS type
65     * @param <R> the RHS type
66     * @param predicate if predicate is true, a Right will be returned if it is
67     * false, a Left will be returned containing the supplied left value.
68     * @param left the LHS value
69     * @param right the RHS value
70     * @return an either with the appropriately selected value
71     */
72    public static <L, R> Either<L, R> cond(final boolean predicate, final L left, final R right) {
73      return predicate ? Either.<L, R> right(right) : Either.<L, R> left(left);
74    }
75  
76    /**
77     * Simplifies extracting a value or throwing a checked exception from an
78     * Either.
79     *
80     * @param <A> the value type
81     * @param <X> the exception type
82     * @param either to extract from
83     * @return the value from the RHS
84     * @throws X the exception on the LHS
85     */
86    public static <X extends Exception, A> A getOrThrow(final Either<X, A> either) throws X {
87      if (either.isLeft()) {
88        throw either.left().get();
89      }
90      return either.right().get();
91    }
92  
93    /**
94     * A predicate that tests if the supplied either is a left.
95     *
96     * @param <L> the LHS type
97     * @param <R> the RHS type
98     * @return the predicate testing left-hand-sidedness
99     */
100   public static <L, R> Predicate<Either<L, R>> isLeft() {
101     return Either::isLeft;
102   }
103 
104   /**
105    * A predicate that tests if the supplied either is a right.
106    *
107    * @param <L> the LHS type
108    * @param <R> the RHS type
109    * @return the predicate testing right-hand-sidedness
110    */
111   public static <L, R> Predicate<Either<L, R>> isRight() {
112     return Either::isRight;
113   }
114 
115   /**
116    * A function that maps an either to an option of its left type. The Function
117    * will return a defined {@link io.atlassian.fugue.Option} containing the
118    * either's left value if {Either#isLeft()} is true, an undefined
119    * {@link io.atlassian.fugue.Option} otherwise.
120    *
121    * @param <L> the LHS type
122    * @param <R> the RHS type
123    * @return the function returning a defined option for left-hand-sided eithers
124    */
125   public static <L, R> Function<Either<L, R>, Option<L>> leftMapper() {
126     return either -> either.left().toOption();
127   }
128 
129   /**
130    * A function that maps an either to an option of its right type. The Function
131    * will return a defined {@link io.atlassian.fugue.Option} containing the
132    * either's right value if {Either#isRight()} is true, an undefined
133    * {@link io.atlassian.fugue.Option} otherwise.
134    *
135    * @param <L> the LHS type
136    * @param <R> the RHS type
137    * @return the function returning a defined option for right-hand-sided
138    * eithers
139    */
140   public static <L, R> Function<Either<L, R>, Option<R>> rightMapper() {
141     return either -> either.right().toOption();
142   }
143 
144   /**
145    * Function to convert from an value to a
146    * {@link io.atlassian.fugue.Either.Left} containing that value.
147    *
148    * @param <L> left type.
149    * @param <R> right type.
150    * @return a {@link java.util.function.Function} returning a
151    * {@link io.atlassian.fugue.Either.Left}.
152    */
153   public static <L, R> Function<L, Either<L, R>> toLeft() {
154     return Either::left;
155   }
156 
157   /**
158    * Function to convert from a value to a
159    * {@link io.atlassian.fugue.Either.Left} containing that value. Allows
160    * hinting the correct types.
161    *
162    * @param leftType expected left type.
163    * @param rightType expected right type.
164    * @param <L> left type.
165    * @param <R> right type.
166    * @return a {@link java.util.function.Function} returning a
167    * {@link io.atlassian.fugue.Either.Left}.
168    */
169   public static <L, R> Function<L, Either<L, R>> toLeft(final Class<L> leftType, final Class<R> rightType) {
170     return Eithers.toLeft();
171   }
172 
173   /**
174    * Supplier returning a {@link io.atlassian.fugue.Either.Left}.
175    *
176    * @param l value to return inside the left.
177    * @param <L> left type.
178    * @param <R> right type.
179    * @return a {@link java.util.function.Supplier} returning a
180    * {@link io.atlassian.fugue.Either.Left}..
181    */
182   public static <L, R> Supplier<Either<L, R>> toLeft(final L l) {
183     return compose(Eithers.<L, R> toLeft(), ofInstance(l));
184   }
185 
186   /**
187    * Supplier returning a {@link io.atlassian.fugue.Either.Left}. Allows hinting
188    * the correct right type.
189    *
190    * @param l value to return inside the left.
191    * @param rightType type hint for the right type of the either.
192    * @param <L> left type.
193    * @param <R> right type.
194    * @return a {@link java.util.function.Supplier} returning a
195    * {@link io.atlassian.fugue.Either.Left}.
196    */
197   public static <L, R> Supplier<Either<L, R>> toLeft(final L l, final Class<R> rightType) {
198     return Eithers.toLeft(l);
199   }
200 
201   /**
202    * Function to convert from an value to a
203    * {@link io.atlassian.fugue.Either.Right}. Allows hinting the correct types.
204    *
205    * @param <L> left type.
206    * @param <R> right type.
207    * @return a {@link java.util.function.Function} returning a
208    * {@link io.atlassian.fugue.Either.Right}.
209    */
210   public static <L, R> Function<R, Either<L, R>> toRight() {
211     return Either::right;
212   }
213 
214   /**
215    * Function to convert from a value to a
216    * {@link io.atlassian.fugue.Either.Right} containing that value. Allows
217    * hinting the correct types.
218    *
219    * @param leftType expected left type.
220    * @param rightType expected right type.
221    * @param <L> left type.
222    * @param <R> right type.
223    * @return a {@link java.util.function.Function} returning a
224    * {@link io.atlassian.fugue.Either.Right}.
225    */
226   public static <L, R> Function<R, Either<L, R>> toRight(final Class<L> leftType, final Class<R> rightType) {
227     return Eithers.toRight();
228   }
229 
230   /**
231    * Supplier returning a {@link io.atlassian.fugue.Either.Right}.
232    *
233    * @param r value to return inside the right.
234    * @param <L> left type.
235    * @param <R> right type.
236    * @return a {@link java.util.function.Supplier} returning a
237    * {@link io.atlassian.fugue.Either.Right}..
238    */
239   public static <L, R> Supplier<Either<L, R>> toRight(final R r) {
240     return compose(Eithers.<L, R> toRight(), ofInstance(r));
241   }
242 
243   /**
244    * Supplier returning a {@link io.atlassian.fugue.Either.Right}. Allows
245    * hinting the correct right type.
246    *
247    * @param r value to return inside the right.
248    * @param leftType type hint for the left type of the either.
249    * @param <L> left type.
250    * @param <R> right type.
251    * @return a {@link java.util.function.Supplier} returning a
252    * {@link io.atlassian.fugue.Either.Right}.
253    */
254   public static <L, R> Supplier<Either<L, R>> toRight(final Class<L> leftType, final R r) {
255     return Eithers.toRight(r);
256   }
257 
258   /**
259    * Upcasts an {@link Either either} of left type L to an either of left type
260    * LL, which is a super type of L, keeping the right type unchanged.
261    *
262    * @param e the source either
263    * @param <L> the base type to upcast
264    * @param <LL> the super type of the contained left type
265    * @param <R> the contained right type
266    * @return an either of left type LL and right type R
267    * @since 2.0
268    */
269   public static <LL, L extends LL, R> Either<LL, R> upcastLeft(final Either<L, R> e) {
270     return e.left().map(Functions.<LL> identity());
271   }
272 
273   /**
274    * Upcasts an {@link Either either} of right type R to an either of right type
275    * RR, which is a super type of R, keeping the left type unchanged.
276    *
277    * @param e the source either
278    * @param <L> the contained left type
279    * @param <R> the base type to upcast
280    * @param <RR> the super type of the contained right type
281    * @return an either of left type L and right type RR
282    * @since 2.0
283    */
284   public static <L, RR, R extends RR> Either<L, RR> upcastRight(final Either<L, R> e) {
285     return e.right().map(Functions.<RR> identity());
286   }
287 
288   /**
289    * Takes an {@link java.lang.Iterable} of {@link Either eithers}, and collects
290    * the left values of every either which has a left value
291    *
292    * @param <L> the LHS type
293    * @param <R> the RHS type
294    * @param it iterable of eithers to filter and transform from
295    * @return the left values contained in the contents of it
296    */
297   public static <L, R> Iterable<L> filterLeft(final Iterable<Either<L, R>> it) {
298     return collect(it, Eithers.<L, R> leftMapper());
299   }
300 
301   /**
302    * Takes an {@link java.lang.Iterable} of {@link Either eithers}, and collects
303    * the right values of every either which has a left value
304    *
305    * @param <L> the LHS type
306    * @param <R> the RHS type
307    * @param it iterable of eithers to filter and transform from
308    * @return the right values contained in the contents of it
309    */
310   public static <L, R> Iterable<R> filterRight(final Iterable<Either<L, R>> it) {
311     return Options.flatten(map(it, Eithers.<L, R> rightMapper()));
312   }
313 
314   /**
315    * Collect the right values if there are only rights, otherwise return the
316    * first left encountered.
317    *
318    * @param <L> the LHS type
319    * @param <R> the RHS type
320    * @param eithers an Iterable of either values
321    * @return either the iterable of right values, or the first left encountered.
322    */
323   public static <L, R> Either<L, Iterable<R>> sequenceRight(final Iterable<Either<L, R>> eithers) {
324     return sequenceRight(eithers, Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
325   }
326 
327   /**
328    * Collect the right values if there are only rights, otherwise return the
329    * first left encountered.
330    *
331    * @param <L> the LHS type
332    * @param <R> the RHS type
333    * @param <A> The intermediate accumulator type
334    * @param <C> The result type
335    * @param eithers an Iterable of either values
336    * @param collector result collector
337    * @since 4.6.0
338    * @return either the iterable of right values, or the first left encountered.
339    */
340   public static <L, R, A, C> Either<L, C> sequenceRight(final Iterable<Either<L, R>> eithers, final Collector<R, A, C> collector) {
341     final A accumulator = collector.supplier().get();
342     for (final Either<L, R> e : eithers) {
343       if (e.isLeft()) {
344         return e.left().as();
345       }
346       collector.accumulator().accept(accumulator, e.right().get());
347     }
348     return Either.right(collector.finisher().apply(accumulator));
349   }
350 
351   /**
352    * Collect the left values if there are only lefts, otherwise return the first
353    * right encountered.
354    *
355    * @param <L> the LHS type
356    * @param <R> the RHS type
357    * @param eithers an Iterable of either values
358    * @return either the iterable of left values, or the first right encountered.
359    */
360   public static <L, R> Either<Iterable<L>, R> sequenceLeft(final Iterable<Either<L, R>> eithers) {
361     return sequenceLeft(eithers, Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
362   }
363 
364   /**
365    * Collect the left values if there are only lefts, otherwise return the first
366    * right encountered.
367    *
368    * @param <L> the LHS type
369    * @param <R> the RHS type
370    * @param <A> The intermediate accumulator type
371    * @param <C> The result type
372    * @param eithers an Iterable of either values
373    * @param collector result collector
374    * @since 4.6.0
375    * @return either the iterable of left values, or the first right encountered.
376    */
377   public static <L, R, A, C> Either<C, R> sequenceLeft(final Iterable<Either<L, R>> eithers, final Collector<L, A, C> collector) {
378     final A accumulator = collector.supplier().get();
379     for (final Either<L, R> e : eithers) {
380       if (e.isRight()) {
381         return e.right().as();
382       }
383       collector.accumulator().accept(accumulator, e.left().get());
384     }
385     return Either.left(collector.finisher().apply(accumulator));
386   }
387 }