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