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