Üretim kodundaki assert beyanında boş kalmamalısınız? [kapalı]


32

Bu soruyu gördüm ancak assertanahtar kelimenin kullanımı hakkında birkaç sorum var . Kullanmayla ilgili diğer birkaç kodlayıcıyla tartışıyordum assert. Bu kullanım durumunda, belirli önkoşullar karşılandığında null değerini döndüren bir yöntem vardı. Yazdığım kod yöntemi çağırır, sonra null döndürmez ve döndürülen nesneyi kullanmaya devam ettiğini iddia eder.

Misal:

class CustomObject {
    private Object object;

    @Nullable
    public Object getObject() {
        return (object == null) ? generateObject() : object;
    }
}

Şimdi şöyle kullandığımı düşünün:

public void useObject(CustomObject customObject) {
    object = customObject.getObject();
    assert object != null;
    // Do stuff using object, which would throw a NPE if object is null.
}

Üretim kodunda asla kullanılmamaları assertgerektiğini , sadece testlerde kullanılmaları gerektiğini söyledim . Bu doğru mu?


19
Varsayılan olarak, iddialar devre dışıdır. Bunları çalışma zamanında -eaveya eşdeğeri aracılığıyla açıkça etkinleştirmeniz gerekir .
jarmod

Yazılım Mühendisliği ile ilgili soru: softwareengineering.stackexchange.com/q/137158/187318 (oldukça eski olmasına rağmen, buradaki kabul edilen cevap Objects.requireNonNull, Java 8'in girişinden bu yana artık gerekli olmayan bir harici kütüphane önermektedir ).
Hulk

Bu soru başlığı çok geniş, ancak vücutta belirtilen soru çok daha dardır ve cevaplar yardımcı fonksiyonlarla tamamen ele alınır.
smci

Açık olmak gerekirse, istemci kodunun nesneler üzerinde null olmayan kontroller / ekler uygulayıp uygulamadığını soruyorsunuz . (Bu, kütüphane kodunun kendisinin nesnelerin boş olup olmayacağını garanti edip etmeyeceğini sormaktan farklıdır ).
smci

Yanıtlar:


19

Bunun için kullanın Objects.requireNonNull(Object).

Belirtilen nesne başvurusunun boş olup olmadığını denetler. Bu yöntem öncelikle yöntemler ve yapıcılarda parametre doğrulaması yapmak için tasarlanmıştır, [...]

Sizin durumunuzda:

public void useObject(CustomObject customObject) {
    object = customObject.getObject();
    Objects.requireNonNull(object);
    // Do stuff using object, which would throw a NPE if object is null.
}

Bu işlev, bahsettiğiniz amaçlar için yapılır; yani null olmaması gerektiğini açıkça işaretleyin; üretimde de. En büyük yararı, null değerleri ilk etapta oluşmaması gereken yerde bulmanızı sağlamaktır. Olmaması gereken bir yere aktarılan boş değerlerin neden olduğu hata ayıklama sorunlarınız daha az olacaktır.

Diğer bir avantaj ise aksine null kontroller konusunda ek esnekliktir assert. assertBoole değerini kontrol etmek için bir anahtar kelime olsa da Objects.requireNonNull(Object), bir işlevdir ve dolayısıyla kodda daha esnek ve okunabilir şekilde gömülebilir. Örneğin:

Foo foo = Objects.requireNonNull(service.fetchFoo());

// You cannot write it in on line.
Bar bar = service.fetchBar();
assert bar != null;
service.foo(Objects.requireNonNull(service.getBar()));

// You cannot write it in on line.
Bar bar = service.getBar();
assert bar != null;
service.foo(bar);

Objects.requireNonNull(Object)Yalnızca assertgenelleştirilen yerlerde null denetim için olduğunu unutmayın .assertbu konuda biraz farklı amaçlara sahiptir, yani öncelikle test etmek. Etkinleştirilmesi gerekir, böylece test için etkinleştirebilir ve üretim için devre dışı bırakabilirsiniz. Her neyse, üretim kodu için kullanmayın. Test amaçlı gereksiz ve karmaşık doğrulamalarla uygulamayı yavaşlatabilir. Sadece test amaçlı kontrolleri, üretim amaçlı kontrollerden ayırmak için kullanın.

Hakkında ayrıntılar için resmi belgelere bakın assert.


14
Kimler ve ne zaman ilan edildi mi? Herhangi bir bağlantı / referans var mı? Testlerde kolayca etkinleştirilebilen ve üretimde devre dışı bırakılabilen sıfır ayak izi doğrulamaları sağlayan aracı "eski" olarak tanımlayan aklı başında bir geliştiriciyi hayal edemiyorum.
Dmitry Pisklov

Çalışma zamanında onaylayıcının çalışıp çalışmadığına karar verebildiğiniz, ancak çalışma zamanında NPE'nin requirNonNull tarafından atılıp atılmadığını belirleyemediğiniz göz önüne alındığında, 'onunla iddiadan daha fazla kontrole sahipsiniz' ne demek?
Pete Kirkham

@DmitryPisklov Haklısın, bunu düzenledim. Test için harika bir araçtır.
akuzminykh

2
@PeteKirkham Haklısın, kontrol bunun için yanlış bir kelimeydi. Daha çok sözdizimindeki esneklikten bahsediyordum. Buna ek olarak: kodun NPE'leri atmasını neden istediğiniz nedenler burada bulunabilir.
akuzminykh

1
"üretim kodu için kullanmayın. Uygulamayı yavaşlatabilir" Olabilir, ama buna değer olabilir. Java, bir diziyi asla aşmamak için yerleşik çalışma zamanı denetimlerine sahiptir. Bunlar, olası performans cezasına rağmen, üretim dağıtımlarında bile etkinleştirilir. Bize bu konuda bir seçenek bile verilmiyor. Üretim kodunda çalışma zamanı denetimleri yapmak her zaman yanlış değildir.
Max Barraclough

22

İddialar hakkında hatırlanması gereken en önemli şey, onların devre dışı bırakılabileceğidir, bu yüzden asla yürütüleceklerini varsaymayın.

Geriye dönük uyumluluk için JVM varsayılan olarak onaylama doğrulamasını devre dışı bırakır. -Enableassertions komut satırı bağımsız değişkeni veya -ea kısayoluyla açıkça etkinleştirilmelidir:

java -ea com.whatever.assertion.Assertion

Bu nedenle, onlara güvenmek iyi bir uygulama değildir.

İddialar varsayılan olarak etkin olmadığından kodda kullanıldıklarında hiçbir zaman yürütülmeyeceklerini varsayamazsınız. Bu nedenle, her zaman null değerleri ve boş Opsiyonelleri kontrol etmeli, girişleri genel bir yönteme kontrol etmek için onaylama kullanmaktan kaçınmalı ve bunun yerine denetlenmeyen bir istisna kullanmalısınız ... Genel olarak, tüm denetimleri onaylama yokmuş gibi yapın.


Açıkçası onlara güvenmek kötü bir uygulama, ama genel olarak kullanmak kötü bir uygulama mı?
Big_Bad_E

3
@Big_Bad_E İddialar, bir programı mümkün olduğunca erken ve gürültülü bir şekilde başarısız kılmak için var olan bir hata ayıklama aracıdır. Bu durumda, bir programın iddialara rağmen başarısız olabilmesinin bir yolu olmadığından emin olmak test paketinin görevidir . Fikir, test paketi (% 100 kapsama alanına sahip, değil mi?!?) Hatasız bir şekilde yürütüldüğünde, yine de tetikleyemedikleri için iddiaları kaldırmak için tasarruf edilir. Elbette bu muhakemede biraz idealizm var, ama fikir bu.
cmaster - eski durumuna getir

11

Elbette size söylenenler açık bir yalan. İşte nedeni.

Yalnızca bağımsız jvm yürütürseniz, varsayılan olarak onaylar devre dışı bırakılır. Devre dışı bırakıldıklarında sıfır yer kaplarlar, dolayısıyla üretim uygulamanızı etkilemezler. Bununla birlikte, kodunuzu geliştirirken ve test ederken muhtemelen en iyi arkadaşlarınızdır ve test çerçevesi koşucularının çoğu iddiaları etkinleştirir (JUnit yapar), bu nedenle, birim testlerinizi çalıştırdığınızda iddia kodunuz yürütülür ve olası hataları daha önce tespit etmenize yardımcı olur (ör. bazı iş mantığı sınır denetimleri için ekler ekleyebilirsiniz; bu, uygunsuz değerler kullanan bazı kodların algılanmasına yardımcı olur).

Bununla birlikte, diğer cevabın da belirttiği gibi, tam olarak bu nedenle (her zaman etkin değildir) bazı hayati kontroller yapmak için iddialara güvenemezsiniz veya (özellikle!) Herhangi bir durumu koruyamazsınız.

Ekleri nasıl kullanabileceğinize dair ilginç bir örnek için, bir göz atın buraya - dosyanın sonunda singleThreadedAccess()201 satırındaki assert deyiminden çağrılan ve testlerde herhangi bir çok iş parçacıklı erişimi yakalamak için bir yöntem var.


4

Diğer cevaplar zaten bunu yeterince iyi kaplıyor, ancak başka seçenekler de var.

Örneğin, Bahar'ın statik bir yöntemi vardır:

org.springframework.util.Assert.notNull(obj)

Kendi Assert.something()yöntemlerine sahip başka kütüphaneler de var. Kendinizinkini yazmak da oldukça basit.

Ancak, bu bir web hizmeti ise hangi istisnaları attığınızı unutmayın. Sözü edilen önceki yöntem, örneğin, birIllegalArgumentException Spring'de varsayılan olarak 500 değerini döndüren bir .

Bir web hizmeti söz konusu olduğunda, bu genellikle değil , bir iç sunucu hatası ve 500 olmamalıdır, bunun yerine kötü bir isteği olan 400.


1
"Assert" yöntemi işlemi hemen çökertmez, bunun yerine bir tür istisna atarsa, bu bir iddia değildir. Bütün mesele, assertüretilen bir çekirdek dosyası ile anında bir çökme elde etmek, böylece durumun ihlal edildiği noktada en sevdiğiniz hata ayıklayıcı ile post-mortem yapabilirsiniz.
cmaster - reinstate monica

Varlıklar derhal bir işlemi çökertmez. Yakalanabilecek bir Hata atarlar. İşlenmeyen istisnalar, testlerin yanı sıra hataları da çökertecektir. İsterseniz anlambilimi tartışabilirsiniz. İsterseniz, istisna yerine Hata veren özel bir onay yazınız. Gerçek şu ki, vakaların ezici çoğunluğunda, uygun eylem bir hatadan ziyade bir istisna atmaktır.
Christopher Schneider

Ah, Java gerçekten assertatmayı tanımlar . İlginç. C / C ++ sürümü böyle bir şey yapmaz. Hemen a) işlemi öldürdüğü ve b) bir çekirdek dökümü oluşturduğu sinyalini verir. Bunu bir sebepten ötürü yapar: Böyle bir iddia başarısızlığında hata ayıklamak son derece basittir, çünkü hala çağrı yığını hakkında tüm bilgilere sahipsiniz. assertBunun yerine bir istisna atmayı tanımlamak , ki bu daha sonra kasıtlı olarak programsal olarak yakalanabilir (imkansız), amacı yener, imho.
cmaster - reinstate monica

Tıpkı C ve C ++ 'da bazı (veya birçok) garip şeyler olduğu gibi, Java'da da bazıları vardır. Bunlardan biri Throwable. Her zaman yakalanabilirler. Bu iyi bir şey olsun ya da olmasın, bilmiyorum. Sanırım buna bağlı. Birçok Java programı web servisleridir ve hemen hemen her nedenden ötürü çökmesi istenmeyen bir durumdur, bu yüzden hemen hemen her şey yakalanır ve günlüğe kaydedilir. Harika şeylerden biri yığın izidir ve bu genellikle bir istisna veya hatanın nedenini kendi başına teşhis etmek için yeterlidir.
Christopher Schneider

3

Hata yaparken programlama hatalarını yakalamaya yardımcı olurken, ekleri bolca kullanın .

Mantıksal olarak meydana gelebilecek bir şeyi yakalamak için assert kullanmayın, yani kötü biçimlendirilmiş giriş Assert'i yalnızca hata kurtarılamadığında kullanın.

Onaylama kontrol edildiğinde çalışan koda herhangi bir üretim mantığı koymayın. Yazılımınız iyi yazılmışsa, bu doğru bir şekilde doğrudur, ancak eğer değilse, iddiaların etkin ve devre dışı bırakıldığı ince yan etkilere ve farklı genel davranışlara sahip olabilirsiniz.

Şirketinizin "test kodu" ve "üretim kodu" aynı şeyi ancak farklı kod tabanları (veya farklı düzenleme aşamaları) olarak yapıyorsa, oradan çıkın ve bir daha geri dönmeyin. Bu yetersizlik seviyesini düzeltmeye çalışmak muhtemelen zaman kaybıdır. Şirketiniz testlerin kodunun dışına herhangi bir iddia beyanı koymazsa, lütfen üretim yapısında varsayımların devre dışı bırakıldığını ve eğer değilse, bu hatayı düzeltmenin ilk önceliğiniz olduğunu söyleyin.

Eklerin değeri, yalnızca test paketinde değil, iş mantığında da kullanılmalıdır. Bu, kodunuzun büyük parçalarından geçmek ve tüm bu iddiaları tetiklemek için birçok şeyi açık bir şekilde test etmek zorunda olmayan birçok yüksek seviye testi çözmeyi kolaylaştırır. Projelerimden birkaçında tipik testler gerçekten hiçbir şey iddia etmedi, sadece belirli girdilere dayalı bir hesaplama yapılmasını emretti ve bu da yüzlerce iddiaların kontrol edilmesine ve küçük mantık parçalarında bile sorunların bulunmasına neden oldu.


2

Assert'i istediğiniz zaman kullanabilirsiniz. Tartışma ne zaman kullanılacağıdır. Örneğin kılavuzda :

  • Genel yöntemlerde argüman denetimi için iddia kullanmayın.
  • Uygulamanızın doğru çalışması için gerektirdiği herhangi bir işi yapmak için iddiaları kullanmayın.

4
İyi kurallar. Ancak bazı nedenler eklenirse cevap daha iyi olurdu.
cmaster - reinstate monica
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.