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 */