Gerekli yöntem parametreleri için assert veya IllegalArgumentException kullanmak daha mı iyidir?


87

Java'da hangisi daha çok önerilir ve neden? Her iki tip de istisnalar ortaya çıkaracaktır, bu yüzden onları idare etmek açısından aynıdır. assertbiraz daha kısa, ama bunun ne kadar önemli olduğundan emin değilim.

public void doStuff(Object obj) {
    assert obj != null;
    ...
}

vs

public void doStuff(Object obj) {
    if (obj == null) {
        throw new IllegalArgumentException("object was null");
    }
    ...
}

Bunun obj.hashCode()yerine basit bir tercih ederim ;-)
Marco

Yanıtlar:


117

DİKKAT!

İddialar açıkça kodunuzu derleme yaparken "iddialarını etkinleştirmek" için belirtmedikçe zamanında kaldırılır. Java İddialar üretim kodu kullanılmak üzere değildir ve özel yöntemlerle sınırlı olmalıdır (bkz Assertion vs İstisna özel yöntemler sadece geliştiriciler tarafından bilinen ve kullanılan bekleniyor beri). Ayrıca assertatacağım AssertionError uzanır Errordeğil Exceptionve normalde çok anormal hata var belirten (kurtulmak zordur "OutOfMemoryError" gibi, değil mi?) Eğer tedavi edebilmek için beklenmiyor.

"İddiaları etkinleştir" bayrağını kaldırın ve bir hata ayıklayıcısını kontrol edin; bu kodun derlenmediğinden (tekrar, "ea" kaldırıldığında) IllegalArgumentException atma çağrısına ... adım atmayacağınızı göreceksiniz

İkinci yapıyı kamuya açık / korunan yöntemler için kullanmak daha iyidir ve bir kod satırında yapılan bir şey istiyorsanız, bildiğim en az bir yol var. Ben şahsen kullanmak Bahar Çerçeve 'nın Assertargümanlarını ve başarısızlık o atmak 'IllegalArgumentException' kontrol etmek için birkaç yöntem vardır sınıfı. Temel olarak, yaptığınız şey:

Assert.notNull(obj, "object was null");

... Aslında, ikinci örnekte yazdığınız aynı kodu uygulayacak. Gibi birkaç diğer yararlı yöntemler vardır hasText, hasLengthiçeride.

Gerekenden fazla kod yazmaktan hoşlanmıyorum, bu yüzden yazılı satır sayısını 2 (2 satır> 1 satır) azalttığım için mutluyum :-)


Ah, iddiaların kaldırıldığını unuttum! Mükemmel cevap. Başka bir şey gelip gelmediğini görmek için biraz bekleyeceğim, sonra kabul et :)
Daenyth

2
Derleme sırasındaki iddiaları kaldıran hiçbir bayrak bulunmadığına dikkat edin ( şartlı tamamlama yoluyla kaldırılabilirler ). İddialar çalışma zamanında varsayılan olarak devre dışı bırakılmıştır (JVM'nin bunları NOOP olarak değerlendirdiğini düşünüyorum), ancak aracılığıyla java -eave program aracılığıyla etkinleştirilebilir . @Jalayn ben üretim kodunda olan iddialar bunlar için yararlıdır olarak, tamamen geçerli olduğunu düşünüyorum alanında ayıklama
Justin Muller

@ Jalayn, -1. Derleyici yok değil onaylama işlemi kodunu kaldırın. Sen cmd yapmazsan onlar çalışmayacak olsa bile java -ea.
Pacerier

5
Ne zaman kullanabileceğinizi Bahar çerçeve gerek yokObjects.requreNonNull
gizlice

46

Bir istisna kullanmanız gerekir. Bir iddiayı kullanmak bu özelliğin yanlış kullanımı olacaktır.

Denetlenmeyen istisnalar, kitaplığınızın kullanıcılarının programlama hatalarını algılamak için tasarlanırken , iddialar kendi mantığınızdaki hataları algılamak için tasarlanmıştır . Bunlar karıştırılmaması gereken ayrı konulardır.

Örneğin, bir iddia

assert myConnection.isConnected();

"Bu iddiaya yol açan her kod yolunun myConnectionbağlanmasını sağladığını biliyorum ; yukarıdaki kod geçerli bir bağlantı kuramazsa, bu noktaya ulaşmadan önce bir istisna atmalı ya da geri dönmeli" dedi.

Öte yandan, bir çek

if (!myConnection.isConnected()) {
    throw new IllegalArgumentException("connection is not established");
}

"Bağlantı kurmadan kitaplığımı aramak bir programlama hatasıdır" anlamına gelir.


1
Bu bilgi gerçekten faydalıdır, ancak Jalayn'ı kabul ediyorum, çünkü assert yöntemiyle nasıl bir hata ortaya koyabileceğime dikkat çekiyor.
Mayıs, 21

4
mükemmel nokta "Denetlenmeyen istisnalar, kitaplığınızın kullanıcılarının programlama hatalarını algılamak için tasarlanırken, iddialar kendi mantığınızdaki hataları algılamak için tasarlanmıştır. Bunlar karıştırılmaması gereken ayrı konulardır."
Asim Ghaffar 19:13

Doğru, ancak bu OP'nin bir kütüphane yazdığını varsayar. Eğer onların kodları sadece dahili kullanım içinse, bir iddia kabul edilebilir.
user949300

11

nullGeçerli bir parametre değeri olarak izin vermeyen bir işlev yazıyorsanız , @Nonnullek adımı imzaya eklemeniz Objects.requireNonNullve argümanın olup olmadığını kontrol etmek için kullanmanız nullve NullPointerExceptioneğer öyleyse bir a atmanız gerekir. @NonnullEk açıklama belgeler içindir ve bazı durumlarda derleme zamanında faydalı uyarılar sağlayacaktır. Çalışma nullzamanında geçilmesini engellemez .

void doStuff(@Nonnull Object obj) {
    Objects.requireNonNull(obj, "obj must not be null");

    // do stuff...
}

Güncelleme:@Nonnull Ek açıklama Java standart kütüphanenin bir parçası değildir. Bunun yerine, üçüncü taraf kütüphanelerinden sayısız rekabet eden standart var (bkz. Hangi @NotNull Java ek açıklamasını kullanmalıyım? ). Bu onu kullanmanın kötü bir fikir olduğu anlamına gelmez, sadece standart değil.


Objects.requireNonNull()Bana haber verdiğin için teşekkür ederim. Herhangi bir yerde benzer bir "demandTrue ()" veya "requestEqual ()" yöntemi olup olmadığını biliyor musunuz? Spring's Assert'a karşı bir şey yok ama herkes bunu kullanmıyor.
user949300,

@ user949300 Objects.requireNonNull()bağımsız değişken doğrulaması içindir. Bir argümanın bir trueşeye eşit veya eşit olması gerekiyorsa , argüman anlamsızdır. Yasadışı argümanlar dışındaki hata durumları için, hatayı daha doğru tanımlayan throwbir Exceptionkarar vermelisiniz . JUnit de var Assertama bu testler için.
cambunctious

Karekök fonksiyonu Objects.requireTrue(x >= 0.0);için, ya da bazı Objects.requireEquals(hash.length == 256)
karmaşalar için dediğim

Hangi @Nonnull kullanmak zorundayım? javax.validation.constraints.NotNull?
Aguid

Eclipse JDT ek açıklamalarını kullanırdım çünkü onlar zeki adamlar tarafından yapılmıştır :). Belgeler: help.eclipse.org/neon/… - IntelliJ’i bunları kullanacak şekilde yapılandırabilirsiniz.
koppor,

2

Ben her zaman IllegalArgumentException'ı iddiaların üzerine atmayı tercih ederim.

Beyanlar, test sonuçlarını kontrol etmek / onaylamak için çoğunlukla JUnit veya diğer test araçlarında kullanılır. Bu nedenle, diğer geliştiricilere, yönteminizin bir test yöntemi olduğu konusunda yanlış izlenim verebilir.

Ayrıca, bir yöntem yasadışı veya uygunsuz bir argüman geçirildiğinde IllegalArgumentException öğesini atmak mantıklıdır . Bu, Java geliştiricileri tarafından izlenen İstisna İşleme sözleşmesi ile daha tutarlıdır.


5
JUnit'in ortaya çıkmasından yaklaşık 40 yıl önce iddialar - bir C programcısına ASSERT makrolarını sor.
JBRWilkinson

3
bu soru c ile ilgili değil; Java hakkında. Bu yüzden Java bağlamında cevap verdim.
rai.skumar

Assert (ayrılmış anahtar kelime) ile Assert (JUnit sınıfı) arasındaki farkı karıştırmayın, ikisi de bir değişkeni kontrol etmek için kullanılır ancak bunun ötesinde ikisi çok farklı şeylerdir ve çok farklı davranırlar.
Newtopian

1

IMO ikincisi biraz daha iyidir çünkü daha fazla bilgi getirir ve daha fazla bilgi sahibi olmak için daha fazla genişletilebilir (örneğin istisna sınıfını genişleterek), ayrıca anlaşılması daha kolay olan negatif karşılaştırmayı kullanmaz.


1

Çok fazla kullanmam ama Lombock @NonNull ile ortak bir yaklaşım: https://projectlombok.org/features/NonNull

Lombok uygulaması: ithalat lombok.NonNull;

public class NonNullExample extends Something {
  private String name;

  public NonNullExample(@NonNull Person person) {
    super("Hello");
    this.name = person.getName();
  }
}

Java versiyonu:

 import lombok.NonNull;

public class NonNullExample extends Something {
  private String name;

  public NonNullExample(@NonNull Person person) {
    super("Hello");
    if (person == null) {
      throw new NullPointerException("person");
    }
    this.name = person.getName();
  }
}

Lombok her yerde kullandığım çok hoş bir kütüphane.

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.