I'm reading the code of Guava where I found the annotation java.util.@Nullable
in some code. I know the meaning of @Nullable
, but I don't understand this one. In particular, I can't find a class called Nullable
in the package java.util
. Please, someone tell me what's the meaning of this java.util.@Nullable
:
public static <T> java.util.@Nullable Optional<T> toJavaUtil( @Nullable Optional<T> googleOptional) { return googleOptional == null ? null : googleOptional.toJavaUtil(); }
@NullableMethod calls that can return null. Variables (fields, local variables, and parameters), that can be null.
You typically use a nullable value type when you need to represent the undefined value of an underlying value type. For example, a Boolean, or bool , variable can only be either true or false . However, in some applications a variable value can be undefined or missing.
... you can use: Boolean myval = null; You can assign it like this: myval = new Boolean(true);
On the other hand, if the parameter is mark as @Nullable and we don't add null check inside the function, Android Studio will warn you with lint error and some visual hint. The @NonNull/@Nullable annotation can put in front of functions as well to indicate the return value nullability.
The line public static <T> java.util.@Nullable Optional<T> toJavaUtil
is written like this, because the usual style public static <T> @Nullable java.util.Optional<T> toJavaUtil
is invalid. This is defined in the JLS §9.7.4:
It is a compile-time error if an annotation of type T applies to a type (or any part of a type) in a type context, and T is applicable in type contexts, and the annotation is not admissible.
For example, assume an annotation type TA which is meta-annotated with just
@Target(ElementType.TYPE_USE)
. The terms@TA java.lang.Object
andjava.@TA lang.Object
are illegal because the simple name to which @TA is closest is classified as a package name. On the other hand,java.lang.@TA Object
is legal.
The type declaration of org.checkerframework.checker.nullness.qual@Nullable
is:
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
So it is applying to this rule.
That this structure doesn't break the execution, since package java.util
and class name Optional
were split, can be seen when we look at the compiled code using javap -c [compiled class name]
:
class just.a.test.Main { just.a.test.Main(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static <T> java.util.Optional<T> toJavaUtil(blub.Optional<T>); Code: 0: aload_0 1: ifnonnull 8 4: aconst_null 5: goto 12 8: aload_0 9: invokevirtual #2 // Method blub/Optional.toJavaUtil:()Ljava/util/Optional; 12: areturn }
(blub.Optional
is a local class where I copied the Guava code in, in order to get a minimal example to de-/compile)
As you can see, the annotation doesn't exist there anymore. It is only a marker for the compiler to prevent a warning when the method returns null (and a hint for the source code readers), but it won't be included in the compiled code.
This compiler error also applies to variables like:
private @Nullable2 java.util.Optional<?> o;
But can become acceptable when the annotation additionally gets the target type ElementType.FIELD
, as written in the same JLS clause:
If TA is additionally meta-annotated with
@Target(ElementType.FIELD)
, then the term@TA java.lang.Object
is legal in locations which are both declaration and type contexts, such as a field declaration@TA java.lang.Object f;
. Here, @TA is deemed to apply to the declaration of f (and not to the type java.lang.Object) because TA is applicable in the field declaration context.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With