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<String> <jv>supplier</jv> = NullableSupplier.<jsm>of</jsm>(() -> <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<Integer> <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}