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