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 }