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.function.BiFunction;
19  import java.util.function.Function;
20  import java.util.function.Predicate;
21  
22  import static io.atlassian.fugue.Iterables.filter;
23  import static io.atlassian.fugue.Iterables.map;
24  import static io.atlassian.fugue.Option.none;
25  import static java.util.Objects.requireNonNull;
26  
27  /**
28   * Utility methods for working with {@link Option options}.
29   *
30   * @since 1.1
31   */
32  public class Options {
33    private Options() {
34      throw new UnsupportedOperationException("This class is not instantiable.");
35    }
36  
37    /**
38     * Find the first option that {@link io.atlassian.fugue.Option#isDefined()
39     * isDefined}, or if there aren't any, then none.
40     *
41     * @param <A> the contained type
42     * @param options an Iterable of options to search through
43     * @return the first defined option, or none if there aren't any
44     */
45    public static <A> Option<A> find(final Iterable<Option<A>> options) {
46      for (final Option<A> option : options) {
47        if (option.isDefined()) {
48          return option;
49        }
50      }
51      return none();
52    }
53  
54    /**
55     * Upcasts an {@link Option option} of type A to an option of its super type
56     * AA.
57     *
58     * @param o the source option
59     * @param <AA> the super type of the contained type
60     * @return an option of the super type
61     * @since 2.0
62     * @param <A> a A object.
63     */
64    public static <AA, A extends AA> Option<AA> upcast(final Option<A> o) {
65      return o.map(Functions.<AA> identity());
66    }
67  
68    /**
69     * Lifts a function that takes an A and returns a B into a function that takes
70     * an option of A and returns an option of B.
71     *
72     * @param f the original function to be lifted, must not be null
73     * @param <A> the input type of the original function
74     * @param <B> the result type of the original function
75     * @return a function that takes an option of type A and returns an option of
76     * type B
77     * @since 2.0
78     */
79    public static <A, B> Function<Option<A>, Option<B>> lift(final Function<A, B> f) {
80      requireNonNull(f);
81      return oa -> oa.map(f);
82    }
83  
84    /**
85     * Returns a function that will lift a function that takes an A and returns a
86     * B into a function that takes an option of A and returns an option of B.
87     *
88     * @param <A> the input type of the function that can be lifted
89     * @param <B> the result type of the function that can be lifted
90     * @return a function that can lift a function of input type A and result type
91     * B into Option
92     * @since 2.0
93     */
94    public static <A, B> Function<Function<A, B>, Function<Option<A>, Option<B>>> lift() {
95      return Options::lift;
96    }
97  
98    /**
99     * Lifts a predicate that takes an A into a predicate that takes an option of
100    * A.
101    *
102    * @param pred the original predicate to be lifted, must not be null
103    * @param <A> the input type of the predicate
104    * @return a predicate that takes an option of type A
105    * @since 2.2
106    */
107   public static <A> Predicate<Option<A>> lift(final Predicate<? super A> pred) {
108     requireNonNull(pred);
109     return oa -> oa.exists(pred);
110   }
111 
112   /**
113    * Applies an option of A to an option of a function with input type A and
114    * result type B and return an option of B.
115    *
116    * @param oa an option of the argument to the function
117    * @param of an option of a function that takes an A and returns a B
118    * @param <A> the input type of the function wrapped in the option 'of'
119    * @param <B> the result type of the function wrapped in the option 'of'
120    * @return an option of B
121    * @since 2.0
122    */
123   public static <A, B> Option<B> ap(final Option<A> oa, final Option<Function<A, B>> of) {
124     return of.fold(Option.<B> noneSupplier(), Functions.compose(Functions.<Option<A>, Option<B>> apply(oa), Options.<A, B> lift()));
125   }
126 
127   /**
128    * Lifts a function that takes an A and a B and returns a C into a function
129    * that takes an option of A and an option of B and returns an option of C.
130    *
131    * @param f2 the original function to be lifted
132    * @param <A> the input type of the first argument of the original function
133    * @param <B> the input type of the second argument of the original function
134    * @param <C> the result type of the original function
135    * @return a function that takes an option of type A and an option of B and
136    * returns an option of type C
137    * @since 2.0
138    */
139   public static <A, B, C> BiFunction<Option<A>, Option<B>, Option<C>> lift2(final BiFunction<A, B, C> f2) {
140     final Function<A, Function<B, C>> curried = Functions.curried(f2);
141     final Function<Option<A>, Option<Function<B, C>>> lifted = lift(curried);
142     return (oa, ob) -> {
143       final Option<Function<B, C>> ofbc = lifted.apply(oa);
144       return Options.ap(ob, ofbc);
145     };
146   }
147 
148   /**
149    * Returns a function that will lift a function that takes an A and a B and
150    * returns a C into a function that takes an option of A and an option of B
151    * and returns an option of C.
152    *
153    * @param <A> the input type of the first argument of the function that can be
154    * lifted
155    * @param <B> the input type of the second argument of the function that can
156    * be lifted
157    * @param <C> the result type of the function that can be lifted
158    * @return a function that can lift a function of input type A and B and
159    * result type C into Option
160    * @since 2.0
161    */
162   public static <A, B, C> Function<BiFunction<A, B, C>, BiFunction<Option<A>, Option<B>, Option<C>>> lift2() {
163     return Options::lift2;
164   }
165 
166   /**
167    * Filter out undefined options.
168    *
169    * @param <A> the contained type
170    * @param options many options that may or may not be defined
171    * @return the filtered options
172    */
173   public static <A> Iterable<Option<A>> filterNone(final Iterable<Option<A>> options) {
174     return filter(options, Maybe::isDefined);
175   }
176 
177   /**
178    * Flattens an {@link java.lang.Iterable} of {@link Option options} into an
179    * iterable of the things, filtering out any nones.
180    *
181    * @param <A> the contained type
182    * @param options the iterable of options
183    * @return an {@link java.lang.Iterable} of the contained type
184    */
185   public static <A> Iterable<A> flatten(final Iterable<Option<A>> options) {
186     return map(filterNone(options), Maybe::get);
187   }
188 
189   /**
190    * Function for wrapping values in a Some or None.
191    *
192    * @param <A> the contained type
193    * @return a {@link java.util.function.Function} to wrap values
194    * @since 3.0
195    */
196   public static <A> Function<A, Option<A>> toOption() {
197     return Option::option;
198   }
199 
200   /**
201    * Turn a null producing function into one that returns an option instead.
202    *
203    * @param nullProducing the function that may return null
204    * @return a function that turns nulls into None, and wraps non-null values in
205    * Some.
206    * @since 3.0
207    * @param <A> input type to the function.
208    * @param <B> output type of the function.
209    */
210   public static <A, B> Function<A, Option<B>> nullSafe(final Function<A, B> nullProducing) {
211     return nullProducing.andThen(toOption());
212   }
213 }