it-swarm.dev

Boş referanslar gerçekten kötü bir şey midir?

Programlama dillerine boş referansların dahil edilmesinin "milyar dolarlık hata" olduğunu söylediğini duydum. Ama neden? Elbette, NullReferenceExceptions'a neden olabilirler, ama ne olacak? Dilin herhangi bir unsuru, yanlış kullanılırsa hata kaynağı olabilir.

Ve alternatifi nedir? Sanırım bunu söylemek yerine:

Customer c = Customer.GetByLastName("Goodman"); // returns null if not found
if (c != null)
{
    Console.WriteLine(c.FirstName + " " + c.LastName + " is awesome!");
}
else { Console.WriteLine("There was no customer named Goodman.  How lame!"); }

Bunu söyleyebilirsin:

if (Customer.ExistsWithLastName("Goodman"))
{
    Customer c = Customer.GetByLastName("Goodman") // throws error if not found
    Console.WriteLine(c.FirstName + " " + c.LastName + " is awesome!"); 
}
else { Console.WriteLine("There was no customer named Goodman.  How lame!"); }

Ama bu nasıl daha iyi? Her iki durumda da, müşterinin var olup olmadığını kontrol etmeyi unutursanız, bir istisna alırsınız.

Bir CustomerNotFoundException daha açıklayıcı olması nedeniyle bir NullReferenceException hata ayıklamak için biraz daha kolay olduğunu varsayalım. Hepsi bu kadar mı?

165
Tim Goodman

boş şeytan

InfoQ hakkında bu konuda bir sunum var: Boş Referanslar: Milyar Dolarlık Hata Tony Hoare

Seçenek türü

İşlevsel programlamanın alternatifi, SOME value Veya NONE içerebilen bir Seçenek türü kullanmaktır.

Seçenek türünü tartışan ve Java için bunun bir uygulamasını sağlayan iyi bir makale “Seçenek” Deseni.

Ayrıca Java bu sorun hakkında bir hata raporu buldum: Java güzel seçenek türleri . istenen özellik Java 8) içinde tanıtıldı.

93
Jonas

Sorun şu ki, teoride herhangi bir nesne boş olabilir ve kullanmaya çalıştığınızda bir istisna atabilir, nesne yönelimli kodunuz temel olarak patlamamış bombaların bir koleksiyonudur.

Zarif hata işlemenin null denetleme if ifadeleri ile işlevsel olarak aynı olabileceğini haklıyorsunuz. Ama kendinizi ikna ettiğiniz bir şey yapamadığında ne olur? belki null olmak, aslında null olur mu? Kerboom. Bundan sonra ne olursa olsun, 1) zarif olmayacak ve 2) beğenmeyeceğinize bahse girmeye hazırım.

Ve "hata ayıklaması kolay" değerini göz ardı etmeyin. Olgun üretim kodu çılgın, genişleyen bir yaratıktır; neyin yanlış gittiğine ve sizi saatlerce kazmanıza neden olabilecek yerlere dair daha fazla bilgi veren her şey.

129
BlairHippo

Kodda null referansları kullanmanın çeşitli sorunları vardır.

İlk olarak, genellikle bir özel durum belirtmek için kullanılır. Normalde uzmanlık yapılırken her durum için yeni bir sınıf veya sabit tanımlamak yerine, boş bir referans kullanmak kayıplı, kitlesel olarak genelleştirilmiş tip/değer kullanıyor.

İkinci olarak, bir boş başvuru göründüğünde hata ayıklama kodu zorlaşır ve siz neyin ürettiğini belirlemeye çalışırsınız, yukarı akış yürütme yolunu izleyebilseniz bile hangi durumun geçerli olduğunu ve nedenini belirtir.

Üçüncü olarak, null referanslar test edilecek ek kod yolları ekler.

Dördüncüsü, null referanslar parametrelerin yanı sıra dönüş değerleri için geçerli durumlar olarak kullanıldığında, savunma programlama (tasarımın neden olduğu durumlar için) çeşitli yerlerde daha boş referans kontrolü yapılmasını gerektirir… sadece durum.

Beşinci olarak, bir nesnenin yöntem tablosunda seçici arama gerçekleştirdiğinde, dilin çalışma zamanı zaten tür denetimleri gerçekleştiriyor. Böylece, nesnenin türünün geçerli/geçersiz olup olmadığını kontrol ederek ve çalışma zamanının yöntemini çağırmak için geçerli nesnenin türünü kontrol etmesini sağlayarak çabayı çoğaltabilirsiniz.

Neden çağırmak için NullObject pattern to çalışma zamanının kontrolünden yararlanın kullanmıyorsunuz NOP = bu duruma özgü yöntemler (normal durumun arayüzüne uygun) ve aynı zamanda kod tabanınızdaki boş referanslar için tüm ekstra denetimleri ortadan kaldırır mı?

Özel bir durumu temsil etmek istediğiniz her arabirim için bir NullObject sınıfı oluşturarak daha fazla iş içerir. Fakat en azından uzmanlık izole edilir durumun mevcut olabileceği kod yerine her özel duruma. IOW, yöntemlerinizde daha az alternatif yürütme yolu var olduğu için test sayısı azaldı.

50
Huperniketes

Beklenmedikçe boş değerler o kadar da kötü değildir. gerekir kodda açıkça bir dil tasarımı sorunu olan null beklediğinizi belirtmeniz gerekir. Bunu düşün:

Customer? c = Customer.GetByLastName("Goodman");
// note the question mark -- 'c' is either a Customer or null
if (c != null)
{
    // c is not null, therefore its type in this block is
    // now 'Customer' instead of 'Customer?'
    Console.WriteLine(c.FirstName + " " + c.LastName + " is awesome!");
}
else { Console.WriteLine("There was no customer named Goodman.  How lame!"); }

Bir Customer?, derleme zamanı hatası almalısınız. Daha fazla dilin bunu yapmamasının nedeni (IMO), hangi kapsamda olduğuna bağlı olarak bir değişkenin türünü değiştirmelerini sağlamamasıdır. Dil bunun üstesinden gelebiliyorsa, sorun tamamen tip sistemi.

Seçenek türlerini ve Maybe kullanarak bu sorunu ele almanın işlevsel bir yolu da vardır, ancak bu kadar tanıdık değilim. Doğru kod teorik olarak doğru bir şekilde derlemek için eklenen bir karakter gerekir çünkü bu şekilde tercih ederim.

null talihsiz semptomlarını kapsayan birçok mükemmel cevap var, bu yüzden alternatif bir argüman sunmak istiyorum: Null, yazım sisteminde bir kusurdur.

Bir yazı sisteminin amacı, bir programın farklı bileşenlerinin "birbirine tam olarak oturmasını" sağlamaktır; iyi yazılmış bir program tanımsız davranışa "Rails off" olamaz.

Java'nın varsayımsal bir lehçesini veya tercih ettiğiniz statik olarak yazılan diliniz ne olursa olsun, "Hello, world!" herhangi bir türdeki herhangi bir değişkene:

Foo foo1 = new Foo();  // Legal
Foo foo2 = "Hello, world!"; // Also legal
Foo foo3 = "Bonjour!"; // Not legal - only "Hello, world!" is allowed

Ve şöyle değişkenleri kontrol edebilirsiniz:

if (foo1 != "Hello, world!") {
    bar(foo1);
} else {
    baz();
}

Bu konuda imkansız bir şey yok - biri isterse böyle bir dil tasarlayabilirdi. Özel değer "Hello, world!" - 42 sayısı, Tuple (1, 4, 9) veya diyelim ki null. Ama bunu neden yaptın? Foo türünde bir değişken yalnızca Foos içermelidir - bu, tür sisteminin bütün noktasıdır! null, Foo değil, "Hello, world!" dır-dir. Daha da kötüsü, null herhangi bir türün değeri değildir ve onunla yapabileceğiniz hiçbir şey yoktur!

Programcı, bir değişkenin gerçekte Foo içerdiğinden asla emin olamaz ve program da olamaz; tanımlanmamış davranışı önlemek için "Hello, world!" _ Foos olarak kullanmadan önce. Önceki snippet'te dize denetimi yapmanın, foo1'in gerçekten bir Foo - bar olduğu gerçeğini yaymadığını unutmayın, sadece güvenli olmak için de kendi denetimi olacaktır.

Bunu, desen eşleşmesi olan bir Maybe/Option türü kullanarak karşılaştırın:

case maybeFoo of
 |  Just foo => bar(foo)
 |  Nothing => baz()

İçinde Just foo yan tümcesi, hem siz hem de program bizim Maybe Foo değişkeni gerçekten bir Foo değeri içeriyor - bu bilgi çağrı zincirinde ilerliyor ve bar herhangi bir kontrol yapmak zorunda değil. Çünkü Maybe FooFoo 'dan farklı bir türdür, Nothing içerme olasılığını ele almak zorunda kalırsınız, böylece asla bir NullPointerException ile körleştiremezsiniz. Programınız hakkında çok daha kolay bir şekilde mantık yürütebilirsiniz ve derleyici Foo türündeki tüm değişkenlerin gerçekten Foos içerdiğini bilerek null kontrolleri atlayabilir. Herkes kazanır.

20
Doval

null işaretçisi bir araçtır

düşman değil. Sadece onları doğru kullanmalısın.

Boş bir işaretçi hatasını bulup düzeltmeye kıyasla, tipik bir geçersiz işaretçi hatasını bulmanın ve düzeltmenin ne kadar zaman alacağını düşünün. İşaretçiyi null ile karşılaştırmak kolaydır. Boş olmayan bir işaretçinin geçerli verilere işaret edip etmediğini doğrulamak bir PITA'dır.

Hala ikna olmadıysanız, senaryonuza iyi bir doz çoklu okuma ekleyin, sonra tekrar düşünün.

Hikayenin ahlakı: Çocukları suya atmayın. Ve kaza için aletleri suçlamayın. Uzun zaman önce sıfır sayısını icat eden adam oldukça zekiydi, o günden beri "hiçbir şey" adını verebilirsiniz. null işaretçisi bundan çok uzakta değil.


EDIT:NullObject kalıbı, boş olabilecek referanslardan daha iyi bir çözüm gibi görünse de, kendi başına sorunlar getirir:

  • NullObject tutan bir referans (teoriye göre) bir yöntem çağrıldığında hiçbir şey yapmamalıdır. Bu nedenle, şimdi boş olmayan (yehaa!) Olduğu ancak istenmeyen bir eylem gerçekleştirdiği garanti edilen yanlışlıkla atanmamış referanslar nedeniyle küçük hatalar ortaya çıkabilir: hiçbir şey. Bir NPE ile sorunun nerede olduğu açıktır. Bir şekilde davranan (ancak yanlış) bir NullObject ile, (çok) geç tespit edilen hata riskini ortaya koyarız. Bu, geçersiz bir işaretçi sorununa benzer bir tesadüf değildir ve benzer sonuçları vardır: Referans, geçerli verilere benzeyen, ancak değil, veri hatalarına neden olan ve izlenmesi zor olabilen bir şeye işaret eder. Dürüst olmak gerekirse, bu durumlarda göz kırpma olmadan hemen , şimdi, aniden bana çarpan bir mantıksal/veri hatası üzerinde başarısız olan bir NPE'yi tercih ederim yolun aşağısında. Hataların maliyetinin hangi aşamada tespit edildiklerinin bir işlevi olduğuna dair IBM çalışmasını hatırlıyor musunuz?

  • NullObject üzerinde bir yöntem çağrıldığında, bir özellik alıcısı veya bir işlev çağrıldığında veya yöntem out aracılığıyla değerler döndürdüğünde hiçbir şey yapmama kavramı. Diyelim ki dönüş değeri int ve "hiçbir şey yapma" ifadesinin "dönüş 0" anlamına geldiğine karar veriyoruz. Ama nasıl emin olabiliriz ki, 0 geri döndürülecek doğru "hiçbir şey" dir? Sonuçta, NullObject hiçbir şey yapmamalıdır, ancak bir değer istendiğinde bir şekilde tepki vermelidir. Başarısızlık bir seçenek değildir: NPE'yi önlemek için NullObject kullanıyoruz ve kesinlikle başka bir istisna ile ticaret yapmıyoruz (uygulanmadı, sıfıra böl, ...), değil mi? Öyleyse, bir şeyi iade etmek zorunda kaldığınızda hiçbir şeyi doğru bir şekilde nasıl iade edemezsiniz?

Yardım edemem, ancak birisi her soruna NullObject desenini uygulamaya çalıştığında, başka bir hata yaparak bir hatayı onarmaya çalışmak gibi görünüyor. Şüphesiz bazı vakalarda iyi ve yararlı bir çözümdür, ancak kesinlikle tüm vakalar için sihirli mermi değildir.

15
JensG

(Şapkamı eski bir soru için yüzüğe atmak;))

Null ile ilgili özel sorun, statik yazmayı bozmasıdır.

Eğer bir Thing t Varsa, derleyici t.doSomething() diyebileceğimi garanti edebilir. Eh, UNLESS t çalışma zamanında null. Şimdi tüm bahisler kapalı. Derleyici, Tamam olduğunu söyledi, ancak daha sonra t aslında doSomething() DEĞİL olduğunu öğrendim. Bu yüzden tür hataları yakalamak için derleyiciye güvenmek yerine, onları yakalamak için çalışma zamanına kadar beklemek zorundayım. Ben de sadece Python kullanabilirsiniz!

Dolayısıyla, bir anlamda null, statik yazımla beklenen bir sonuçla birlikte dinamik yazmayı devreye sokar.

Bu sıfıra bölme veya negatif, vb. Günlüğü arasındaki fark, i = 0 olduğunda, hala bir int olmasıdır. Derleyici yine de türünü garanti edebilir. Sorun şu ki, mantık bu değeri mantık tarafından izin verilmeyen bir şekilde yanlış uygular ... ama mantık bunu yaparsa, bu bir hatanın tanımıdır.

(Derleyici BTW bu sorunlardan bazılarını yakalayabilir . i = 1 / 0 Gibi ifadeleri derleme zamanında işaretlemek gibi. derleyicinin bir işlevi izlemesini bekle ve parametrelerin işlevin mantığıyla tutarlı olmasını sağla)

Pratik sorun, çok fazla ekstra iş yapmanız ve çalışma zamanında kendinizi korumak için boş kontroller eklemenizdir, ancak ya unutursanız? Derleyici atamanızı durdurur:

Dize s = yeni Tamsayı (1234);

Öyleyse, neden s referanslarını kesecek bir değere (null) atanmasına izin vermeli?

"Değersiz" kodunuzdaki "yazılan" referanslarla karışarak, programcılara fazladan bir yük getirirsiniz. Ve NullPointerExceptions gerçekleştiğinde, bunları izlemek daha da zaman alıcı olabilir. "This is beklenen bir şey için bir başvuru" demek için statik yazmaya güvenmek yerine, dilin "this iyi olabilir beklenen bir şey için bir başvuru olduğunu söylemesine izin veriyorsunuz. "

14
Rob

Ve alternatifi nedir?

İsteğe bağlı türler ve desen eşleştirme. C # bilmediğim için, burada Scala # :-) adlı kurgusal bir dilde bir kod parçası var

Customer.GetByLastName("Goodman")    // returns Option[Customer]
match
{
    case Some(customer) =>
    Console.WriteLine(customer.FirstName + " " + customer.LastName + " is awesome!");

    case None =>
    Console.WriteLine("There was no customer named Goodman.  How lame!");
}
8
fredoverflow

Null referanslar, mantıksız koda izin verdikleri için bir hatadır:

foo = null
foo.bar()

Tür sisteminden faydalanırsanız alternatifler vardır:

Maybe<Foo> foo = null
foo.bar() // error{Maybe<Foo> does not have any bar method}

Genel fikir, değişkeni bir kutuya koymaktır ve yapabileceğiniz tek şey, kutudan çıkarmak, tercihen Eiffel için önerilen gibi derleyici yardımını kayıt etmektir.

Haskell sıfırdan (Maybe) var, C++ 'da boost::optional<T> ama yine de tanımsız davranış alabilirsiniz ...

8
Matthieu M.

Null'ların sorunu, onlara izin veren dillerin sizi savunmaya karşı programlamaya zorlamasıdır. Bunu sağlamak için çok çaba gerektirir (savunma if-bloklarını kullanmaya çalışmaktan çok daha fazlası)

  1. onlardan beklediğiniz nesneler değil null değerindir.
  2. savunma mekanizmalarınızın gerçekten de tüm potansiyel NPE'lerle etkin bir şekilde ilgilenmesi.

Yani, aslında, sıfırlar pahalı bir şey olurlar.

6
luis.espinal

Programlama dilinizin, programınızı çalıştırmadan önce doğruluğunu kanıtlamaya çalıştığı sorun. Statik olarak yazılan bir dilde, doğru türlere sahip olduğunuzu kanıtlarsınız. Null edilemeyen referansların varsayılanına (isteğe bağlı null edilebilir referanslarla) geçerek null değerinin geçildiği ve olmaması gereken durumların çoğunu ortadan kaldırabilirsiniz. Soru, geçersiz olmayan referansları ele almak için fazladan çaba göstermenin program doğruluğu açısından faydaya değip değmeyeceğidir.

4
Winston Ewert

Sorun o kadar boş değil, birçok modern dilde boş olmayan bir başvuru türü belirleyemezsiniz.

Örneğin, kodunuz şöyle görünebilir

public void MakeCake(Egg egg, Flour flour, Milk milk)
{
    if (Egg == null) { throw ... }
    if (flour == null) { throw ... }
    if (milk == null) { throw ... }

    Egg.Crack();
    MixingBowl.Mix(Egg, flour, milk);
    // etc
}

// inside Mixing bowl class
public void Mix(Egg egg, Flour flour, Milk milk)
{
    if (Egg == null) { throw ... }
    if (flour == null) { throw ... }
    if (milk == null) { throw ... }

    //... etc
}

Sınıf referansları aktarıldığında, savunma programı, özellikle test edilen yeniden kullanılabilir üniteler oluştururken, onları önceden null için kontrol etseniz bile, tüm parametreleri null için tekrar kontrol etmenizi önerir. Aynı referans kod tabanında 10 defa null için kolayca kontrol edilebilir!

Bir şey aldığınızda normal bir boş yazı tipine sahip olabilirseniz, o zaman orada orada boş durun, daha sonra boşta olmayan bir tür olarak tüm küçük yardımcı işlevlerinize ve sınıflarınıza null olup olmadığını denetlemeden geçirmeniz daha iyi olmaz mıydı? zaman?

Bu seçenek çözümünün amacı - hata durumlarını açmanıza izin vermek için değil, dolaylı olarak boş argümanları kabul edemeyen işlevlerin tasarımına izin vermek. Türlerin "varsayılan" uygulamasının boş veya boş olup olmadığı, her iki araca da sahip olma esnekliğinden daha az önemlidir.

http://twistedoakstudios.com/blog/Post330_non-nullable-types-vs-c-fixing-the-billion-dollar-mistake

Bu ayrıca C # için en çok oy alan # 2 özelliği olarak da listelenmektedir https://visualstudio.uservoice.com/forums/121579-visual-studio/category/30931-languages-c

4
Michael Parker

Null kötülüktür. Bununla birlikte, bir sıfırın olmaması daha büyük bir kötülük olabilir.

Sorun şu ki, gerçek dünyada çoğu zaman verilerinizin olmadığı bir durumunuz var. Boşluksuz sürüm örneğiniz hala patlayabilir - ya bir mantık hatası yaptınız ve Goodman'ı kontrol etmeyi unuttunuz ya da Goodman kontrol ettiğinizde ve ona baktığınızda evlendi. (Moriarty'nin kodunuzun her parçasını izlediğini ve sizi açmaya çalıştığını anlarsanız, mantığın değerlendirilmesine yardımcı olur.)

Goodman'ın araması orada olmadığında ne yapar? Bir null olmadan bir çeşit varsayılan müşteriyi iade etmelisiniz - ve şimdi bu varsayılana bir şeyler satıyorsunuz.

Temel olarak, kodun ne işe ya da doğru çalıştığına bakılmaksızın daha önemli olup olmadığına bakılır. Uygunsuz davranış hiçbir davranışa tercih edilmiyorsa, null istemezsiniz. (Bunun doğru seçim olabileceği bir örnek için Ariane V'in ilk lansmanını düşünün. Yakalanmayan/0 hatası, roketin sert bir dönüş yapmasına neden oldu ve bu nedenle parçalandığında kendini imha etti. aslında güçlendiricinin yandığı anda herhangi bir amaca hizmet etmediğini hesaplamaya çalışıyordu - rutin dönen çöplere rağmen yörünge yapardı.)

100 üzerinden en az 99 kez null kullanmayı tercih ederim. Yine de, kendilerinin onların versiyonuna sevinçle sıçrardım.

3
Loren Pechtel

En yaygın durum için optimize edin.

Her zaman null olup olmadığını kontrol etmek sıkıcıdır - sadece Customer nesnesini tutup onunla çalışabilirsiniz.

Normal durumda, bu iyi çalışmalıdır - aramayı yaparsınız, nesneyi alır ve kullanırsınız.

istisnai durumda, (rastgele) bir müşteriyi adıyla ararsanız, bu kaydın/nesnenin var olup olmadığını bilmeden, bunun başarısız olduğuna dair bazı belirtilere ihtiyacınız olacaktır. Bu durumda, yanıt bir RecordNotFound istisnası atmak (veya altındaki SQL sağlayıcı bunu sizin için yapmasına izin).

Gelen verilere güvenip güvenemeyeceğinizi bilmediğiniz bir durumdaysanız (parametre), belki de bir kullanıcı tarafından girildiği için, 'TryGetCustomer (ad, dışarı müşteri)' Desen. İnt.Parse ve int.TryParse ile çapraz referans.

1
JBRWilkinson

İstisnalar eval değildir!

Onlar bir sebep için orada. Kodunuz kötü çalışıyorsa, istisna adı verilen dahi bir desen vardır ve bu size bir şeyin yanlış olduğunu söyler.

Boş nesneleri kullanmaktan kaçınarak, bu istisnaların bir kısmını gizlersiniz. Ben null pointer istisna iyi yazılan istisna dönüştürmek OP örnek hakkında spiking değilim, bu okunabilirliği artırmak gibi aslında iyi bir şey olabilir. @Jonas'ın işaret ettiği gibi Seçenek türü çözümünü her ne zaman aldığınızda, istisnaları gizlersiniz.

Üretim uygulamanızda olduğundan, boş seçeneği seçmek için düğmeye tıkladığınızda atılacak istisna yerine, hiçbir şey olmuyor. Boş gösterici istisnası yerine bu istisnanın bir raporunu alırız (birçok üretim uygulamasında olduğu gibi böyle bir mekanizmaya sahibiz) ve aslında onu düzeltebiliriz.

İstisnadan kaçınarak kodunuzu kurşun geçirmez hale getirmek kötü bir fikirdir, istisnayı düzelterek kod kurşun geçirmez hale getirmek, bu benim seçtiğim yol.

0
Ilya Gazman

Hayır.

Bir dilin null gibi özel bir değeri hesaba katmaması dilin sorunudur. Kotlin veya Swift gibi dillere bakarsanız, yazarı her karşılaşmada açıkça boş değer olasılığı ile uğraşmaya zorlarsa, tehlike yok.

Söz konusu dil gibi dillerde, dil null öğesinin herhangi birinin değeri olmasına izin verir-imtrak yazın, ancak daha sonra kabul etmek için herhangi bir yapı sağlamaz, bu da beklenmedik bir şekilde null olmasına neden olur (özellikle size başka bir yerden geçtiğinizde) ve böylece çökmeler alırsınız. Kötülük bu: onunla ilgilenmeden null kullanmanıza izin vermek.

0
Ben Leggiero

Nulls sorunludur, çünkü açıkça kontrol edilmeleri gerekir, ancak derleyici sizi kontrol etmeyi unuttuğunuz konusunda sizi uyaramaz. Bunu sadece zaman alan statik analizler söyleyebilir. Neyse ki, birkaç iyi alternatif var.

Değişkeni kapsam dışına çıkarın. Çok sık, null, bir programcı değişkeni çok erken bildirdiğinde veya çok uzun süre sakladığında yer tutucu olarak kullanılır. En iyi yaklaşım, değişkenten kurtulmaktır. Geçerli bir değere sahip olana kadar bunu beyan etmeyin. Bu, düşündüğünüz kadar zor bir kısıtlama değildir ve kodunuzu çok daha temiz hale getirir.

Boş nesne desenini kullanın. Bazen eksik bir değer, sisteminiz için geçerli bir durumdur. Boş nesne kalıbı burada iyi bir çözümdür. Sürekli açık kontrol ihtiyacını ortadan kaldırır, ancak yine de boş bir durumu temsil etmenizi sağlar. Bazı insanların iddia ettiği gibi "bir hata koşulu üzerinde kağıtlama" değildir, çünkü bu durumda boş bir durum geçerli bir anlamsal durumdur. Bununla birlikte, bir boş durum geçerli bir anlamsal durum olmadığında bu modeli kullanmamalısınız. Sadece değişkeninizi kapsam dışına çıkarmalısınız.

Belki/Seçenek Kullanın. Her şeyden önce, derleyici sizi eksik bir değer olup olmadığını kontrol etmeniz gerektiği konusunda uyarır, ancak bir tür açık kontrolün yerine başka bir tür denetimin yerine geçmekten daha fazlasını yapar. Options kullanarak, kodunuzu zincirleyebilir ve mutlak son dakikaya kadar gerçekten kontrol etmenize gerek kalmadan değeriniz varmış gibi devam edebilirsiniz. Scala'da örnek kodunuz şuna benzer:

val customer = customerDb getByLastName "Goodman"
val awesomeMessage =
  customer map (c => s"${c.firstName} ${c.lastName} is awesome!")
val notFoundMessage = "There was no customer named Goodman.  How lame!"
println(awesomeMessage getOrElse notFoundMessage)

Harika mesajı oluşturduğumuz ikinci satırda, müşterinin bulunup bulunmadığına dair net bir kontrol yapmıyoruz ve güzellik ihtiyacımız yok . Daha sonra birçok satır olabilen son satıra kadar, hatta OptionNone ise ne olduğumuzu açıkça endişelediğimiz farklı bir modülde bile değil. Sadece bu da değil, eğer yapmayı unutsaydık, kontrol tipine sahip olmazdı. O zaman bile, açık bir if ifadesi olmadan çok doğal bir şekilde yapılır.

Bir null ile yazdığınızda kontrastın iyi olduğunu kontrol edin, ancak kullanım sırasında şanslıysanız, yolun her adımında açık bir kontrol yapmanız veya uygulamanızın tamamının patlaması durumunda. ünite test egzersizi yapar. Sadece uğraşmaya değmez.

0
Karl Bielefeldt

NULL'un temel sorunu, sistemi güvenilmez kılmasıdır. 1980'de Tony Hoare, Turing Ödülü'ne adanmış gazetede şunları yazdı:

Ve böylece, ADA'nın yaratıcılarına ve tasarımcılarına tavsiyem en iyisi göz ardı edildi. .... Mevcut durumda bu dilin güvenilirliğin kritik olduğu uygulamalarda kullanılmasına izin vermeyin, yani nükleer santraller, seyir füzeleri, erken uyarı sistemleri, antiballistik füze savunma sistemleri. Bir programlama dili hatasından dolayı sapacak olan bir sonraki roket Venüs'e zararsız bir yolculukta keşif bir uzay roketi olmayabilir: Kendi şehirlerimizden biri üzerinde patlayan bir nükleer savaş başlığı olabilir. Güvenilmez programlar üreten güvenilmez bir programlama dili, çevremiz ve toplumumuz için güvenli olmayan arabalardan, toksik böcek ilaçlarından veya nükleer santrallerdeki kazalardan çok daha büyük bir risk oluşturur. Riski azaltmak için değil, azaltmak için dikkatli olun.

O zamandan beri ADA dili çok değişti, ancak Java, C # ve diğer birçok popüler dilde bu tür sorunlar hala var.

Bir müşteri ile tedarikçi arasında sözleşmeler oluşturmak geliştiricinin görevidir. Örneğin, C # 'da, Java’da olduğu gibi, Generics referansının Null referansının etkisini salt okunur NullableClass<T> (İki seçenek):

class NullableClass<T>
{
     public HasValue {get;}
     public T Value {get;}
}

ve sonra onu

NullableClass<Customer> customer = dbRepository.GetCustomer('Mr. Smith');
if(customer.HasValue){
  // one logic with customer.Value
}else{
  // another logic
} 

veya C # uzantı yöntemleriyle iki seçenek stili kullanın:

customer.Do(
      // code with normal behaviour
      ,
      // what to do in case of null
) 

Fark önemlidir. Bir yöntemin müşterisi olarak ne bekleyeceğinizi biliyorsunuz. Bir takımın kuralı olabilir:

Bir sınıf NullableClass türünde değilse, örnek null olmamalıdır.

Takım bu fikri Sözleşme ile Tasarım ve derleme zamanında statik kontrol kullanarak, örneğin ön koşulla güçlendirebilir:

function SaveCustomer([NotNullAttribute]Customer customer){
     // there is no need to check whether customer is null 
     // it is a client problem, not this supplier
}

veya bir dize için

function GetCustomer([NotNullAndNotEmptyAttribute]String customerName){
     // there is no need to check whether customerName is null or empty 
     // it is a client problem, not this supplier
}

Bu yaklaşım büyük ölçüde artabilir uygulama güvenilirlik ve yazılım kalitesi. Sözleşme Tasarımı, Bertrand Meyer tarafından 1988'de ünlü Nesne Tabanlı Yazılım İnşaat kitabında ve Eyfel dilinde doldurulmuş olan Hoare mantığı örneğidir, ancak modern yazılım işçiliğinde geçersiz olarak kullanılmamaktadır.

0
Artru