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