001/* 002 * ============================================================================ 003 * Copyright © 2002-2020 by Thomas Thrien. 004 * All Rights Reserved. 005 * ============================================================================ 006 * Licensed to the public under the agreements of the GNU Lesser General Public 007 * License, version 3.0 (the "License"). You may obtain a copy of the License at 008 * 009 * http://www.gnu.org/licenses/lgpl.html 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, WITHOUT 013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 014 * License for the specific language governing permissions and limitations 015 * under the License. 016 */ 017 018package org.tquadrat.foundation.lang; 019 020import static org.apiguardian.api.API.Status.STABLE; 021import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument; 022 023import java.util.Optional; 024import java.util.function.Consumer; 025import java.util.function.Function; 026import java.util.function.Supplier; 027 028import org.apiguardian.api.API; 029import org.tquadrat.foundation.annotation.ClassVersion; 030import org.tquadrat.foundation.lang.internal.LazyImpl; 031 032/** 033 * <p>{@summary A holder for a lazy initialised object instance.}</p> 034 * <p>An instance of an implementation of this interface holds a value that 035 * will be initialised by a call to the supplier (provided with the method 036 * {@link #use(Supplier)}) 037 * on a first call to 038 * {@link #get()}.</p> 039 * <p>The methods 040 * {@link #getAsString()} 041 * and 042 * {@link #getAsString(Stringer)} 043 * do call {@code get()} internally.</p> 044 * <p>For special purposes, the method 045 * {@link #of(Object)} 046 * creates an already initialised instance of {@code Lazy}.</p> 047 * <p>Use 048 * {@link #isPresent()} 049 * to avoid unnecessary initialisation.</p> 050 * <p>As a lazy initialisation makes the value unpredictable, it is necessary 051 * that the implementations of 052 * {@link #equals(Object)} 053 * and 054 * {@link #hashCode()} 055 * do force the initialisation.</p> 056 * <p>{@link #toString()} 057 * will not force the initialisation.</p> 058 * <p>This interface is not feasible for the lazy initialisation of 059 * connections to resources of any kind, as these will usually throw (checked) 060 * exceptions when problems arise, and usually these should be handled on one 061 * central location.</p> 062 * 063 * @extauthor Thomas Thrien - thomas.thrien@tquadrat.org 064 * @version $Id: Lazy.java 1041 2022-12-18 22:14:52Z tquadrat $ 065 * @since 0.0.5 066 * 067 * @UMLGraph.link 068 * 069 * @param <T> The type of the value for this instance of {@code Lazy}. 070 */ 071@SuppressWarnings( "NewClassNamingConvention" ) 072@ClassVersion( sourceVersion = "$Id: Lazy.java 1041 2022-12-18 22:14:52Z tquadrat $" ) 073@API( status = STABLE, since = "0.0.5" ) 074public sealed interface Lazy<T> 075 permits org.tquadrat.foundation.lang.internal.LazyImpl 076{ 077 /*---------*\ 078 ====** Methods **========================================================== 079 \*---------*/ 080 /** 081 * {@inheritDoc} 082 */ 083 @Override 084 public boolean equals( final Object obj ); 085 086 /** 087 * Returns the value for this instance of {@code Lazy}. 088 * 089 * @return The value. 090 */ 091 public T get(); 092 093 /** 094 * <p>{@summary Returns the value for this instance of {@code Lazy} as its 095 * String representation.}</p> 096 * <p>Basically it will call the value's 097 * {@link Object#toString() toString()} 098 * method.</p> 099 * 100 * @return The value as String. 101 */ 102 public default String getAsString() { return getAsString( Objects::toString ); } 103 104 /** 105 * Returns the value for this instance of {@code Lazy} as a String that is 106 * generated by the provided 107 * {@link Stringer}. 108 * 109 * @note As the value is allowed to be {@code null}, it is necessary that 110 * the provided instance of {@code Function} can handle {@code null} 111 * as a valid argument. 112 * 113 * @param stringer The function that creates the String from the 114 * value. 115 * @return The value as String. 116 */ 117 public default String getAsString( final Stringer<? super T> stringer ) 118 { 119 final var retValue = requireNonNullArgument( stringer, "stringer" ) 120 .toString( get() ); 121 122 //---* Done *---------------------------------------------------------- 123 return retValue; 124 } // getAsString() 125 126 /** 127 * {@inheritDoc} 128 */ 129 @Override 130 public int hashCode(); 131 132 /** 133 * If this {@code Lazy} instance has been initialised already, the 134 * provided 135 * {@link Consumer} 136 * will be executed; otherwise nothing happens. 137 * 138 * @param consumer The consumer. 139 */ 140 public default void ifPresent( final Consumer<? super T> consumer ) 141 { 142 if( isPresent() ) requireNonNullArgument( consumer, "consumer" ).accept( get() ); 143 } // ifPresent() 144 145 /** 146 * <p>{@summary Checks whether this {@code Lazy} instance has been 147 * initialised already.} But even it was initialised, 148 * {@link #get()} 149 * may still return {@code null}.</p> 150 * 151 * @return {@code true} if the instance was initialised, {@code false} 152 * otherwise. 153 */ 154 public boolean isPresent(); 155 156 /** 157 * If this instance of {@code Lazy} is initialised, the provided mapper 158 * function will be executed on the value. 159 * 160 * @param <R> The result type for the mapper function. 161 * @param mapper The mapper function. 162 * @return An instance of 163 * {@link Optional} 164 * that holds the result for the mapping. 165 */ 166 public default <R> Optional<R> map( final Function<? super T,? extends R> mapper ) 167 { 168 final Optional<R> retValue = isPresent() ? Optional.ofNullable( mapper.apply( get() ) ) : Optional.empty(); 169 170 //---* Done *---------------------------------------------------------- 171 return retValue; 172 } // map() 173 174 /** 175 * <p>{@summary Creates a new {@code Lazy} instance that is already 176 * initialised.}</p> 177 * <p>This allows to use {@code Lazy} instances also for 178 * {@linkplain java.lang.Cloneable cloneable} 179 * objects, given that {@code T} is either cloneable itself or 180 * immutable.</p> 181 * 182 * @param <T> The type of the value for the new instance of {@code Lazy}. 183 * @param value The value; can be {@code null}. 184 * @return The new instance. 185 * 186 * @see Object#clone() 187 */ 188 @API( status = STABLE, since = "0.0.5" ) 189 public static <T> Lazy<T> of( final T value ) 190 { 191 return new LazyImpl<>( value ); 192 } // of() 193 194 /** 195 * Returns the value or throws the exception that is created by the 196 * given 197 * {@link Supplier} 198 * when not yet initialised. 199 * 200 * @param <X> The type of the implementation of 201 * {@link Throwable}. 202 * @param exceptionSupplier The supplier for the exception to throw 203 * when the instance was not yet initialised. 204 * @return The value. 205 * @throws X When not initialised, the exception created by the given 206 * supplier will be thrown. 207 */ 208 public <X extends Throwable> T orElseThrow( Supplier<? extends X> exceptionSupplier ) throws X; 209 210 /** 211 * {@inheritDoc} 212 */ 213 @Override 214 public String toString(); 215 216 /** 217 * Creates a new {@code Lazy} instance that uses the given supplier to 218 * initialise. 219 * 220 * @param <T> The type of the value for the new instance of {@code Lazy}. 221 * @param supplier The supplier that initialises the value for this 222 * instance on the first call to 223 * {@link #get()}. 224 * @return The new instance. 225 */ 226 @API( status = STABLE, since = "0.0.5" ) 227 public static <T> Lazy<T> use( final Supplier<T> supplier ) 228 { 229 return new LazyImpl<>( supplier ); 230 } // use() 231} 232// interface Lazy 233 234/* 235 * End of File 236 */