어떤 @NotNull Java 주석을 사용해야합니까?
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의 상태는 무엇입니까? ) 소스org.jetbrains.annotations.NotNull
정적 분석을 위해 IntelliJ IDEA IDE에서 사용됩니다.
선적 서류 비치lombok.NonNull
Project Lombok 에서 코드 생성을 제어하는 데 사용됩니다 .
표준이 없으므로 자리 표시 자 주석입니다.
소스 , 문서android.support.annotation.NonNull
Android에서 사용 가능한 마커 주석 (support-annotations 패키지
문서에서 제공)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 스타일 컨텍스트를 사용합니다. 다음 표는 개요를 제공합니다.
FIELD METHOD PARAMETER 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를 매우 좋아합니다 . 나는 비교를 제공하기 위해 다른 사람을 실제로 시도하지 않았지만이 구현에 만족합니다.
저는 소프트웨어를 제공하는 그룹에 소속되어 있지 않지만 팬입니다.
이 시스템에 대해 내가 좋아하는 네 가지 :
nullness (@Nullable)에 대한 결함 검사기가 있지만 불변성 및 인턴 (및 기타)에 대한 검사기 도 있습니다 . 나는 첫 번째 (nullness)를 사용하고 두 번째 (불변성 / IGJ)를 사용하려고합니다. 세 번째를 시도하고 있지만 아직 장기간 사용하는 것이 확실하지 않습니다. 아직 다른 검사기의 일반적인 유용성은 확신하지 못하지만 프레임 워크 자체가 다양한 추가 주석 및 검사기를 구현하는 시스템이라는 사실을 알게되어 기쁩니다.
nullness 검사 의 기본 설정 은 잘 작동합니다. 로컬을 제외하고 null이 아닙니다 (NNEL). 기본적으로 이것은 기본적으로 검사기가 로컬 변수를 제외한 모든 항목 (인스턴스 변수, 메서드 매개 변수, 제네릭 유형 등)을 기본적으로 @NonNull 유형을 갖는 것처럼 처리한다는 것을 의미합니다. 문서에 따라 :
NNEL 기본값은 코드에서 가장 적은 수의 명시 적 주석으로 이어집니다.
NNEL이 작동하지 않는 경우 클래스 또는 메서드에 대해 다른 기본값을 설정할 수 있습니다.
이 프레임 워크를 사용하면 주석에 주석 을 포함하여 프레임 워크 에 대한 종속성을 만들지 않고도 with를 사용할 수 있습니다 . 예 :
/*@Nullable*/
. 라이브러리 또는 공유 코드에 주석을 달고 확인할 수 있지만 프레임 워크를 사용하지 않는 다른 프로젝트에서 해당 라이브러리 / 공유 코딩을 계속 사용할 수 있기 때문에 좋습니다. 이것은 좋은 기능입니다. 지금은 모든 프로젝트에서 Checker Framework를 활성화하는 경향이 있지만 사용하는 데 익숙해졌습니다.프레임 워크에는 스텁 파일을 사용하여 아직 nullness 주석이 추가되지 않은 API 에 주석 을 추가 하는 방법이 있습니다.
IntelliJ를 사용합니다. 주로 IntelliJ가 NPE를 생성 할 수있는 항목을 표시하는 데 관심이 있기 때문입니다. 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에 대한 관심이 다시 살아나더라도 놀라지 않을 것입니다. AFAIK, JSR-305 팀은 공식적으로 작업을 포기하지 않았습니다. 그들은 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 는 "휴면"으로 표시됩니다. 문서에 따르면 :
집행위원회에서 "휴면"으로 투표 한 JSR 또는 자연 수명이 다한 JSR입니다.
JSR 308 이 JDK 8로 만드는 것처럼 보이며 JSR은 @NotNull을 정의하지 않지만 동반하는 Checkers Framework
것은 있습니다. 이 글을 쓰는 시점에서이 버그로 인해 Maven 플러그인을 사용할 수 없습니다 : https://github.com/typetools/checker-framework/issues/183
Eclipse에는 자체 주석도 있습니다.
org.eclipse.jdt.annotation.NonNull
자세한 내용은 http://wiki.eclipse.org/JDT_Core/Null_Analysis 를 참조하십시오.
Java Validation API ( javax.validation.constraints.*
)에는 @Nullable
주석 이 포함되어 있지 않으므로 정적 분석 컨텍스트에서 매우 유용합니다. 이것은 Java의 기본이 아닌 필드에 대한 기본값이므로 런타임 빈 유효성 검사에 적합합니다 (즉, 유효성 검사 / 시행 할 항목 없음). 목적을 위해 대안에 무게를 두어야합니다.
정적 분석과 런타임 분석을 구분합니다. 내부 항목에는 정적 분석을 사용하고 코드의 공개 경계에는 런타임 분석을 사용하십시오.
null이 아니어야하는 항목의 경우 :
런타임 검사 : "if (x == null) ..."(종속성 없음) 또는 @ javax.validation.NotNull (빈 유효성 검사 포함) 또는 @ lombok.NonNull (일반 및 단순) 또는 guavas Preconditions.checkNotNull (.. .)
- 메서드 반환 유형에 대해 Optional을 사용합니다 (전용). Java8 또는 Guava 중 하나입니다.
정적 검사 : @NonNull 주석 사용
- 적합한 경우 클래스 또는 패키지 수준에서 @ ... NonnullByDefault 주석을 사용하십시오. 이러한 주석을 직접 만듭니다 (예는 찾기 쉽습니다).
- 그렇지 않으면 NPE를 피하기 위해 메서드 반환에 @ ... CheckForNull을 사용합니다.
이것은 최상의 결과를 제공해야합니다 : IDE의 경고, Findbugs 및 checkerframework의 오류, 의미있는 런타임 예외.
정적 검사가 성숙 될 것이라고 기대하지 마십시오. 이름이 표준화되지 않았으며 다른 라이브러리와 IDE가 다르게 처리하고 무시합니다. JSR305 javax.annotations. * 클래스는 표준처럼 보이지만 그렇지 않으며 Java9 +로 분할 패키지를 발생시킵니다.
일부 메모 설명 :
- javax.validation. * 패키지가있는 Findbugs / spotbugs / jsr305 주석이 Java9 +의 다른 모듈과 충돌하며 Oracle 라이센스를 위반할 수도 있습니다.
- Spotbugs 주석은 여전히 컴파일 타임에 jsr305 / findbugs 주석에 의존합니다 ( https://github.com/spotbugs/spotbugs/issues/421 작성 당시 )
- jetbrains @NotNull 이름이 @ javax.validation.NotNull과 충돌합니다.
- 정적 검사를위한 jetbrains, eclipse 또는 checkersframework 주석은 Java9 이상에서 다른 모듈과 충돌하지 않는다는 점에서 javax.annotations에 비해 이점이 있습니다.
- @ javax.annotations.Nullable은 Findbugs / Spotbugs 사용자 (또는 IDE)가 의미하는 바를 의미하지 않습니다. Findbugs는이를 무시합니다 (멤버의 경우). 슬프지만 사실입니다 ( https://sourceforge.net/p/findbugs/bugs/1181 )
- IDE 외부의 정적 검사를 위해 Spotbugs (이전 Findbugs) 및 checkersframework의 두 가지 무료 도구가 있습니다.
- Eclipse 라이브러리에는 @NonNullByDefault가 있고 jsr305에는 @ParametersAreNonnullByDefault 만 있습니다. 그것들은 패키지 (또는 클래스)의 모든 것에 기본 주석을 적용하는 단순한 편의 래퍼이며, 쉽게 직접 만들 수 있습니다. 패키지에 사용할 수 있습니다. 생성 된 코드 (예 : lombok)와 충돌 할 수 있습니다.
- Eclipse jdt 어노테이션은 정적 메소드 리턴 및 기타 일부 경우에 적용되지 않습니다.
- lombok을 내 보낸 종속성으로 사용하는 것은 다른 사람들과 공유하는 라이브러리에 대해 피해야합니다. 전 이적 종속성이 적을수록 좋습니다.
- Bean 유효성 검사 프레임 워크를 사용하는 것은 강력하지만 높은 오버 헤드가 필요하므로 수동 null 검사를 피하기 위해 과잉입니다.
- 필드 및 메소드 매개 변수에 선택 사항을 사용하는 것은 논란의 여지가 있습니다 (이에 대한 기사를 쉽게 찾을 수 있음).
- Android null 주석은 Android 지원 라이브러리의 일부이며 다른 많은 클래스와 함께 제공되며 다른 주석 / 도구와 잘 작동하지 않습니다.
Java9 이전에는 이것이 내 권장 사항입니다.
// file: package-info.java
@javax.annotation.ParametersAreNonnullByDefault
package example;
// file: PublicApi
package example;
public interface PublicApi {
Person createPerson(
// NonNull by default due to package-info.java above
String firstname,
String lastname);
}
// file: PublicApiImpl
public class PublicApiImpl implements PublicApi {
public Person createPerson(
// In Impl, handle cases where library users still pass null
@Nullable String firstname, // Users might send null
@Nullable String lastname // Users might send null
) {
if (firstname == null) throw new IllagalArgumentException(...);
if (lastname == null) throw new IllagalArgumentException(...);
return doCreatePerson(fistname, lastname, nickname);
}
@NonNull // Spotbugs checks that method cannot return null
private Person doCreatePerson(
String firstname, // Spotbugs checks null cannot be passed, because package has ParametersAreNonnullByDefault
String lastname,
@Nullable String nickname // tell Spotbugs null is ok
) {
return new Person(firstname, lastname, nickname);
}
@CheckForNull // Do not use @Nullable here, Spotbugs will ignore it, though IDEs respect it
private Person getNickname(
String firstname,
String lastname) {
return NICKNAMES.get(firstname + ':' + lastname);
}
}
nullable 메서드 매개 변수가 역 참조 될 때 Spotbugs가 경고를 발생 시키도록 할 수있는 방법이 없습니다 (작성 당시 Spotbugs 버전 3.1). 아마도 checkerframework가 그렇게 할 수 있습니다.
슬프게도 이러한 주석은 임의의 호출 사이트가있는 라이브러리의 공용 메서드와 각 호출 사이트를 알 수있는 비공개 메서드의 경우를 구분하지 않습니다. 따라서 "null이 원치 않는다는 것을 나타내지 만 그럼에도 불구하고 null이 전달 될 준비를한다"라는 이중 의미는 단일 선언에서 불가능합니다. 따라서 위의 예제는 인터페이스와 구현에 대해 다른 주석을 가지고 있습니다.
분할 인터페이스 접근 방식이 실용적이지 않은 경우 다음 접근 방식이 절충안입니다.
public Person createPerson(
@NonNull String firstname,
@NonNull String lastname
) {
// even though parameters annotated as NonNull, library clients might call with null.
if (firstname == null) throw new IllagalArgumentException(...);
if (lastname == null) throw new IllagalArgumentException(...);
return doCreatePerson(fistname, lastname, nickname);
}
이를 통해 클라이언트는 null (올바른 코드 작성)을 전달하지 않고 유용한 오류를 반환 할 수 있습니다.
안타깝게도이 JSR 308
프로젝트 로컬 Not Null 제안보다 더 많은 값을 추가하지 않습니다.
Java 8
단일 기본 주석 또는 자체 Checker
프레임 워크 가 제공되지 않습니다 . Find-bugs 또는와 유사하게 JSR 305
,이 JSR은 대부분의 학업 팀에 의해 제대로 관리되지 않습니다.
그 배후에 상업적 전력이 없기 때문에 지금 (Early Draft Review at ) 을 JSR 308
시작 하지만 6 개월 이내에 배송 될 예정입니다 .-O btw 와 유사합니다 . 하지만 지금은 자바 플랫폼에 미칠 피해를 최소화하기 위해 창립자로부터 책임을 맡았습니다.EDR 3
JCP
Java 8
310
308 Oracle
뒤에서 것과 같은 모든 프로젝트, 공급 업체 및 학술 클래스 Checker Framework
와는 JSR 308
독자적인 검사 주석을 생성합니다.
몇 가지 인기있는 타협이 발견되고 Java 9
또는에 추가 될 수있을 때까지 또는 또는 ;-) 10
와 같은 프레임 워크를 통해 소스 코드를 향후 몇 년 동안 호환되지 않게 만들기Apache Commons
Google Guava
기계적 인조 인간
이 답변은 Android 전용입니다. Android에는 support-annotations
. 이 제공하는 수십 가지 의 안드로이드 특정의 주석을 또한 제공합니다 일반적인 사람 처럼 NonNull
, Nullable
등
추가 지원 - 주석 패키지를, 당신의 build.gradle에 다음 종속성을 추가 :
compile 'com.android.support:support-annotations:23.1.1'
다음을 사용하십시오.
import android.support.annotation.NonNull;
void foobar(@NonNull Foo bar) {}
이것이 업스트림에서 정렬되기를 기다리는 동안 (Java 8?) 자신 만의 프로젝트 로컬 @NotNull
및 @Nullable
주석을 정의 할 수도 있습니다 . 이 기능은 기본적으로 javax.validation.constraints
사용할 수없는 Java SE로 작업하는 경우에도 유용 할 수 있습니다 .
import java.lang.annotation.*;
/**
* Designates that a field, return value, argument, or variable is
* guaranteed to be non-null.
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Documented
@Retention(RetentionPolicy.CLASS)
public @interface NotNull {}
/**
* Designates that a field, return value, argument, or variable may be null.
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Documented
@Retention(RetentionPolicy.CLASS)
public @interface Nullable {}
위의 내용 자체가 이러한 주석의 정적 분석에 대한 지원을 추가하지 않기 때문에 이는 대부분 장식 또는 미래 보장 목적을위한 것입니다.
Android 용으로 개발하는 경우 자체 주석이있는 Eclipse (편집 : 더 이상 작성하지 않음)에 다소 묶여 있습니다. Eclipse 3.8+ (Juno)에 포함되어 있지만 기본적으로 비활성화되어 있습니다.
Preferences> Java> Compiler> Errors / Warnings> Null analysis (하단의 축소 가능한 섹션)에서 활성화 할 수 있습니다.
"주석 기반 널 분석 사용"을 선택하십시오.
http://wiki.eclipse.org/JDT_Core/Null_Analysis#Usage 에는 설정에 대한 권장 사항이 있습니다. 그러나 작업 영역에 외부 프로젝트 (예 : facebook SDK)가있는 경우 이러한 권장 사항을 충족하지 못할 수 있으며 각 SDK 업데이트로 수정하고 싶지 않을 것입니다 ;-)
나는 사용한다:
- Null 포인터 액세스 : 오류
- 널 스펙 위반 : 오류 (점 # 1에 링크 됨)
- 잠재적 널 포인터 액세스 : 경고 (그렇지 않으면 facebook SDK에 경고가 있음)
- null 주석과 null 추론 간의 충돌 : 경고 (점 # 3에 연결됨)
큰 프로젝트에서 작업하는 경우 자체 @Nullable
및 / 또는 @NotNull
주석 을 만드는 것이 더 나을 수 있습니다 .
예를 들면 :
@java.lang.annotation.Documented
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS)
@java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD,
java.lang.annotation.ElementType.METHOD,
java.lang.annotation.ElementType.PARAMETER,
java.lang.annotation.ElementType.LOCAL_VARIABLE})
public @interface Nullable
{
}
올바른 보존 정책 을 사용하면 런타임에 주석 을 사용할 수 없습니다 . 그 관점에서 그것은 단지 내부적 인 것입니다.
이것은 엄격한 과학은 아니지만 내부 수업 을 사용하는 것이 가장 합리적이라고 생각 합니다.
- 내부적 인 것입니다. (기능적 또는 기술적 영향 없음)
- 많은 많은 용도로.
- IntelliJ와 같은 IDE는 사용자 정의
@Nullable
/@NotNull
주석을 지원 합니다. - 대부분의 프레임 워크는 자체 내부 버전도 선호합니다.
추가 질문 (댓글 참조) :
IntelliJ에서 이것을 구성하는 방법은 무엇입니까?
IntelliJ 상태 표시 줄의 오른쪽 하단에있는 "경찰관"을 클릭합니다. 그리고 팝업에서 "검사 구성"을 클릭합니다. 다음 ...
Java 8에서이 작업을 수행하는 또 다른 방법이 있습니다. 필요한 작업을 수행하기 위해 두 가지 작업을 수행하고 있습니다.
- nullable 필드를 다음으로 래핑하여 형식으로 nullable 필드를 명시 적으로 만들기
java.util.Optional
- nullable이 아닌 모든 필드가 생성시 null이 아닌지 확인합니다.
java.util.Objects.requireNonNull
예:
import static java.util.Objects.requireNonNull;
public class Role {
private final UUID guid;
private final String domain;
private final String name;
private final Optional<String> description;
public Role(UUID guid, String domain, String name, Optional<String> description) {
this.guid = requireNonNull(guid);
this.domain = requireNonNull(domain);
this.name = requireNonNull(name);
this.description = requireNonNull(description);
}
그래서 제 질문은 Java 8을 사용할 때 주석을 달아야합니까?
편집 : 나중에 일부 사람들이 Optional
인수 에 사용하는 나쁜 관행을 고려한다는 것을 알게되었으며 여기에 장단점에 대한 좋은 토론이 있습니다. 왜 Java 8의 옵션을 인수에 사용하지 않아야합니까?
여기에는 이미 너무 많은 답변이 있지만 (a) 2019 년이고 여전히 "표준"이 Nullable
없으며 (b) Kotlin을 참조하는 다른 답변이 없습니다.
Kotlin은 Java와 100 % 상호 운용 가능하고 핵심 Null Safety 기능이 있기 때문에 Kotlin에 대한 참조가 중요합니다. 자바 라이브러리를 호출 할 때 이러한 주석을 활용하여 Kotlin 도구에 자바 API가 null
.
내가 아는 Nullable
한 Kotlin org.jetbrains.annotations
과 호환되는 유일한 패키지는 및 android.support.annotation
(현재 androidx.annotation
)입니다. 후자는 Android 와만 호환되므로 Android 이외의 JVM / Java / Kotlin 프로젝트에서는 사용할 수 없습니다. 그러나 JetBrains 패키지는 모든 곳에서 작동합니다.
따라서 Android 및 Kotlin에서도 작동하고 Android Studio 및 IntelliJ에서 지원해야하는 Java 패키지를 개발하는 경우 가장 좋은 선택은 아마도 JetBrains 패키지 일 것입니다.
메이븐 :
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations-java5</artifactId>
<version>15.0</version>
</dependency>
Gradle :
implementation 'org.jetbrains:annotations-java5:15.0'
태양은 지금 자신의 것을 가지고 있지 않습니까? 내용 :
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm
이것은 지난 몇 년 동안 내가 사용한 모든 버전의 Java와 함께 패키지 된 것 같습니다.
편집 : 아래 주석에서 언급했듯이 아마도 이것을 사용하고 싶지 않을 것입니다. 이 경우 내 투표는 IntelliJ jetbrains 주석입니다!
당신은 스프링 프레임 워크 I을 사용하여 응용 프로그램을 구축하는 경우 사용하는 제안 javax.validation.constraints.NotNull
에서 오는 콩 검증 다음 의존성에 포장 :
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
이 어노테이션의 주요 장점은 Spring이로 어노테이션이있는 클래스 필드와 메소드 매개 변수를 모두 지원한다는 것입니다 javax.validation.constraints.NotNull
. 지원을 활성화하기 위해해야 할 일은 다음과 같습니다.
빈 유효성 검사를위한 api jar와 jsr-303 / jsr-349 주석의 유효성 검사기를 구현 한 jar를 제공합니다 (Hibernate Validator 5.x 종속성과 함께 제공됨).
<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.4.1.Final</version> </dependency>
Spring의 컨텍스트에 MethodValidationPostProcessor 제공
@Configuration @ValidationConfig public class ValidationConfig implements MyService { @Bean public MethodValidationPostProcessor providePostProcessor() { return new MethodValidationPostProcessor() } }
마지막으로 클래스에 Spring의 주석을 달고
org.springframework.validation.annotation.Validated
유효성 검사는 Spring에 의해 자동으로 처리됩니다.
예:
@Service
@Validated
public class MyServiceImpl implements MyService {
@Override
public Something doSomething(@NotNull String myParameter) {
// No need to do something like assert myParameter != null
}
}
doSomething 메서드를 호출하고 매개 변수 값으로 null을 전달하려고하면 (HibernateValidator를 통해) spring이 throw ConstraintViolationException
됩니다. 여기서는 수동 작업이 필요 없습니다.
반환 값의 유효성을 검사 할 수도 있습니다.
javax.validation.constraints.NotNull
Beans Validation Framework 의 또 다른 중요한 이점 은 현재 아직 개발 중이며 새 버전 2.0에 대한 새로운 기능이 계획되어 있다는 것입니다.
어때 @Nullable
? Beans Validation 1.1에는 이와 같은 것이 없습니다. 글쎄요, 당신이 사용하기로 결정했다면 @NotNull
주석 이 붙지 않은 모든 @NonNull
것이 사실상 "nullable"이기 때문에 @Nullable
주석은 쓸모가 없다고 주장 할 수 있습니다.
또 다른 옵션은 ANTLR 4와 함께 제공되는 주석입니다. Pull Request # 434 에 따라 @NotNull
및 @Nullable
주석을 포함하는 아티팩트 에는 이러한 속성 중 하나가 오용되는 경우 컴파일 시간 오류 및 / 또는 경고를 생성하는 주석 프로세서가 포함됩니다 (예 : 둘 다 동일한 항목에 @Nullable
적용 되거나 기본 유형이있는 항목에 적용되는 경우 ). 주석 프로세서는 소프트웨어 개발 프로세스 동안 메서드 상속의 경우를 포함하여 이러한 주석을 적용하여 전달되는 정보가 정확하다는 추가 보증을 제공합니다.
IntelliJ의 좋은 점 중 하나는 주석을 사용할 필요가 없다는 것입니다. 직접 작성하거나 원하는 다른 도구를 사용할 수 있습니다. 당신은 단일 유형에 국한되지 않습니다. 서로 다른 @NotNull 주석을 사용하는 두 개의 라이브러리를 사용하는 경우 IntelliJ에 둘 다 사용하도록 지시 할 수 있습니다. 이렇게하려면 "검사 구성"으로 이동하여 "상수 조건 및 예외"검사를 클릭 한 다음 "검사 구성"버튼을 누르십시오. 가능한 모든 곳에서 Nullness Checker를 사용하므로 해당 주석을 사용하도록 IntelliJ를 설정했지만 원하는 다른 도구와 함께 사용할 수 있습니다. (저는 IntelliJ의 검사를 수년 동안 사용해 왔기 때문에 다른 도구에 대한 의견이 없으며 좋아합니다.)
참고 URL : https://stackoverflow.com/questions/4963300/which-notnull-java-annotation-should-i-use
'programing' 카테고리의 다른 글
외부 JAR에서 "오류 1로 인해 Dalvik 형식으로 변환 실패" (0) | 2020.09.28 |
---|---|
JSON을 C # 동적 개체로 역 직렬화 하시겠습니까? (0) | 2020.09.28 |
MySQL 데이터베이스의 이름을 빠르게 바꾸려면 어떻게합니까 (스키마 이름 변경)? (0) | 2020.09.28 |
bash 스크립트에서 정규식을 어떻게 사용합니까? (0) | 2020.09.25 |
JavaScript 키 코드 란 무엇입니까? (0) | 2020.09.25 |