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.Shorts.*;
020
021import java.util.*;
022import java.util.function.*;
023
024/**
025 * A {@link Supplier} whose value may be null, with Optional-like null-safe query methods.
026 *
027 * <p>
028 * This interface extends {@link Supplier} and provides convenience methods for working with potentially null values,
029 * similar to {@link Optional}. The key difference is that this interface is lazy - the value is only computed when
030 * {@link #get()} is called, and the null-safe methods operate on that computed value.
031 *
032 * <h5 class='section'>Features:</h5>
033 * <ul class='spaced-list'>
034 *    <li>Extends Supplier - can be used anywhere a Supplier is expected
035 *    <li>Null-safe API - provides isPresent(), isEmpty(), map(), orElse(), etc.
036 *    <li>Lazy evaluation - value is only computed when get() is called
037 *    <li>Null-safe - handles null values gracefully
038 * </ul>
039 *
040 * <h5 class='section'>Usage:</h5>
041 * <p class='bjava'>
042 *    <jc>// Create from a supplier</jc>
043 *    NullableSupplier&lt;String&gt; <jv>supplier</jv> = NullableSupplier.<jsm>of</jsm>(() -&gt; <js>"value"</js>);
044 *
045 *    <jc>// Check if value is present</jc>
046 *    <jk>if</jk> (<jv>supplier</jv>.isPresent()) {
047 *       String <jv>value</jv> = <jv>supplier</jv>.get();
048 *    }
049 *
050 *    <jc>// Map the value</jc>
051 *    NullableSupplier&lt;Integer&gt; <jv>length</jv> = <jv>supplier</jv>.map(String::length);
052 *
053 *    <jc>// Get value or default</jc>
054 *    String <jv>result</jv> = <jv>supplier</jv>.orElse(<js>"default"</js>);
055 * </p>
056 *
057 * <h5 class='section'>See Also:</h5><ul>
058 *    <li class='jc'>{@link Supplier} - Base functional interface
059 *    <li class='jc'>{@link Optional} - Java's Optional class
060 * </ul>
061 *
062 * @param <T> The type of value supplied by this supplier.
063 */
064@FunctionalInterface
065@SuppressWarnings({
066   "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants
067})
068public interface NullableSupplier<T> extends Supplier<T> {
069
070   /**
071    * Creates a NullableSupplier from a Supplier.
072    *
073    * @param <T> The value type.
074    * @param supplier The supplier. Must not be <jk>null</jk>.
075    * @return A new NullableSupplier instance.
076    */
077   public static <T> NullableSupplier<T> of(Supplier<T> supplier) {
078      reqnn("supplier", supplier);
079      return supplier::get;
080   }
081
082   /**
083    * Creates a NullableSupplier that always returns the specified value.
084    *
085    * @param <T> The value type.
086    * @param value The value to return. Can be <jk>null</jk>.
087    * @return A new NullableSupplier instance.
088    */
089   public static <T> NullableSupplier<T> ofNullable(T value) {
090      return () -> value;
091   }
092
093   /**
094    * Creates an empty NullableSupplier that always returns <jk>null</jk>.
095    *
096    * @param <T> The value type.
097    * @return A new NullableSupplier instance that always returns <jk>null</jk>.
098    */
099   public static <T> NullableSupplier<T> empty() {
100      return () -> null;
101   }
102
103   /**
104    * Returns <jk>true</jk> if the supplied value is not <jk>null</jk>.
105    *
106    * @return <jk>true</jk> if the supplied value is not <jk>null</jk>.
107    */
108   default boolean isPresent() {
109      return nn(get());
110   }
111
112   /**
113    * Returns <jk>true</jk> if the supplied value is <jk>null</jk>.
114    *
115    * @return <jk>true</jk> if the supplied value is <jk>null</jk>.
116    */
117   default boolean isEmpty() {
118      return ! isPresent();
119   }
120
121   /**
122    * If a value is present, applies the provided mapping function to it and returns a NullableSupplier describing the result.
123    *
124    * @param <U> The type of the result of the mapping function.
125    * @param mapper A mapping function to apply to the value, if present. Must not be <jk>null</jk>.
126    * @return A NullableSupplier describing the result of applying a mapping function to the value of this NullableSupplier, if a value is present, otherwise an empty NullableSupplier.
127    */
128   default <U> NullableSupplier<U> map(Function<? super T,? extends U> mapper) {
129      reqnn("mapper", mapper);
130      return () -> {
131         T value = get();
132         return nn(value) ? mapper.apply(value) : null;
133      };
134   }
135
136   /**
137    * If a value is present, returns the result of applying the given NullableSupplier-bearing mapping function to the value, otherwise returns an empty NullableSupplier.
138    *
139    * @param <U> The type parameter to the NullableSupplier returned by the mapping function.
140    * @param mapper A mapping function to apply to the value, if present. Must not be <jk>null</jk>.
141    * @return The result of applying a NullableSupplier-bearing mapping function to the value of this NullableSupplier, if a value is present, otherwise an empty NullableSupplier.
142    */
143   default <U> NullableSupplier<U> flatMap(Function<? super T,? extends NullableSupplier<? extends U>> mapper) {
144      reqnn("mapper", mapper);
145      return () -> {
146         T value = get();
147         if (nn(value)) {
148            NullableSupplier<? extends U> result = mapper.apply(value);
149            return result != null ? result.get() : null;
150         }
151         return null;
152      };
153   }
154
155   /**
156    * If a value is present, and the value matches the given predicate, returns a NullableSupplier describing the value, otherwise returns an empty NullableSupplier.
157    *
158    * @param predicate A predicate to apply to the value, if present. Must not be <jk>null</jk>.
159    * @return A NullableSupplier describing the value of this NullableSupplier if a value is present and the value matches the given predicate, otherwise an empty NullableSupplier.
160    */
161   default NullableSupplier<T> filter(Predicate<? super T> predicate) {
162      reqnn("predicate", predicate);
163      return () -> {
164         T value = get();
165         return (nn(value) && predicate.test(value)) ? value : null;
166      };
167   }
168
169   /**
170    * If a value is present, returns the value, otherwise returns <jk>other</jk>.
171    *
172    * @param other The value to be returned if there is no value present. Can be <jk>null</jk>.
173    * @return The value, if present, otherwise <jk>other</jk>.
174    */
175   default T orElse(T other) {
176      T value = get();
177      return nn(value) ? value : other;
178   }
179
180   /**
181    * If a value is present, returns the value, otherwise returns the result produced by the supplying function.
182    *
183    * @param other A {@link Supplier} whose result is returned if no value is present. Must not be <jk>null</jk>.
184    * @return The value, if present, otherwise the result of <jk>other.get()</jk>.
185    */
186   default T orElseGet(Supplier<? extends T> other) {
187      reqnn("other", other);
188      T value = get();
189      return nn(value) ? value : other.get();
190   }
191
192   /**
193    * If a value is present, returns the value, otherwise throws an exception produced by the exception supplying function.
194    *
195    * @param <X> Type of the exception to be thrown.
196    * @param exceptionSupplier The supplying function that produces an exception to be thrown. Must not be <jk>null</jk>.
197    * @return The value, if present.
198    * @throws X If no value is present.
199    */
200   default <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
201      reqnn("exceptionSupplier", exceptionSupplier);
202      T value = get();
203      if (nn(value))
204         return value;
205      throw exceptionSupplier.get();
206   }
207
208   /**
209    * If a value is present, performs the given action with the value, otherwise does nothing.
210    *
211    * @param action The action to be performed, if a value is present. Must not be <jk>null</jk>.
212    */
213   default void ifPresent(Consumer<? super T> action) {
214      reqnn("action", action);
215      T value = get();
216      if (nn(value))
217         action.accept(value);
218   }
219
220   /**
221    * If a value is present, performs the given action with the value, otherwise performs the given empty-based action.
222    *
223    * @param action The action to be performed, if a value is present. Must not be <jk>null</jk>.
224    * @param emptyAction The empty-based action to be performed, if no value is present. Must not be <jk>null</jk>.
225    */
226   default void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
227      reqnn("action", action);
228      reqnn("emptyAction", emptyAction);
229      T value = get();
230      if (nn(value))
231         action.accept(value);
232      else
233         emptyAction.run();
234   }
235
236   /**
237    * Converts this NullableSupplier to an {@link Optional}.
238    *
239    * @return An Optional containing the value if present, otherwise an empty Optional.
240    */
241   default Optional<T> toOptional() {
242      return o(get());
243   }
244}