001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.commons.function;
018
019import static org.apache.juneau.commons.utils.AssertionUtils.*;
020import static org.apache.juneau.commons.utils.Utils.*;
021
022import java.util.*;
023import java.util.function.*;
024
025/**
026 * Combines the features of {@link Supplier} and {@link Optional} into a single class.
027 *
028 * <p>
029 * This interface extends {@link Supplier} and provides convenience methods for working with potentially null values,
030 * similar to {@link Optional}. The key difference is that this interface is lazy - the value is only computed when
031 * {@link #get()} is called, and the Optional-like methods operate on that computed value.
032 *
033 * <h5 class='section'>Features:</h5>
034 * <ul class='spaced-list'>
035 *    <li>Extends Supplier - can be used anywhere a Supplier is expected
036 *    <li>Optional-like API - provides isPresent(), isEmpty(), map(), orElse(), etc.
037 *    <li>Lazy evaluation - value is only computed when get() is called
038 *    <li>Null-safe - handles null values gracefully
039 * </ul>
040 *
041 * <h5 class='section'>Usage:</h5>
042 * <p class='bjava'>
043 *    <jc>// Create from a supplier</jc>
044 *    OptionalSupplier&lt;String&gt; <jv>supplier</jv> = OptionalSupplier.<jsm>of</jsm>(() -&gt; <js>"value"</js>);
045 *
046 *    <jc>// Check if value is present</jc>
047 *    <jk>if</jk> (<jv>supplier</jv>.isPresent()) {
048 *       String <jv>value</jv> = <jv>supplier</jv>.get();
049 *    }
050 *
051 *    <jc>// Map the value</jc>
052 *    OptionalSupplier&lt;Integer&gt; <jv>length</jv> = <jv>supplier</jv>.map(String::length);
053 *
054 *    <jc>// Get value or default</jc>
055 *    String <jv>result</jv> = <jv>supplier</jv>.orElse(<js>"default"</js>);
056 * </p>
057 *
058 * <h5 class='section'>See Also:</h5><ul>
059 *    <li class='jc'>{@link Supplier} - Base functional interface
060 *    <li class='jc'>{@link Optional} - Java's Optional class
061 * </ul>
062 *
063 * @param <T> The type of value supplied by this supplier.
064 */
065@FunctionalInterface
066public interface OptionalSupplier<T> extends Supplier<T> {
067
068   /**
069    * Creates an OptionalSupplier from a Supplier.
070    *
071    * @param <T> The value type.
072    * @param supplier The supplier. Must not be <jk>null</jk>.
073    * @return A new OptionalSupplier instance.
074    */
075   public static <T> OptionalSupplier<T> of(Supplier<T> supplier) {
076      assertArgNotNull("supplier", supplier);
077      return supplier::get;
078   }
079
080   /**
081    * Creates an OptionalSupplier that always returns the specified value.
082    *
083    * @param <T> The value type.
084    * @param value The value to return. Can be <jk>null</jk>.
085    * @return A new OptionalSupplier instance.
086    */
087   public static <T> OptionalSupplier<T> ofNullable(T value) {
088      return () -> value;
089   }
090
091   /**
092    * Creates an empty OptionalSupplier that always returns <jk>null</jk>.
093    *
094    * @param <T> The value type.
095    * @return A new OptionalSupplier instance that always returns <jk>null</jk>.
096    */
097   public static <T> OptionalSupplier<T> empty() {
098      return () -> null;
099   }
100
101   /**
102    * Returns <jk>true</jk> if the supplied value is not <jk>null</jk>.
103    *
104    * @return <jk>true</jk> if the supplied value is not <jk>null</jk>.
105    */
106   default boolean isPresent() {
107      return nn(get());
108   }
109
110   /**
111    * Returns <jk>true</jk> if the supplied value is <jk>null</jk>.
112    *
113    * @return <jk>true</jk> if the supplied value is <jk>null</jk>.
114    */
115   default boolean isEmpty() {
116      return ! isPresent();
117   }
118
119   /**
120    * If a value is present, applies the provided mapping function to it and returns an OptionalSupplier describing the result.
121    *
122    * @param <U> The type of the result of the mapping function.
123    * @param mapper A mapping function to apply to the value, if present. Must not be <jk>null</jk>.
124    * @return An OptionalSupplier describing the result of applying a mapping function to the value of this OptionalSupplier, if a value is present, otherwise an empty OptionalSupplier.
125    */
126   default <U> OptionalSupplier<U> map(Function<? super T, ? extends U> mapper) {
127      assertArgNotNull("mapper", mapper);
128      return () -> {
129         T value = get();
130         return nn(value) ? mapper.apply(value) : null;
131      };
132   }
133
134   /**
135    * If a value is present, returns the result of applying the given OptionalSupplier-bearing mapping function to the value, otherwise returns an empty OptionalSupplier.
136    *
137    * @param <U> The type parameter to the OptionalSupplier returned by the mapping function.
138    * @param mapper A mapping function to apply to the value, if present. Must not be <jk>null</jk>.
139    * @return The result of applying an OptionalSupplier-bearing mapping function to the value of this OptionalSupplier, if a value is present, otherwise an empty OptionalSupplier.
140    */
141   default <U> OptionalSupplier<U> flatMap(Function<? super T, ? extends OptionalSupplier<? extends U>> mapper) {
142      assertArgNotNull("mapper", mapper);
143      return () -> {
144         T value = get();
145         if (nn(value)) {
146            OptionalSupplier<? extends U> result = mapper.apply(value);
147            return result != null ? result.get() : null;
148         }
149         return null;
150      };
151   }
152
153   /**
154    * If a value is present, and the value matches the given predicate, returns an OptionalSupplier describing the value, otherwise returns an empty OptionalSupplier.
155    *
156    * @param predicate A predicate to apply to the value, if present. Must not be <jk>null</jk>.
157    * @return An OptionalSupplier describing the value of this OptionalSupplier if a value is present and the value matches the given predicate, otherwise an empty OptionalSupplier.
158    */
159   default OptionalSupplier<T> filter(Predicate<? super T> predicate) {
160      assertArgNotNull("predicate", predicate);
161      return () -> {
162         T value = get();
163         return (nn(value) && predicate.test(value)) ? value : null;
164      };
165   }
166
167   /**
168    * If a value is present, returns the value, otherwise returns <jk>other</jk>.
169    *
170    * @param other The value to be returned if there is no value present. Can be <jk>null</jk>.
171    * @return The value, if present, otherwise <jk>other</jk>.
172    */
173   default T orElse(T other) {
174      T value = get();
175      return nn(value) ? value : other;
176   }
177
178   /**
179    * If a value is present, returns the value, otherwise returns the result produced by the supplying function.
180    *
181    * @param other A {@link Supplier} whose result is returned if no value is present. Must not be <jk>null</jk>.
182    * @return The value, if present, otherwise the result of <jk>other.get()</jk>.
183    */
184   default T orElseGet(Supplier<? extends T> other) {
185      assertArgNotNull("other", other);
186      T value = get();
187      return nn(value) ? value : other.get();
188   }
189
190   /**
191    * If a value is present, returns the value, otherwise throws an exception produced by the exception supplying function.
192    *
193    * @param <X> Type of the exception to be thrown.
194    * @param exceptionSupplier The supplying function that produces an exception to be thrown. Must not be <jk>null</jk>.
195    * @return The value, if present.
196    * @throws X If no value is present.
197    */
198   default <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
199      assertArgNotNull("exceptionSupplier", exceptionSupplier);
200      T value = get();
201      if (nn(value))
202         return value;
203      throw exceptionSupplier.get();
204   }
205
206   /**
207    * If a value is present, performs the given action with the value, otherwise does nothing.
208    *
209    * @param action The action to be performed, if a value is present. Must not be <jk>null</jk>.
210    */
211   default void ifPresent(Consumer<? super T> action) {
212      assertArgNotNull("action", action);
213      T value = get();
214      if (nn(value))
215         action.accept(value);
216   }
217
218   /**
219    * If a value is present, performs the given action with the value, otherwise performs the given empty-based action.
220    *
221    * @param action The action to be performed, if a value is present. Must not be <jk>null</jk>.
222    * @param emptyAction The empty-based action to be performed, if no value is present. Must not be <jk>null</jk>.
223    */
224   default void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
225      assertArgNotNull("action", action);
226      assertArgNotNull("emptyAction", emptyAction);
227      T value = get();
228      if (nn(value))
229         action.accept(value);
230      else
231         emptyAction.run();
232   }
233
234   /**
235    * Converts this OptionalSupplier to an {@link Optional}.
236    *
237    * @return An Optional containing the value if present, otherwise an empty Optional.
238    */
239   default Optional<T> toOptional() {
240      return opt(get());
241   }
242}
243