blob: b6c7b029f43762e96959c034a735ddd290860bdb [file] [log] [blame]
package org.checkerframework.checker.nullness.util;
import java.util.NoSuchElementException;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.framework.qual.AnnotatedFor;
/**
* Utility class for the Nullness Checker, providing every method in {@link java.util.Optional}, but
* written for possibly-null references rather than for the {@code Optional} type.
*
* <p>To avoid the need to write the {@code Opt} class name at invocation sites, do:
*
* <pre>import static org.checkerframework.checker.nullness.util.Opt.orElse;</pre>
*
* or
*
* <pre>import static org.checkerframework.checker.nullness.util.Opt.*;</pre>
*
* <p><b>Runtime Dependency</b>: If you use this class, you must distribute (or link to) {@code
* checker-qual.jar}, along with your binaries. Or, you can can copy this class into your own
* project.
*
* @see java.util.Optional
*/
@AnnotatedFor("nullness")
public final class Opt {
/** The Opt class cannot be instantiated. */
private Opt() {
throw new AssertionError("shouldn't be instantiated");
}
/**
* If primary is non-null, returns it, otherwise throws NoSuchElementException.
*
* @param <T> the type of the argument
* @param primary a non-null value to return
* @return {@code primary} if it is non-null
* @throws NoSuchElementException if primary is null
* @see java.util.Optional#get()
*/
// `primary` is @NonNull; otherwise, the method could throw an exception.
public static <T extends @NonNull Object> T get(T primary) {
if (primary == null) {
throw new NoSuchElementException("No value present");
}
return primary;
}
/**
* Returns true if primary is non-null, false if primary is null.
*
* @see java.util.Optional#isPresent()
*/
@EnsuresNonNullIf(expression = "#1", result = true)
public static boolean isPresent(@Nullable Object primary) {
return primary != null;
}
/**
* If primary is non-null, invoke the specified consumer with the value, otherwise do nothing.
*
* @see java.util.Optional#ifPresent(Consumer)
*/
public static <T> void ifPresent(T primary, Consumer<@NonNull ? super @NonNull T> consumer) {
if (primary != null) {
consumer.accept(primary);
}
}
/**
* If primary is non-null, and its value matches the given predicate, return the value. If primary
* is null or its non-null value does not match the predicate, return null.
*
* @see java.util.Optional#filter(Predicate)
*/
public static <T> @Nullable T filter(
T primary, Predicate<@NonNull ? super @NonNull T> predicate) {
if (primary == null) {
return null;
} else {
return predicate.test(primary) ? primary : null;
}
}
/**
* If primary is non-null, apply the provided mapping function to it and return the result. If
* primary is null, return null.
*
* @see java.util.Optional#map(Function)
*/
public static <T, U> @Nullable U map(
T primary, Function<@NonNull ? super @NonNull T, ? extends U> mapper) {
if (primary == null) {
return null;
} else {
return mapper.apply(primary);
}
}
// flatMap would have the same signature and implementation as map
/**
* Return primary if it is non-null. If primary is null, return other.
*
* @see java.util.Optional#orElse(Object)
*/
public static <T> @NonNull T orElse(T primary, @NonNull T other) {
return primary != null ? primary : other;
}
/**
* Return primary if it is non-null. If primary is null, invoke {@code other} and return the
* result of that invocation.
*
* @see java.util.Optional#orElseGet(Supplier)
*/
public static <T> @NonNull T orElseGet(T primary, Supplier<? extends @NonNull T> other) {
return primary != null ? primary : other.get();
}
/**
* Return primary if it is non-null. If primary is null, throw an exception to be created by the
* provided supplier.
*
* @see java.util.Optional#orElseThrow(Supplier)
*/
// `primary` is @NonNull; otherwise, the method could throw an exception.
public static <T extends @NonNull Object, X extends @NonNull Throwable> T orElseThrow(
T primary, Supplier<? extends X> exceptionSupplier) throws X {
if (primary != null) {
return primary;
} else {
throw exceptionSupplier.get();
}
}
}