@Nullable ve @Nonnull ek açıklamalarını nasıl daha etkin kullanabilirim?


140

Bunu görebiliyorum @Nullableve @Nonnullek açıklamalar s'yi önlemede yardımcı olabilirNullPointerException ama çok ilerlemiyorlar.

  • Bu ek açıklamaların etkinliği bir dolaylı aktarım düzeyinden sonra tamamen düşer, bu nedenle yalnızca birkaçını eklerseniz çok fazla yayılmazlar.
  • Bu ek açıklamalar iyi uygulanmadığından, işaretli bir değerin @Nonnullnull olmadığını ve sonuç olarak null kontrol gerçekleştirmediğini varsayma tehlikesi vardır .

Aşağıdaki kod ile işaretlenmiş bir parametre neden @Nonnullolmak nullherhangi bir şikayet yükseltmeden. NullPointerExceptionÇalıştırıldığında bir atar .

public class Clazz {
    public static void main(String[] args){
        Clazz clazz = new Clazz();

        // this line raises a complaint with the IDE (IntelliJ 11)
        clazz.directPathToA(null);

        // this line does not
        clazz.indirectPathToA(null); 
    }

    public void indirectPathToA(Integer y){
        directPathToA(y);
    }

    public void directPathToA(@Nonnull Integer x){
        x.toString(); // do stuff to x        
    }
}

Bu ek açıklamaları daha katı hale getirmenin ve / veya daha fazla yaymanın bir yolu var mı?


1
Ben fikir gibi @Nullableya @Nonnullda değer ise, ancak "solicit tartışma muhtemeldir" çok olduğunu
Maarten Bodewes

Bu bir derleyici hata veya uyarı neden olduğu bir dünyaya taşımak için bir yol nullable değişken ile bir yöntem @Nonnullçağrıldığında bir döküm gerektiren olduğunu düşünüyorum @Nonnull. Tabii ki, Java 7'de bir açıklama ile yayın yapmak mümkün değildir, ancak Java 8, dökümler dahil olmak üzere bir değişkenin kullanımına ek açıklama uygulama yeteneği ekleyecektir. Böylece bu Java 8'de uygulamak mümkün olabilir.
Theodore Murdock

1
@TheodoreMurdock, evet, Java 8'de bir döküm (@NonNull Integer) ysözdizimsel olarak mümkündür, ancak bir derleyicinin ek açıklamaya dayalı olarak belirli bir bayt kodu yayınlamasına izin verilmez. Çalışma zamanı iddiaları için küçük yardımcı yöntemler bugs.eclipse.org/442103 (örn. directPathToA(assertNonNull(y))) ' De tartışıldığı gibi yeterlidir - ancak unutmayın, bu sadece hızlı başarısızlığa yardımcı olur. Tek güvenli yol, gerçek bir null denetim (artı umarım diğer dalda alternatif bir uygulama) gerçekleştirmektir.
Stephan Herrmann

1
Bu hangi söylemek bu soruya yararlı olacağını @Nonnullve @Nullablebirden çok benzer annoations olduğu gibi (Bkz bahsediyorsun bu soruyu ). Paketteki ek açıklamalardan mı bahsediyorsunuz javax.annotation?
James Dunn

1
@TJamesBoone Bu sorunun bağlamı için önemli değil, bu onların nasıl etkili bir şekilde kullanılacağı ile ilgiliydi.
Mike Rylander

Yanıtlar:


66

Kısa cevap: Bu ek açıklamaların yalnızca IDE'nizin sizi potansiyel olarak boş işaretçi hataları konusunda uyarması için yararlı olduğunu düşünüyorum.

"Kodu Temizle" kitabında belirtildiği gibi, genel yönteminizin parametrelerini kontrol etmeli ve değişmezleri kontrol etmekten kaçınmalısınız.

Başka bir iyi ipucu asla null değerler döndürmektir, bunun yerine Null Nesne Deseni kullanmaktır.


10
Muhtemelen boş olan dönüş değerleri için Optional, düz yerine türü kullanmanızı şiddetle tavsiye ederimnull
Patrick

7
İsteğe bağlı "null" değerinden daha iyi değil. Null kullanımı NullPointerException öğesini kullanırken, isteğe bağlı # get () öğesi NoSuchElementException öğesini atar. Her ikisi de anlamlı bir açıklama olmadan RuntimeException'dır. Sıfırlanabilir değişkenleri tercih ederim.
30

4
@ 30thhiç önce neden Optional.get () kullanıyorsunuz ve ilk olarak Optional.isPresent () veya Optional.map kullanmıyorsunuz?
GauravJ

7
@GauravJ Neden boş değer içeren bir değişkeni doğrudan kullanıyorsunuz ve ilk önce boşsa kontrol etmiyorsunuz? ;-)
30thh

5
Arasındaki fark OptionalBu durumda ve geçersiz olanOptional , bu değerin kasıtlı olarak boş olabileceğini daha iyi bildirir. Elbette, bu sihirli bir değnek değildir ve çalışma zamanında nullable değişkeniyle aynı şekilde başarısız olabilir. Ancak, programcı tarafından API alımı Optionalbence daha iyidir .
user1053510

31

nullArgümanın boş olmamasını bekleyen yöntemlere geçtiğinizde size IDE veren ipuçları dışında başka avantajlar da vardır:

  • Statik kod analiz araçları IDE'nizle aynı testi yapabilir (örn. FindBugs)
  • Bu iddiaları kontrol etmek için AOP'yi kullanabilirsiniz

Bu, kodunuzun daha sürdürülebilir ( nullkontrollere ihtiyacınız olmadığından) ve daha az hataya açık olmasına yardımcı olabilir .


9
Burada OP'ye sempati duyuyorum, çünkü bu iki avantajı belirtmenize rağmen, her iki durumda da "can" kelimesini kullandınız. Bu, bu kontrollerin gerçekten gerçekleşeceğinin garantisi olmadığı anlamına gelir. Şimdi, bu davranışsal fark, sahip olduğumuz üretim modunda çalışmaktan kaçınmak istediğiniz performansa duyarlı testler için yararlı olabilir assert. Ben bulmak @Nullableve @Nonnullyararlı fikirler olması, ama bize bir şey hakkında hipotez ziyade, arkalarında daha fazla güç istiyorum olabilir hala yaprakları onlarla hiçbir şey yapmama olasılığını açık olan onlarla ne.
seh

2
Soru, nereden başlayacağınızdır. Şu anda seçimleri isteğe bağlıdır. Bazı durumlarda olmasaydı bunu isterdim çünkü bazı durumlarda onları zorlamak yardımcı olacaktır ...
Uwe Plonus

Burada bahsettiğiniz AOP'yi sorabilir miyim?
Chris.Zou

@ Chris.Zou AOP en boy yönelimli programlama anlamına gelir, örneğin AspectJ
Uwe Plonus

13

Bu orijinal sorunun dolaylı olarak @NonNull kullanılmasına rağmen, çalışma zamanı null-pointer kontrolünün hala gerekli olduğuna dair genel bir tavsiyeye işaret ettiğini düşünüyorum. Aşağıdaki bağlantıya bakın:

Java 8'in yeni Tip Ek Açıklamaları

Yukarıdaki blogda şunlar önerilir:

İsteğe Bağlı Tür Ek Açıklamaları, çalışma zamanı doğrulamasının yerini almaz Tür Ek Açıklamalarından önce, güvenlik açığı veya aralıklar gibi şeyleri açıklamanın birincil konumu javadoc'taydı. Tür ek açıklamaları ile bu iletişim, derleme zamanı doğrulaması için bayt koduna gelir. Kodunuz yine de çalışma zamanı doğrulaması yapmalıdır.


1
Anlaşıldı, ancak varsayılan tiftik denetimleri, çalışma zamanı null denetimlerinin gereksiz olduğu konusunda uyarıyor ve bu da ilk izlenimde bu öneriyi caydırıyor gibi görünüyor.
swooby

1
@swooby Kodumun doğru olduğundan emin olduğumda genellikle tüy bırakmayan uyarıları görmezden gelirim. Bu uyarılar hata değildir.
jonathanzh

12

Eclipse'deki orijinal örneği uyumluluk 1.8'de derleyerek ve ek açıklama tabanlı boş analiz etkinleştirildiğinde şu uyarıyı alırız:

    directPathToA(y);
                  ^
Null type safety (type annotations): The expression of type 'Integer' needs unchecked conversion to conform to '@NonNull Integer'

Bu uyarı, ham türleri ("denetlenmeyen dönüşüm") kullanarak oluşturulmuş kodu eski kodla karıştırırken aldığınız uyarılara benzer şekilde ifade edilir. Burada da tam olarak aynı durum var: yöntemindirectPathToA() herhangi bir boş sözleşme belirtmemesi nedeniyle "eski" imzası var. Araçlar bunu kolayca raporlayabilir, böylece boş ek açıklamaların yayılması gereken ancak henüz bulunmayan tüm sokaklarda sizi takip ederler.

Ve akıllıca kullanırken @NonNullByDefault bunu her seferinde söylemek zorunda bile değiliz.

Başka bir deyişle: "çok ileri yayılan" null ek açıklamaların kullanılıp kullanılmadığına ve aracın verdiği tüm uyarılara ne kadar titizlikle katıldığınıza bağlı olabilir. İle TYPE_USE boş ek açıklamalar nihayet aracı hakkında uyarmak izin seçeneğine sahip her nullness tipi sisteminin bir intrisic özelliği haline gelmiştir, çünkü programda olası NPE.


8

Ek açıklamaların "çok fazla yayılmadığını" kabul ediyorum. Ancak, programcı tarafında hatayı görüyorum.

NonnullEk açıklamayı dokümantasyon olarak anlıyorum . Aşağıdaki yöntem null olmayan bir bağımsız değişken gerektirdiğini (ön koşul olarak) ifade eder x.

    public void directPathToA(@Nonnull Integer x){
        x.toString(); // do stuff to x        
    }

Aşağıdaki kod snippet'i bir hata içeriyor. Yöntem null olmayan directPathToA()zorlama olmadan çağırır y(yani, çağrılan yöntemin önkoşulunu garanti etmez). Bir olasılık da bir ön Nonnullaçıklama eklemektir indirectPathToA()(ön koşulu yaymak). Olasılık iki geçersizliği için kontrol etmektir yiçinde indirectPathToA()ve çağrısını önlemek directPathToA()zaman yboş.

    public void indirectPathToA(Integer y){
        directPathToA(y);
    }

1
İlerleyen @Nonnull olması indirectPathToA(@Nonnull Integer y)imho kötü uygulama şudur: Tam çağrı yığını (bir eklerseniz böylece yayılmasını mainain gerekir nullcheck directPathToA(), değiştirmek gerekecektir @Nonnulltarafından @Nullabletam çağrı yığını içinde). Bu, büyük uygulamalar için büyük bir bakım çabası olacaktır.
Julien Kronegg

@Nonnull ek açıklaması, yalnızca argümanın null doğrulamasının yanınızda olduğunu vurgular (null olmayan değeri geçtiğinizden emin olmanız gerekir). Yöntemin sorumluluğu yoktur.
Alexander Drobyshevsky

@Null değeri bu yöntem için herhangi bir anlam ifade etmediğinde deNonnull mantıklı bir şeydir
Alexander Drobyshevsky

5

Projelerimde "Sabit koşullar ve istisnalar" kod denetiminde aşağıdaki seçeneği etkinleştirmektir:
@null değeri eklenebilir, null döndürülebilecek ve ek açıklama eklenmemiş parametrelere geçirilen boş değerleri bildirebilecek yöntemler için öner Denetimler

Etkinleştirildiğinde, tüm açıklamalı olmayan parametreler boş olarak değerlendirilir ve böylece dolaylı aramanızda da bir uyarı görürsünüz:

clazz.indirectPathToA(null); 

Daha güçlü kontroller için Checker Çerçevesi iyi bir seçim olabilir (bu güzel eğiticiye bakın .
Not : Henüz kullanmadım ve Jack derleyicisiyle ilgili sorunlar olabilir: bu hata raporuna bakın


4

Java'da Guava'nın İsteğe bağlı türünü kullanırdım . Gerçek bir tür olarak derleyici kullanımı hakkında garanti alırsınız. Bunu atlamak ve bir elde etmek kolaydır NullPointerException, ancak en azından yöntemin imzası, bir argüman olarak ne beklediğini veya ne döndürebileceğini açıkça bildirir.


16
Buna dikkat etmelisin. İsteğe bağlı yalnızca bir değerin gerçekten isteğe bağlı olduğu ve yokluğu daha fazla mantık için bir karar kapısı olarak kullanıldığı durumlarda kullanılmalıdır. Bunun Objelerin Opsiyonellerle battaniyeyle değiştirilmesi ve null kontrollerin, noktayı kaçıran varlık kontrolleri ile değiştirildiğini gördüm.
Christopher Perry

JDK 8 veya daha yenisini hedefliyorsanız java.util.Optional, Guava sınıfı yerine kullanmayı tercih edin . Farklarla ilgili ayrıntılar için Guava notlarına / karşılaştırmasına bakın.
AndrewF

1
Eğer ne anlamı üzerinde, o zaman, detaylandırabileceğiniz "boş çekler noktasını özlüyor varlığı için kontroller ile değiştirilir" olduğunu ? Bence Optionals'ın tek nedeni bu değil , ama kesinlikle en büyük ve en iyisi.
scubbo

4

Kotlin'i kullanırsanız, derleyicisindeki bu nullabilite ek açıklamalarını destekler ve null olmayan bir argüman gerektiren bir java yöntemine null değerini geçirmenizi önler. Bu soru başlangıçta Java'yı hedeflemiş olsa da, bu Kotlin özelliğinden özellikle bu Java ek açıklamasını hedef aldığından ve " Bu ek açıklamaları daha sıkı bir şekilde uygulamanın ve / veya daha fazla yaymanın bir yolu var mı ?" ve bu özellik bu ek açıklamaları daha sıkı bir şekilde uygular .

@NotNullEk açıklama kullanan Java sınıfı

public class MyJavaClazz {
    public void foo(@NotNull String myString) {
        // will result in an NPE if myString is null
        myString.hashCode();
    }
}

Java sınıfını çağıran ve @NotNull ile açıklanmış argüman için null ileten Kotlin sınıfı

class MyKotlinClazz {
    fun foo() {
        MyJavaClazz().foo(null)
    }
}  

@NotNullEk açıklamayı uygulayan Kotlin derleyici hatası .

Error:(5, 27) Kotlin: Null can not be a value of a non-null type String

bkz. http://kotlinlang.org/docs/reference/java-interop.html#nullability-annotations


3
Soru, Kotlin'e değil, ilk etiketine göre Java'yı ele alıyor.
seh

1
@seh bu cevabın neden bu soru ile alakalı olduğuna dair güncellemeye bakın.
Mike Rylander

2
Yeterince adil. Bu Kotlin'in güzel bir özelliği. Java hakkında bilgi edinmek için buraya gelenleri tatmin edeceğini sanmıyorum.
seh

ancak parametreye eklenmemiş myString.hashCode()olsa bile erişim hala NPE atar @NotNull. Ekleme konusunda daha spesifik olan nedir?
kAmol

@kAmol Buradaki fark, Kotlin'i kullanırken bir çalışma zamanı hatası yerine bir derleme zamanı hatası alacağınızdır . Ek açıklama, geliştiricinin bir null değerinin geçirilmediğinden emin olmanız gerektiğini bildirmektir. Bu, null değerinin çalışma zamanında geçirilmesini engellemez, ancak bu yöntemi null olarak çağıran kod yazmanızı önler (veya null döndürebilen bir işlevle).
Mike Rylander

-4

Java 8'in yeni özelliği İsteğe bağlı olduğundan, artık kendi kodunuzda @Nullable veya @Notnull kullanmamalısınız . Aşağıdaki örneği alın:

public void printValue(@Nullable myValue) {
    if (myValue != null) {
        System.out.print(myValue);
    } else {
        System.out.print("I dont have a value");
}

Şununla yeniden yazılabilir:

public void printValue(Optional<String> myValue) {
    if (myValue.ifPresent) {
        System.out.print(myValue.get());
    } else {
        System.out.print("I dont have a value");
}

İsteğe bağlı bir kullanım , null değeri kontrol etmeye zorlar . Yukarıdaki kodda, değere yalnızcaget yöntemi .

Diğer bir avantaj ise kodun daha okunabilir olmasıdır . Java 9 ifPresentOrElse eklenmesi ile işlev şu şekilde de yazılabilir:

public void printValue(Optional<String> myValue) {
    myValue.ifPresentOrElse(
        v -> System.out.print(v),
        () -> System.out.print("I dont have a value"),
    )
}

Bununla birlikte Optional, tüm bağımlılıklarınızı Optionals kullanmak için güncellenmiş sürümlerle güncellemek / değiştirmek mümkün olmayacak şekilde bu ek açıklamaları kullanan birçok kitaplık ve çerçeve vardır. Optionalancak kendi kodunuzda null kullandığınız durumlarda yardımcı olabilir.
Mike Rylander
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.