org.eclipse.jdt.annotation.Checks Maven / Gradle / Ivy
Show all versions of org.eclipse.jdt.annotation Show documentation
/*******************************************************************************
* Copyright (c) 2016, 2019 Stephan Herrmann and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Stephan Herrmann - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.annotation;
import java.util.Collection;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* Utility functions intended for use with the null annotations defined in this package.
*
*
* For maximum generality, all type parameters of methods in this class are not constraint
* to either non-null nor nullable. Users of these methods can freely choose these types.
*
*
* Methods in this class come in three groups: Assertions, Requirements, as well as Queries, conversions and computations.
*
*
* Assertions
*
* All methods in this group start with the prefix "assert", and work similar to the assert
keyword.
*
*
* - One or more values are checked for
null
.
* - If any value is
null
, an exception is thrown.
* - The method has no other effect (except for potential side effects in an Iterator).
*
*
* Requirements
*
* All methods in this group start with the prefix "require". They encode domain knowledge of the developer
* and make this knowledge visible to static null analysis.
*
*
* - One or more values are checked for
null
.
* - If any value is
null
, an exception is thrown.
* - Otherwise a guaranteed non-null value is returned.
*
* For Strings and Collections additional checks for empty may be included.
*
* Typical usage includes the case of interfacing with legacy API, that is not specified using
* null annotations, but where corresponding guarantees are given informally:
*
*
* interface LegacyThing {
* {@literal /}** @return the name of this thing, never <code>null</code>. *{@literal /}
* String getName();
* }
* ...
* public void process(@NonNull LegacyThing t) {
* {@literal @}NonNull String name = Checks.requireNonNull(t.getName(), "LegacyThing is supposed to have a name");
* ...
* }
*
*
* Queries, conversions and computations
*
* A commonality among methods in this group is the null-safety that can be verified by static null analysis,
* hence in a fully analyzed program none of these methods should throw an exception.
*
*
* - boolean queries
* - Methods {@link #isNull(Object)}, {@link #isAnyNull(Object...)}, {@link #containsNull(Iterable)} simply
* answer whether a null value could be found in the argument(s).
* - conversions
* - Methods {@link #nonNullElse(Object, Object)}, {@link #nonNullElseGet(Object, Supplier)}, {@link #asNullable(Optional)}
* and the {@link #unboxElse(Boolean, boolean)} family of methods provide null-safe conversions,
* which can be checked by static analysis.
* - computations
* - Methods {@link #ifNonNull(Object, Consumer)}, {@link #applyIfNonNull(Object, Function)},
* {@link #applyIfNonNullElse(Object, Function, Object)} and {@link #applyIfNonNullElseGet(Object, Function, Supplier)}
* feed unsafe values into a given functional expression in a null-safe way.
*
*
* @since 2.1
*/
public class Checks {
/**
* Checks whether any of the provided values is null
.
* @param values arbitrary values to be checked
* @throws NullPointerException if a null
was found among values.
*/
@SafeVarargs
public static void assertNonNull(T @NonNull... values) {
for (int i = 0; i < values.length; i++) {
if (values[i] == null)
throw new NullPointerException("Value in position "+i+" must not be null"); //$NON-NLS-1$//$NON-NLS-2$
}
}
/**
* Checks whether any of the provided values is null
.
* @param message explanatory message to be used when throwing {@link NullPointerException}.
* @param values arbitrary values to be checked
* @throws NullPointerException if a null
was found among values.
*/
@SafeVarargs
public static void assertNonNullWithMessage(String message, T @NonNull... values) {
for (T v : values)
if (v == null)
throw new NullPointerException(message);
}
/**
* Checks whether any element in the provided values is null
.
* @param values an Iterable of arbitrary values to be checked
* @throws NullPointerException if a null
was found among the elements in values.
*/
public static void assertNonNullElements(@NonNull Iterable values) {
int count = 0;
for (T v : values) {
if (v == null)
throw new NullPointerException("Value in position "+count+" must not be null"); //$NON-NLS-1$ //$NON-NLS-2$
count++;
}
}
/**
* Checks whether any of the provided values is null
.
* @param values an iterable of arbitrary values to be checked
* @param message explanatory message to be used when throwing {@link NullPointerException}.
* @throws NullPointerException if a null
was found among the elements in values.
*/
public static void assertNonNullElements(@NonNull Iterable values, String message) {
for (T v : values)
if (v == null)
throw new NullPointerException(message);
}
/**
* Answer the given value as a non-null value.
* Throws {@link NullPointerException} if the given value was null
.
*
* @param value an arbitrary value, maybe null
.
* @return the original passed value, guaranteed not to be null
.
*
* @throws NullPointerException if the given value was null
.
*/
public static @NonNull T requireNonNull(@Nullable T value) {
if (value == null)
throw new NullPointerException();
return value;
}
/**
* Answer the given value as a non-null value.
* Throws {@link NullPointerException} if the given value was null
.
*
* @param value an arbitrary value, maybe null
.
* @param message explanatory message to be used when throwing {@link NullPointerException}.
* @return the original passed value, guaranteed not to be null
.
*
* @throws NullPointerException if the given value was null
.
*/
public static @NonNull T requireNonNull(@Nullable T value, @NonNull String message) {
if (value == null)
throw new NullPointerException(message);
return value;
}
/**
* Answer the given value, guaranteeing it to be neither null
nor
* an empty string.
*
* @param value value to be checked
* @return the given value, guaranteed to be neither null
nor
* and empty string.
*
* @throws NullPointerException if the given value was null
* @throws IllegalArgumentException if the given value was an empty string.
*/
public static @NonNull String requireNonEmpty(@Nullable String value) {
if (value == null)
throw new NullPointerException();
if (value.isEmpty())
throw new IllegalArgumentException();
return value;
}
/**
* Answer the given value, guaranteeing it to be neither null
nor
* an empty string.
*
* @param value value to be checked
* @param message explanatory message to be used when throwing an exception.
* @return the given value, guaranteed to be neither null
nor
* an empty string.
*
* @throws NullPointerException if the given value was null
* @throws IllegalArgumentException if the given value was an empty string.
*/
public static @NonNull String requireNonEmpty(@Nullable String value, String message) {
if (value == null)
throw new NullPointerException(message);
if (value.isEmpty())
throw new IllegalArgumentException(message);
return value;
}
/**
* Answer the given value, guaranteeing it to be neither null
nor
* an empty collection. This method doesn't make any statement about whether
* or not elements in the collection can possibly be null
.
*
* @param value value to be checked
* @return the given value, guaranteed to be neither null
nor
* an empty collection.
*
* @throws NullPointerException if the given value was null
* @throws IllegalArgumentException if the given value was an empty collection.
*/
public static > @NonNull C requireNonEmpty(@Nullable C value) {
if (value == null)
throw new NullPointerException();
if (value.isEmpty())
throw new IllegalArgumentException();
return value;
}
/**
* Answer the given value, guaranteeing it to be neither null
nor
* an empty collection. This method doesn't make any statement about whether
* or not elements in the collection can possibly be null
.
*
* @param value value to be checked
* @param message explanatory message to be used when throwing an exception.
* @return the given value, guaranteed to be neither null
nor
* an empty collection.
*
* @throws NullPointerException if the given value was null
* @throws IllegalArgumentException if the given value was an empty collection.
*/
public static > @NonNull C requireNonEmpty(@Nullable C value, String message) {
if (value == null)
throw new NullPointerException(message);
if (value.isEmpty())
throw new IllegalArgumentException(message);
return value;
}
/**
* Answer whether the given value is null
.
* Calling this method should express that a null check is performed
* which the compiler would normally deem unnecessary or redundant.
* By calling this method, these warnings will be avoided, and readers
* of that code will be informed that the check is redundant with respect
* to null analysis, and done only as a measure for extra safety.
* @param value an object which analysis at the call-site considers as non-null
* @return true if the argument is null
, else false.
*/
@SuppressWarnings("null") // intentionally performing a redundant check
public static boolean isNull(@NonNull Object value) { return value == null; }
/**
* Answer whether any of the given values is null
.
* Depending on the nullness of concrete types for T
,
* this method may or may not be redundant from the point of view of
* static analysis.
* @param values arbitrary values to be checked
* @return true if the argument is null
, else false.
*/
@SafeVarargs
public static boolean isAnyNull(T @NonNull... values) {
for (int i = 0; i < values.length; i++) {
if (values[i] == null)
return true;
}
return false;
}
/**
* Answer whether an element in the provided values is null
.
* Depending on the nullness of the given Iterable
's type argument,
* this method may or may not be redundant from the point of view of
* static analysis.
* @param values an iterable of arbitrary values
* @return true if the argument contains the value null
, else false.
*/
public static boolean containsNull(@NonNull Iterable> values) {
for (Object value : values) {
if (value == null)
return true;
}
return false;
}
/**
* Answer the value of an {@link Optional}, or null
if it has no value.
*
* @param optional wrapper for an optional value
* @return the value or null
.
*/
public static @Nullable T asNullable(@NonNull Optional optional) {
if (optional.isPresent())
return optional.get();
return null;
}
/**
* Answer the given value as a non-null value.
* If the value was actually null
the alternative 'fallbackValue' is returned.
*
* @param value an arbitrary value, maybe null
.
* @param fallbackValue value to be returned when the value is null
.
*
* @return the original passed value, guaranteed not to be null
, or the fallback value.
*/
public static @NonNull T nonNullElse(@Nullable T value, @NonNull T fallbackValue) {
if (value == null)
return fallbackValue;
return value;
}
/**
* Answer the given value as a non-null value.
* If the value was actually null
an alternative is computed by
* invoking the given 'fallbackSupplier'.
*
* @param value an arbitrary value, maybe null
.
* @param fallbackSupplier will compute the value to be returned when the 'value' is null
.
*
* @return the original passed value, guaranteed not to be null
,
* or a fallback value provided by the 'fallbackSupplier'.
*/
public static @NonNull T nonNullElseGet(@Nullable T value, @NonNull Supplier extends @NonNull T> fallbackSupplier) {
if (value == null)
return fallbackSupplier.get();
return value;
}
/**
* Invoke the given consumer if and only if the given value is not null
.
* Otherwise do nothing.
* @param value the value to be checked for null and possibly passed into the consumer.
* @param consumer the consumer to invoke after checking the value for null.
*/
public static void ifNonNull(@Nullable T value, @NonNull Consumer<@NonNull ? super T> consumer) {
if (value != null)
consumer.accept(value);
}
/**
* Apply the given function if and only if the given value is not null
.
* @param value the value to be checked for null
and possibly passed into the function.
* @param function the function to apply after checking the value for null
.
* @return the result of applying 'function' with 'value',
* or null
if 'value' was null
*/
public static @Nullable U applyIfNonNull(@Nullable T value, @NonNull Function<@NonNull ? super T, ? extends U> function) {
if (value != null)
return function.apply(value);
return null;
}
/**
* Apply the given function if and only if the given value is not null
.
* @param value the value to be checked for null
and possibly passed into the function.
* @param function the function to apply after checking the value for null
.
* @param fallbackValue value to be returned when the 'value' is null
.
* @return the result of applying 'function' with 'value',
* or the 'fallbackValue' if 'value' was null
*/
public static U applyIfNonNullElse(@Nullable T value, @NonNull Function<@NonNull ? super T, ? extends U> function, U fallbackValue) {
if (value != null)
return function.apply(value);
return fallbackValue;
}
/**
* Apply the given function if and only if the given value is not null
.
* @param value the value to be checked for null
and possibly passed into the function.
* @param function the function to apply after checking the value for null
.
* @return the result of applying 'function' with 'value',
* or a value provided by invoking 'fallbackSupplier' if 'value' was null
*/
public static U applyIfNonNullElseGet(@Nullable T value, @NonNull Function<@NonNull ? super T, ? extends U> function,
@NonNull Supplier extends U> fallbackSupplier)
{
if (value != null)
return function.apply(value);
return fallbackSupplier.get();
}
/**
* Unbox the given 'boxedValue' if and only if it is not null
.
* Otherwise the given 'fallbackValue' is returned.
* @param boxedValue value, can be null
.
* @param fallbackValue the value to use if 'boxedValue' is null
* @return either the unboxed boolean corresponding to 'boxedValue' or
* 'fallbackValue' if 'boxedValue' was null
.
*/
public static boolean unboxElse(@Nullable Boolean boxedValue, boolean fallbackValue) {
if (boxedValue == null)
return fallbackValue;
return boxedValue.booleanValue();
}
/**
* Unbox the given 'boxedValue' if and only if it is not null
.
* Otherwise the given 'fallbackValue' is returned.
* @param boxedValue value, can be null
.
* @param fallbackValue the value to use if 'boxedValue' is null
* @return either the unboxed byte corresponding to 'boxedValue' or
* 'fallbackValue' if 'boxedValue' was null
.
*/
public static byte unboxElse(@Nullable Byte boxedValue, byte fallbackValue) {
if (boxedValue == null)
return fallbackValue;
return boxedValue.byteValue();
}
/**
* Unbox the given 'boxedValue' if and only if it is not null
.
* Otherwise the given 'fallbackValue' is returned.
* @param boxedValue value, can be null
.
* @param fallbackValue the value to use if 'boxedValue' is null
* @return either the unboxed char corresponding to 'boxedValue' or
* 'fallbackValue' if 'boxedValue' was null
.
*/
public static char unboxElse(@Nullable Character boxedValue, char fallbackValue) {
if (boxedValue == null)
return fallbackValue;
return boxedValue.charValue();
}
/**
* Unbox the given 'boxedValue' if and only if it is not null
.
* Otherwise the given 'fallbackValue' is returned.
* @param boxedValue value, can be null
.
* @param fallbackValue the value to use if 'boxedValue' is null
* @return either the unboxed int corresponding to 'boxedValue' or
* 'fallbackValue' if 'boxedValue' was null
.
*/
public static int unboxElse(@Nullable Integer boxedValue, int fallbackValue) {
if (boxedValue == null)
return fallbackValue;
return boxedValue.intValue();
}
/**
* Unbox the given 'boxedValue' if and only if it is not null
.
* Otherwise the given 'fallbackValue' is returned.
* @param boxedValue value, can be null
.
* @param fallbackValue the value to use if 'boxedValue' is null
* @return either the unboxed long corresponding to 'boxedValue' or
* 'fallbackValue' if 'boxedValue' was null
.
*/
public static long unboxElse(@Nullable Long boxedValue, long fallbackValue) {
if (boxedValue == null)
return fallbackValue;
return boxedValue.longValue();
}
/**
* Unbox the given 'boxedValue' if and only if it is not null
.
* Otherwise the given 'fallbackValue' is returned.
* @param boxedValue value, can be null
.
* @param fallbackValue the value to use if 'boxedValue' is null
* @return either the unboxed short corresponding to 'boxedValue' or
* 'fallbackValue' if 'boxedValue' was null
.
*/
public static short unboxElse(@Nullable Short boxedValue, short fallbackValue) {
if (boxedValue == null)
return fallbackValue;
return boxedValue.shortValue();
}
/**
* Unbox the given 'boxedValue' if and only if it is not null
.
* Otherwise the given 'fallbackValue' is returned.
* @param boxedValue value, can be null
.
* @param fallbackValue the value to use if 'boxedValue' is null
* @return either the unboxed float corresponding to 'boxedValue' or
* 'fallbackValue' if 'boxedValue' was null
.
*/
public static float unboxElse(@Nullable Float boxedValue, float fallbackValue) {
if (boxedValue == null)
return fallbackValue;
return boxedValue.floatValue();
}
/**
* Unbox the given 'boxedValue' if and only if it is not null
.
* Otherwise the given 'fallbackValue' is returned.
* @param boxedValue value, can be null
.
* @param fallbackValue the value to use if 'boxedValue' is null
* @return either the unboxed double corresponding to 'boxedValue' or
* 'fallbackValue' if 'boxedValue' was null
.
*/
public static double unboxElse(@Nullable Double boxedValue, double fallbackValue) {
if (boxedValue == null)
return fallbackValue;
return boxedValue.doubleValue();
}
}