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