
ru.progrm_jarvis.javacommons.object.extension.NullSafetyExtensions Maven / Gradle / Ivy
package ru.progrm_jarvis.javacommons.object.extension;
import lombok.NonNull;
import lombok.experimental.UtilityClass;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
/**
* Extensions to provide null-safety on nullable types.
* These methods behave specifically, for example call on {@code null} may not throw {@link NullPointerException}
* thus they have underscores ({@code _}) in their names.
*/
@UtilityClass
public class NullSafetyExtensions {
/**
* Returns the passed value if it not {@code null} otherwise returning the default one.
*
* @param value value whose nullability is tested
* @param defaultValue value returned if {@code value} is {@code null}
* @param type of the value
* @return {@code value} if it is not {@code null} and {@code defaultValue} otherwise
*/
@Contract("!null, _ -> param1; null, _ -> param2")
public T _or(final @Nullable T value,
final @Nullable T defaultValue) {
return value == null ? defaultValue : value;
}
/**
* Returns the passed value if it not {@code null} otherwise returning the default one.
*
* @param value value whose nullability is tested
* @param defaultValueSupplier supplier of the value returned if {@code value} is {@code null}
* @param type of the value
* @return {@code value} if it is not {@code null} and {@code defaultValue} otherwise
*
* @throws NullPointerException if {@code defaultValueSupplier} is {@code null}
*/
@SuppressWarnings("Contract") // Lombok's annotation is treated incorrectly
@Contract("_, null -> fail; !null, _ -> param1; null, _ -> _")
public T _orGet(final @Nullable T value,
final @NonNull Supplier<@Nullable ? extends T> defaultValueSupplier) {
return value == null ? defaultValueSupplier.get() : value;
}
/**
* Maps the given value if it is {@code null} otherwise returning {@code null}.
*
* @param value value to be mapped if it is not {@code null}
* @param mappingFunction function to be used for mapping of the the non-{@code null} value
* @param type of the source value
* @param type of the mapped value
* @return mapped {@code value} if the latter was not {@code null} or {@code null} otherwise
*
* @throws NullPointerException if {@code mappingFunction} is {@code null}
*/
@SuppressWarnings("Contract") // Lombok's annotation is treated incorrectly
@Contract("_, null -> fail; !null, _ -> _; null, _ -> null")
public @Nullable R _map(final @Nullable T value,
final @NonNull Function<@NotNull T, R> mappingFunction) {
return value == null ? null : mappingFunction.apply(value);
}
/**
* Maps the given value.
*
* @param value value to be mapped
* @param mappingFunction function to be used for mapping of the value
* @param type of the source value
* @param type of the mapped value
* @return mapped value
*
* @throws NullPointerException if {@code mappingFunction} is {@code null}
*/
@SuppressWarnings("Contract") // Lombok's annotation is treated incorrectly
@Contract("_, null -> fail; _, _ -> _")
public @Nullable R _mapNullable(final @Nullable T value,
final @NonNull Function<@Nullable T, R> mappingFunction) {
return mappingFunction.apply(value);
}
/**
* Returns the passed value if it is not {@code null} and matches the predicate and {@code null} otherwise.
*
* @param value tested value
* @param predicate condition to test the value agains
* @param type of the value
* @return {@code value} if it is not {@code null} and matches the predicate and {@code null} otherwise.
*
* @throws NullPointerException if {@code predicate} is {@code null}
*/
@SuppressWarnings("Contract") // Lombok's annotation is treated incorrectly
@Contract("_, null -> fail; !null, _ -> _; null, _ -> null")
public @Nullable T _filter(final @Nullable T value,
final @NonNull Predicate predicate) {
return value == null ? null : predicate.test(value) ? value : null;
}
/**
* Returns the passed value if it matches the predicate and {@code null} otherwise.
*
* @param value tested value
* @param predicate condition to test the value agains
* @param type of the value
* @return {@code value} if it matches the predicate and {@code null} otherwise.
*
* @throws NullPointerException if {@code predicate} is {@code null}
*/
@SuppressWarnings("Contract") // Lombok's annotation is treated incorrectly
@Contract("_, null -> fail; _, _ -> _")
public @Nullable T _filterNullable(final @Nullable T value, final @NonNull Predicate<@Nullable T> predicate) {
return predicate.test(value) ? value : null;
}
/**
* Throws the supplied exception if the given value is null.
*
* @param value checked value
* @param throwableSupplier supplier of a throwable used when the value is {@code null}
* @param type of the value
* @param thrown type throwable
* @return {@code value} if it is not {@code null}
*
* @throws X if {@code value} is null
* @throws NullPointerException if {@code throwableSupplier} or it supplies {@code null}
*/
@SuppressWarnings("Contract") // Lombok's annotation is treated incorrectly
@Contract("null, _ -> fail; _, null -> fail; _, _ -> param1")
public @NotNull T _orElseThrow(final @Nullable T value,
final @NonNull Supplier<@NonNull X>
throwableSupplier) throws X {
if (value == null) throw throwableSupplier.get();
return value;
}
/**
* Runs the corresponding action depending on whether the value is {@code null}.
*
* @param value value to be checked
* @param action action to be run on non-{@code null} value
* @param nullAction action to be run if the value is {@code null}
* @param type of the value
*
* @throws NullPointerException if {@code action} or {@code nullAction} is {@code null}
*/
@SuppressWarnings("Contract") // Lombok's annotation is treated incorrectly
@Contract("_, null, _ -> fail; _, _, null -> fail")
public void _ifPresentOrElse(final @Nullable T value,
final @NonNull Consumer<@NotNull ? super T> action,
final @NonNull Runnable nullAction) {
if (value == null) nullAction.run();
else action.accept(value);
}
/**
* Converts the given value into a {@link Stream stream} containing the value
* if is not {@code null} or an {@link Stream#empty() empty stream} otherwise.
*
* @param value value to be converted into a stream if it is not {@code null}
* @param type of the value
* @return {@link Stream stream} containing the value if it is not {@code null}
* or an {@link Stream#empty() empty stream} otherwise.
*/
public @NotNull Stream<@NotNull T> _stream(final @Nullable T value) {
return value == null ? Stream.empty() : Stream.of(value);
}
/**
* Converts the given value into a {@link Stream stream}.
*
* @param value value to be converted into a stream if it is not {@code null}
* @param type of the value
* @return {@link Stream stream} containing the value.
*/
public @NotNull Stream<@Nullable T> _streamOfNullable(final @Nullable T value) {
return Stream.of(value);
}
/**
* Converts the value into an {@link Optional optional}
* returning {@link Optional#empty()} if the value is {@code null}.
*
* @param value value to be converted into an optional
* @param type of the value
* @return value wrapped into an {@link Optional}
*/
@Contract("null -> _; _ -> new")
public @NotNull Optional _toOptional(final @Nullable T value) {
return Optional.ofNullable(value);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy