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