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