[java] java.util. @ Nullable의 의미는 무엇입니까?

일부 코드 에서 주석 을 찾은 구아바 코드를 읽고 java.util.@Nullable있습니다. 의 의미는 알지만 @Nullable이해하지 못합니다. 특히 Nullable패키지에서 호출 된 클래스를 찾을 수 없습니다 java.util. 누군가가 이것의 의미가 무엇인지 말해주십시오 java.util.@Nullable.

public static <T> java.util.@Nullable Optional<T> toJavaUtil(
    @Nullable Optional<T> googleOptional) {
  return googleOptional == null ? null : googleOptional.toJavaUtil();
}



답변

public static <T> java.util.@Nullable Optional<T> toJavaUtil일반적인 스타일 public static <T> @Nullable java.util.Optional<T> toJavaUtil이 유효하지 않기 때문에 행 은 다음과 같이 작성 됩니다. 이것은 JLS §9.7.4에 정의되어 있습니다 .

T 유형의 주석이 유형 컨텍스트의 유형 (또는 유형의 일부)에 적용되고 T가 유형 컨텍스트에 적용 가능하고 주석이 허용되지 않으면 컴파일 타임 오류입니다.

예를 들어 just로 메타 주석이 달린 주석 유형 TA를 가정하십시오 @Target(ElementType.TYPE_USE). 용어 @TA java.lang.Object와는 java.@TA lang.Object단순한 이름이있는에 @TA가 가장 가까운 패키지 이름으로 분류되어 있기 때문에 불법이다. 반면에 java.lang.@TA Object합법적입니다.

유형 선언 org.checkerframework.checker.nullness.qual@Nullable은 다음과 같습니다.

@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})

이 규칙에 적용됩니다.

패키지 java.util와 클래스 이름 Optional이 분리되어 있기 때문에이 구조가 실행을 중단시키지 않는다는 것은 다음을 사용하여 컴파일 된 코드를 볼 때 볼 수 있습니다 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디 컴파일 / 컴파일하기위한 최소한의 예제를 얻기 위해 Guava 코드를 복사 한 로컬 클래스입니다)

보시다시피 주석은 더 이상 존재하지 않습니다. 메소드가 널 (및 소스 코드 리더에 대한 힌트)을 리턴 할 때 경고를 방지하는 것은 컴파일러의 마커 일 뿐이지 만 컴파일 된 코드에는 포함되지 않습니다.


이 컴파일러 오류는 다음과 같은 변수에도 적용됩니다.

private @Nullable2 java.util.Optional<?> o;

그러나 주석 ElementType.FIELD이 동일한 JLS 절에 작성된대로 대상 유형을 추가로 가져 오면 허용 될 수 있습니다 .

TA에 추가로 메타 주석이 추가 된 경우 필드 선언과 같이 선언 및 유형 컨텍스트가 모두있는 위치에서이 @Target(ElementType.FIELD)용어 @TA java.lang.Object가 유효합니다 @TA java.lang.Object f;. 여기서 TA는 필드 선언 컨텍스트에 적용 할 수 있으므로 @TA는 f 선언 (java.lang.Object 유형이 아닌)에 적용되는 것으로 간주됩니다.


답변

주석을 사용할 때 import 문을 추가하는 대신 형식의 정규화 된 이름을 쓰려고 할 때 사용되는 구문입니다.

체커 프레임 워크 매뉴얼 에서 인용 :

정규화 된 유형 이름에 주석을 작성하는 올바른 Java 구문은 java.util. @ Nullable List에서와 같이 단순 이름 부분에 주석을 추가하는 것입니다. 그러나 소스 파일에 import java.util.List를 추가하면 @Nullable List 만 작성할 수 있습니다.

여기에서 다운로드 할 수있는 JSR308 사양의 2 페이지에 나와 있습니다 . 그것은 말한다 :

@NonNull String 또는 java.lang. @ NonNull String과 같이 형식의 간단한 이름 앞에 형식 주석이 나타납니다.


답변

여기서 이상한 점은 실제로 ElementType.TYPE_USE-targeted 주석 을 적용하는 익숙하지 않은 구문입니다 . 당신이 선택하면 Null 허용 의 문서를, 당신은 낯선 대상을 볼 수 있습니다 :

...
@Target(value={TYPE_USE,TYPE_PARAMETER})
<public @interface Nullable
...

이 주석은 다음 두 가지 모두와 같이 주석이 달린 유형의 단순 이름 바로 앞에 사용됩니다.

public static <T> @Nullable Optional<T> toJavaUtil
public static <T> java.util.@Nullable Optional<T> toJavaUtil

나는 이런 종류의 대상이 무엇인지 알지 못했기 때문에 빠른 읽기 후에이 간단한 예제를 보았습니다.이 예제는 해당 대상이있는 주석을 사용하여 반환 유형 메타 데이터를 선택합니다.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
@interface InterceptedReturnValue {
    boolean value() default true;
}

그리고 다음을 사용하여 처리했습니다.

public java.lang.@InterceptedReturnValue(true) String testMethod(String param) {
    return null;
}

public @InterceptedReturnValue(false) String testMethod(int param) {
    return null;
}

public static void main(String[] args) throws Exception {
    Method m = Main.class.getDeclaredMethod("testMethod", String.class);
    if(m.getAnnotatedReturnType().isAnnotationPresent(InterceptedReturnValue.class)) {
        InterceptedReturnValue config = m.getAnnotatedReturnType()
                .getAnnotation(InterceptedReturnValue.class);

        if(config.value()) {
            //logging return value enabled
        }
    }
}

체커 프레임 워크와 같은 많은 유용한 프레임 워크가 가장 적절하게 사용된다고 확신합니다. ElementType.TYPE_USE


답변