ความหมายของ java.util คืออะไร @ Nullable?


56

ฉันกำลังอ่านโค้ดของ Guavaที่ฉันพบบันทึกย่อ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();
}

4
@ PaulRooney ฉันไม่คิดอย่างนั้น Nullableพวกเขากำลังพูดถึงดูเหมือนว่าจะมีในไม่javax.annotation java.util
— Joseph Sible-Reinstate Monica

3
ฉันสงสัยว่านี่อาจเป็น Java-syntax-ism ที่แปลกหรือเปล่า โดยเฉพาะอย่างยิ่งนี่อาจหมายถึงเพียงpublic static <T> @Nullable java.util.Optional<T> toJavaUtilแต่ Java นั้นไม่ยอมให้คุณเขียนอย่างนั้น?
— Joseph Sible-Reinstate Monica

1
@JosephSible public static <T> @Nullable java.util.Optional<T> toJavaUtilเป็นไปไม่ได้จริง ๆ แต่ไม่มีเหตุผลที่จะใช้ FQN Optionalเมื่อมีการนำเข้าอยู่แล้ว
— ทอม

6
@Tom มีอีกOptionalขอบเขตอยู่ที่นั่น
— Joseph Sible-Reinstate Monica

2
ขอบคุณพวกฉันพบมันใน Checker Framework @Nullable java.util.List The correct Java syntax to write an annotation on a fully-qualified type name is to put the annotation on the simple name part, as in java.util.@Nullable List. But, it’s usually better to add import java.util.List to your source file, so that you can just write @Nullable List.
— SetDaemon

คำตอบ:


37

บรรทัดpublic static <T> java.util.@Nullable Optional<T> toJavaUtilถูกเขียนเช่นนี้เนื่องจากสไตล์ปกติpublic static <T> @Nullable java.util.Optional<T> toJavaUtilไม่ถูกต้อง สิ่งนี้กำหนดไว้ในJLS §9.7.4 :

มันเป็นข้อผิดพลาดในการคอมไพล์เวลาหากการเพิ่มความคิดเห็นของประเภท T นำไปใช้กับประเภท (หรือส่วนใดส่วนหนึ่งของประเภท) ในบริบทประเภทและ T สามารถใช้งานได้ในบริบทประเภทและคำอธิบายประกอบไม่สามารถยอมรับได้

ตัวอย่างเช่นสมมติประเภทคำอธิบายประกอบ 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 เพื่อให้ได้ตัวอย่างน้อยที่สุดในการกำจัด / คอมไพล์)

อย่างที่คุณเห็นคำอธิบายประกอบจะไม่มีอยู่อีกต่อไป มันเป็นเพียงเครื่องหมายสำหรับคอมไพเลอร์เพื่อป้องกันการเตือนเมื่อเมธอดส่งคืน null (และคำใบ้สำหรับตัวอ่านซอร์สโค้ด) แต่จะไม่รวมอยู่ในโค้ดที่คอมไพล์


ข้อผิดพลาดของคอมไพเลอร์นี้ยังนำไปใช้กับตัวแปรเช่น:

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

แต่สามารถยอมรับได้เมื่อคำอธิบายประกอบเพิ่มประเภทเป้าหมาย ElementType.FIELDตามที่เขียนไว้ในข้อ JLS เดียวกัน:

หาก TA ยังเป็นอภิกำกับด้วย@Target(ElementType.FIELD)แล้วคำว่าเป็นกฎหมายในสถานที่ซึ่งมีทั้งการประกาศและประเภทบริบทเช่นการประกาศเขต@TA java.lang.Object @TA java.lang.Object f;ที่นี่ @TA จะถือว่ามีผลบังคับใช้กับการประกาศ f (และไม่ใช้กับประเภท java.lang.Object) เนื่องจาก TA ใช้งานได้ในบริบทการประกาศฟิลด์


11

เมื่อใช้คำอธิบายประกอบนี่เป็นไวยากรณ์ที่ใช้เมื่อคุณต้องการเขียนชื่อแบบเต็มสำหรับประเภทแทนที่จะเพิ่มคำสั่งนำเข้า

การอ้างอิงจากกรอบงานตัวตรวจสอบ :

ไวยากรณ์ Java ที่ถูกต้องในการเขียนคำอธิบายประกอบบนชื่อชนิดที่ผ่านการรับรองอย่างสมบูรณ์คือการใส่คำอธิบายประกอบบนส่วนชื่อแบบง่ายเช่นใน java.util. @ Nullable List แต่โดยปกติแล้วจะเป็นการดีกว่าที่จะเพิ่มการนำเข้า java.util.List ลงในซอร์สไฟล์ของคุณเพื่อให้คุณสามารถเขียน @Nullable List ได้

นอกจากนี้ยังกล่าวถึงในหน้า 2 ของJSR308เปคซึ่งสามารถดาวน์โหลดได้ที่นี่ มันบอกว่า:

คำอธิบายประกอบประเภทจะปรากฏขึ้นต่อหน้าชื่อแบบง่ายของประเภทเช่นใน @NonNull String หรือ java.lang. @ NonNull String


6

บิตแปลกที่นี่จริงๆเป็นไวยากรณ์ที่ไม่คุ้นเคยสำหรับการใช้ElementType.TYPE_USEคำอธิบายประกอบแบบกำหนดเป้าหมาย หากคุณตรวจสอบเอกสารของNullableคุณจะเห็นเป้าหมายที่ไม่คุ้นเคย:

...
@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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.