NullPointerExceptions을 피하기 위해 IDE 코드 검사 및 정적 코드 분석 (FindBugs 및 Sonar)과 같은 툴링을 사용하고 코드를 더 읽기 쉽게 만들고 싶습니다. 많은 도구가 서로의 @NotNull
/ @NonNull
/ @Nonnull
주석과 호환되지 않는 것처럼 보이며 내 코드에 모든 도구를 나열하는 것은 끔찍할 것입니다. 어느 것이 ‘최고’인지에 대한 제안? 내가 찾은 동등한 주석 목록은 다음과 같습니다.
-
javax.validation.constraints.NotNull
정적 분석이 아닌 런타임 유효성 검사를 위해 작성되었습니다.
선적 서류 비치 -
edu.umd.cs.findbugs.annotations.NonNull
에서 사용 Findbugs 때문에 정적 분석 및 수중 음파 탐지기 (지금 Sonarqube )
문서 -
javax.annotation.Nonnull
이것은 Findbugs에서도 작동하지만 JSR-305 는 비활성화되어 있습니다. ( JSR 305의 상태는 무엇입니까? 참조 )
source -
org.jetbrains.annotations.NotNull
정적 분석을 위해 IntelliJ IDEA IDE에서 사용합니다.
선적 서류 비치 -
lombok.NonNull
Project Lombok 에서 코드 생성을 제어하는 데 사용됩니다 .
표준이 없으므로 자리 표시 자 주석
소스 ,
문서 -
android.support.annotation.NonNull
지원 주석 패키지 설명서를 통해 제공되는 Android에서 마커 주석 사용 가능
-
org.eclipse.jdt.annotation.NonNull
정적 코드 분석 문서를 위해 Eclipse에서 사용
답변
이후 JSR 305 (누구의 목표를 표준화하는 것이었다 @NonNull
과 @Nullable
) 몇 년 동안 잠복하고있다, 난 두려워 좋은 답변이 없습니다. 우리가 할 수있는 것은 실용적인 해결책을 찾는 것입니다.
통사론
순수한 스타일 관점에서 IDE, 프레임 워크 또는 Java 자체를 제외한 툴킷에 대한 언급을 피하고 싶습니다.
이것은 배제한다 :
android.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
org.checkerframework.checker.nullness.qual
lombok.NonNull
어느 하나 우리 잎 javax.validation.constraints
이나 javax.annotation
. 전자는 JEE와 함께 제공됩니다. 이것이 javax.annotation
JSE와 함께 제공되거나 전혀 제공되지 않는 것보다 낫다면 논쟁의 여지가 있습니다. javax.annotation
JEE 의존성이 마음에 들지 않기 때문에 개인적으로 선호합니다 .
이것은 우리를 떠나
javax.annotation
또한 가장 짧은 것입니다.
더 좋은 구문은 하나뿐입니다 java.annotation.Nullable
. 다른 패키지를 졸업대로 javax
에 java
과거의 javax.annotation의 오른쪽 방향으로 단계가 될 것입니다.
이행
나는 그들이 기본적으로 모두 동일한 사소한 구현을 가지기를 바랐지만 자세한 분석은 이것이 사실이 아니라는 것을 보여주었습니다.
유사점 우선 :
@NonNull
주석 모든 라인을 가지고
public @interface NonNull {}
제외하고
org.jetbrains.annotations
그것을 호출@NotNull
하고 사소한 구현이 있습니다.javax.annotation
더 긴 구현이 있습니다javax.validation.constraints
또한 그것을 호출@NotNull
하고 구현이 있습니다.
@Nullable
주석 모든 라인을 가지고
public @interface Nullable {}
org.jetbrains.annotations
사소한 구현으로 (다시)를 제외하고 .
차이점을 위해 :
눈에 띄는 것은
javax.annotation
javax.validation.constraints
org.checkerframework.checker.nullness.qual
모두 런타임 주석 ( @Retention(RUNTIME)
)이 있지만
android.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
컴파일 시간 ( @Retention(CLASS)
)입니다.
이 SO 답변에 설명 된 것처럼 런타임 주석의 영향은 생각보다 작지만 컴파일 시간 외에도 도구를 사용하여 런타임 검사를 수행 할 수 있다는 이점이 있습니다.
또 다른 중요한 차이점은 어디에 코드에서 주석을 사용할 수 있습니다. 두 가지 접근 방식이 있습니다. 일부 패키지는 JLS 9.6.4.1 스타일 컨텍스트를 사용합니다. 다음 표는 개요를 제공합니다.
필드 방법 매개 변수 LOCAL_VARIABLE android.support.annotation XXX edu.umd.cs.findbugs.annotations XXXX org.jetbrains.annotation XXXX 롬복 XXXX javax.validation.constraints XXX
org.eclipse.jdt.annotation
, javax.annotation
그리고 org.checkerframework.checker.nullness.qual
그것을 할 올바른 방법은 내 의견에 JLS 4.11에 정의 된 컨텍스트를 사용합니다.
이것은 우리를 떠나
javax.annotation
org.checkerframework.checker.nullness.qual
이 라운드에서.
암호
자세한 내용을 직접 비교할 수 있도록 아래에 모든 주석의 코드를 나열합니다. 비교를 쉽게하기 위해 주석, 가져 오기 및 @Documented
주석을 제거했습니다 . (모두 @Documented
Android 패키지의 클래스를 제외하고) 나는 라인과 @Target
필드를 재정렬하고 자격을 정규화했습니다.
package android.support.annotation;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER})
public @interface NonNull {}
package edu.umd.cs.findbugs.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}
package org.eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface NonNull {}
package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NotNull {String value() default "";}
package javax.annotation;
@TypeQualifier
@Retention(RUNTIME)
public @interface Nonnull {
When when() default When.ALWAYS;
static class Checker implements TypeQualifierValidator<Nonnull> {
public When forConstantValue(Nonnull qualifierqualifierArgument,
Object value) {
if (value == null)
return When.NEVER;
return When.ALWAYS;
}
}
}
package org.checkerframework.checker.nullness.qual;
@Retention(RUNTIME)
@Target({TYPE_USE, TYPE_PARAMETER})
@SubtypeOf(MonotonicNonNull.class)
@ImplicitFor(
types = {
TypeKind.PACKAGE,
TypeKind.INT,
TypeKind.BOOLEAN,
TypeKind.CHAR,
TypeKind.DOUBLE,
TypeKind.FLOAT,
TypeKind.LONG,
TypeKind.SHORT,
TypeKind.BYTE
},
literals = {LiteralKind.STRING}
)
@DefaultQualifierInHierarchy
@DefaultFor({TypeUseLocation.EXCEPTION_PARAMETER})
@DefaultInUncheckedCodeFor({TypeUseLocation.PARAMETER, TypeUseLocation.LOWER_BOUND})
public @interface NonNull {}
완성을 위해 @Nullable
구현은 다음과 같습니다.
package android.support.annotation;
@Retention(CLASS)
@Target({METHOD, PARAMETER, FIELD})
public @interface Nullable {}
package edu.umd.cs.findbugs.annotations;
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
@Retention(CLASS)
public @interface Nullable {}
package org.eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface Nullable {}
package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface Nullable {String value() default "";}
package javax.annotation;
@TypeQualifierNickname
@Nonnull(when = When.UNKNOWN)
@Retention(RUNTIME)
public @interface Nullable {}
package org.checkerframework.checker.nullness.qual;
@Retention(RUNTIME)
@Target({TYPE_USE, TYPE_PARAMETER})
@SubtypeOf({})
@ImplicitFor(
literals = {LiteralKind.NULL},
typeNames = {java.lang.Void.class}
)
@DefaultInUncheckedCodeFor({TypeUseLocation.RETURN, TypeUseLocation.UPPER_BOUND})
public @interface Nullable {}
다음 두 패키지에는가 없으므로 @Nullable
별도로 나열합니다. 롬복은 꽤 지루 @NonNull
합니다. 에서 javax.validation.constraints
(가) @NonNull
실제로이며 @NotNull
그것은 기름 한 구현이있다.
package lombok;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}
package javax.validation.constraints;
@Retention(RUNTIME)
@Target({ FIELD, METHOD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Constraint(validatedBy = {})
public @interface NotNull {
String message() default "{javax.validation.constraints.NotNull.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default {};
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@interface List {
NotNull[] value();
}
}
지원하다
내 경험상, javax.annotation
적어도 Eclipse와 Checker Framework는 기본적으로 지원됩니다.
요약
이상적인 주석은 java.annotation
Checker Framework 구현 의 구문입니다.
Checker Framework를 사용하지 않으 려면 당분간 javax.annotation
( JSR-305 )이 가장 좋습니다.
Checker Framework에 기꺼이 구매하려는 경우을 사용하십시오 org.checkerframework.checker.nullness.qual
.
출처
android.support.annotation
…에서android-5.1.1_r1.jar
edu.umd.cs.findbugs.annotations
…에서findbugs-annotations-1.0.0.jar
org.eclipse.jdt.annotation
…에서org.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
org.jetbrains.annotations
…에서jetbrains-annotations-13.0.jar
javax.annotation
…에서gwt-dev-2.5.1-sources.jar
org.checkerframework.checker.nullness.qual
…에서checker-framework-2.1.9.zip
lombok
에서lombok
커밋f6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
javax.validation.constraints
…에서validation-api-1.0.0.GA-sources.jar
답변
필자 는 nullness checker와 같은 결함 검사기를 구현하는 데 사용되는 형식 주석 ( JSR-308 ) 의 구현 인 Checker Framework를 매우 좋아합니다 . 나는 비교를 제공하기 위해 다른 것을 시도하지는 않았지만이 구현에 만족했습니다.
저는 소프트웨어를 제공하는 그룹과 제휴하지는 않지만 팬입니다.
이 시스템에 대해 내가 좋아하는 네 가지 :
-
Null에 대한 결함 검사기 (@Nullable)가 있지만 불변성 및 인턴 (및 기타)에 대한 결함 검사기 도 있습니다 . 나는 첫 번째 (nullness)를 사용하고 두 번째 것을 사용하려고합니다 (불변성 / IGJ). 세 번째 방법을 시도하고 있지만 아직 장기적으로 사용하고 있는지 확실하지 않습니다. 나는 다른 체커의 일반적인 유용성을 아직 확신하지 못하지만 프레임 워크 자체가 다양한 추가 주석 및 체커를 구현하기위한 시스템이라는 것을 알고 있습니다.
-
그만큼 널 (Null) 검사 기본 설정은 다음과 같이 작동합니다. NEL (Null을 제외한 널 없음). 기본적으로 이는 체커가 기본적으로 @NonNull 유형을 갖는 것처럼 로컬 변수를 제외한 모든 변수 (인스턴스 변수, 메소드 매개 변수, 일반 유형 등)를 처리한다는 것을 의미합니다. 설명서에 따라 :
NNEL 기본값은 코드에서 가장 적은 수의 명시 적 주석으로 이어집니다.
NNEL이 작동하지 않으면 클래스 또는 메소드에 대해 다른 기본값을 설정할 수 있습니다.
-
이 프레임 워크를 사용하면 주석에 주석을 묶어 프레임 워크 에 대한 종속성을 만들지 않고 함께 사용할 수 있습니다 .
/*@Nullable*/
. 라이브러리 또는 공유 코드에 주석을 달고 확인할 수는 있지만 프레임 워크를 사용하지 않는 다른 프로젝트에서 해당 라이브러리 / 공유 코드를 계속 사용할 수 있기 때문에 좋습니다. 이것은 좋은 기능입니다. 현재 모든 프로젝트에서 Checker Framework를 사용하는 경향이 있지만 사용에 익숙해졌습니다. -
프레임 워크에는 스텁 파일을 사용하여 널 (null)에 대해 아직 주석을 달지 않은 사용하는 API 에 주석 을 달 수 있는 방법이 있습니다.
답변
나는 IntelliJ를 사용하는데, 이는 NPE를 생성 할 수있는 것들을 표시하는 IntelliJ에 주로 관심이 있기 때문입니다. JDK에 표준 주석이없는 것이 실망 스럽습니다. 그것을 추가하는 것에 대한 이야기가 있는데, 그것은 Java 7로 만들 수 있습니다.이 경우 선택할 수있는 것이 하나 더 있습니다!
답변
Java 7 기능 목록 에 따르면 JSR-308 유형 주석은 Java 8로 연기됩니다. JSR-305 주석은 언급되지 않았습니다.
최신 JSR-308 초안 의 부록 에 JSR-305 상태에 대한 약간의 정보가 있습니다. 여기에는 JSR-305 주석이 폐기 된 것으로 보입니다. JSR-305 페이지에도 “비활성”으로 표시됩니다.
그 동안 실용적인 답변은 가장 널리 사용되는 도구가 지원하는 주석 유형을 사용하고 상황이 바뀌면 변경할 수 있도록 준비하는 것입니다.
실제로 JSR-308은 주석 유형 / 클래스를 정의하지 않으며 범위를 벗어난 것으로 생각됩니다. (그리고 JSR-305의 존재를 감안할 때 그들은 옳습니다).
그러나 JSR-308이 실제로 Java 8로 만들어지는 것처럼 보이면 JSR-305에 대한 관심이 다시 살아나더라도 놀라지 않을 것입니다. JSR-305 팀인 AFAIK는 공식적으로 업무를 포기하지 않았습니다. 그들은 2 년 이상 조용했습니다.
Bill Pugh (JSR-305의 기술 책임자)가 FindBugs의이면에 있다는 것은 흥미 롭습니다.
답변
Android 프로젝트의 경우 android.support.annotation.NonNull
및 을 사용해야합니다 android.support.annotation.Nullable
. 이러한 유용한 기타 Android 관련 주석은 지원 라이브러리 에서 사용할 수 있습니다 .
에서 http://tools.android.com/tech-docs/support-annotations :
지원 라이브러리 자체에도 이러한 주석으로 주석이 달렸으므로 지원 라이브러리의 사용자로서 Android Studio는 이미 주석을 기반으로 코드를 확인하고 잠재적 인 문제를 표시합니다.
답변
누구나 IntelliJ 클래스를 찾고 있다면 다음을 사용하여 maven 저장소에서 가져올 수 있습니다
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>15.0</version>
</dependency>
답변
JSR305와 FindBugs는 같은 사람이 작성합니다. 둘 다 잘 관리되지 않았지만 모든 주요 IDE에서 지원하고 지원하는 표준입니다. 좋은 소식은 그대로 작동한다는 것입니다.
기본적으로 @Nonnull을 모든 클래스, 메서드 및 필드에 적용하는 방법은 다음과 같습니다. 참조 https://stackoverflow.com/a/13319541/14731 및 https://stackoverflow.com/a/9256595/14731
- 밝히다
@NotNullByDefault
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;
/**
* This annotation can be applied to a package, class or method to indicate that the class fields,
* method return types and parameters in that element are not null by default unless there is: <ul>
* <li>An explicit nullness annotation <li>The method overrides a method in a superclass (in which
* case the annotation of the corresponding parameter in the superclass applies) <li> there is a
* default parameter annotation applied to a more tightly nested element. </ul>
* <p/>
* @see https://stackoverflow.com/a/9256595/14731
*/
@Documented
@Nonnull
@TypeQualifierDefault(
{
ElementType.ANNOTATION_TYPE,
ElementType.CONSTRUCTOR,
ElementType.FIELD,
ElementType.LOCAL_VARIABLE,
ElementType.METHOD,
ElementType.PACKAGE,
ElementType.PARAMETER,
ElementType.TYPE
})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotNullByDefault
{
}
2. 각 패키지에 주석을 추가하십시오. package-info.java
@NotNullByDefault
package com.example.foo;
업데이트 : 2012 년 12 월 12 일 현재 JSR 305 는 “Dormant”로 표시됩니다. 설명서에 따르면 :
집행위원회에 의해 “휴면”으로 선정 된 JSR 또는 자연 수명이 다한 JSR.
JSR 308 이 JDK 8로 만드는 것처럼 보이고 JSR이 @NotNull을 정의하지는 않지만 첨부 된 것 Checkers Framework
입니다. 이 글을 쓰는 시점 에서이 버그로 인해 Maven 플러그인을 사용할 수 없습니다 : https://github.com/typetools/checker-framework/issues/183