View Javadoc
1   package io.atlassian.fugue.extensions.step;
2   
3   import io.atlassian.fugue.Option;
4   
5   import java.util.function.BiFunction;
6   import java.util.function.BiPredicate;
7   import java.util.function.Function;
8   import java.util.function.Supplier;
9   
10  /**
11   * The second step of the {@link Option} type.
12   * <p>
13   * This class is not intended to be contructed manually, and should only be used
14   * as part of a {@link Steps} chain, started by {@link Steps#begin(Option)}
15   *
16   * @param <A> The type of the first defined value
17   * @param <B> The type of the second defined value
18   * @see Steps for usage examples
19   * @see Option
20   * @since 4.7.0
21   */
22  public final class OptionStep2<A, B> {
23  
24    private final Option<A> option1;
25    private final Option<B> option2;
26  
27    OptionStep2(Option<A> option1, Option<B> option2) {
28      this.option1 = option1;
29      this.option2 = option2;
30    }
31  
32    /**
33     * Apply the provided function with the previous Step results.
34     * <p>
35     * Internally this will perform a {@link Option#flatMap(Function)} and the
36     * result will become the next step value.
37     *
38     * @param functor The functor to be applied as a flatMap with the previous
39     * steps
40     * @param <C> The type of the next step result
41     * @return The next step class
42     */
43    public <C> OptionStep3<A, B, C> then(BiFunction<? super A, ? super B, ? extends Option<? extends C>> functor) {
44      Option<C> option3 = option1.flatMap(value1 -> option2.flatMap(value2 -> functor.apply(value1, value2)));
45      return new OptionStep3<>(option1, option2, option3);
46    }
47  
48    /**
49     * Apply the provided supplier with the previous Step results.
50     * <p>
51     * Internally this will perform a {@link Option#flatMap(Function)} and the
52     * supplier will become the next step value.
53     * <p>
54     * This is different to {@link #then(BiFunction)} in that the previous step
55     * results are not provided for the new step evaluation.
56     *
57     * @param supplier The supplier to provide the result of the flatMap with the
58     * previous step.
59     * @param <C> The type of the next step result
60     * @return The next step class
61     */
62    public <C> OptionStep3<A, B, C> then(Supplier<? extends Option<? extends C>> supplier) {
63      Option<C> option3 = option1.flatMap(value1 -> option2.flatMap(value2 -> supplier.get()));
64      return new OptionStep3<>(option1, option2, option3);
65    }
66  
67    /**
68     * Apply the provided predicate with the previous step results.
69     *
70     * @param predicate The check that must be satisfied by contained values
71     * @return This step class with either the same last step value, or changed to
72     * none
73     */
74    public OptionStep2<A, B> filter(BiPredicate<? super A, ? super B> predicate) {
75      Option<B> filterOption2 = option1.flatMap(value1 -> option2.filter(value2 -> predicate.test(value1, value2)));
76      return new OptionStep2<>(option1, filterOption2);
77    }
78  
79    /**
80     * Terminating step expression, that will provide the previous steps to this
81     * function and return the result as a <code>some</code>
82     *
83     * @param functor The yield function to map on previous values
84     * @param <Z> The type for the returned result
85     * @return An Option containing this result or none
86     */
87    public <Z> Option<Z> yield(BiFunction<? super A, ? super B, Z> functor) {
88      return option1.flatMap(value1 -> option2.map(value2 -> functor.apply(value1, value2)));
89    }
90  
91  }