Java'da null denetimi yapmak zorunda kalmadan bir değer getiriliyor


15

Çoğu zaman kendimi nullPointerExceptions önlemek için bazı veri hiyerarşisinden bir değer getirilirken null kontrol, hatalara eğilimli ve bir sürü boilerplate ihtiyacı buluyorum.

Bir nesneyi getirirken boş denetimi atlamama izin veren çok basit bir rutin yazdım ...

public final class NoNPE {

    public static <T> T get(NoNPEInterface<T> in) {
        try {
            return in.get();
        } catch (NullPointerException e) {
            return null;
        }
    }

    public interface NoNPEInterface<T> {
        T get();
    }
}

Biraz böyle kullanıyorum ...

Room room = NoNPE.get(() -> country.getTown().getHouses().get(0).getLivingRoom());

Yukarıdakiler, tüm ebeveyn seviyelerini kontrol etmek zorunda kalmadan bir Room nesnesi veya null elde etmeme neden oldu.

Yukarıdakiler hakkında ne düşünüyorsun? Sorunlu bir kalıp oluşturuyor muyum? Sizce bunu yapmanın daha iyi bir yolu var mı?


1
Görünüşe göre Java 8'i kullandığınız için, uygulamanızı java.util.Optionaleksik verileri temsil etmek için null yerine kullanmak üzere yeniden tasarlamayı düşünebilir miyim ? Bu, hem tanımladığınız hem de zincirin sonunda bir arıza koşulu döndürmek yerine varsayılan verilerle devam etmek istediğiniz durumlar için kullanışlı yardımcı programlar sağlar.
Periata Breatta

Sanırım Option(ya da Maybe) monad'ı yeniden keşfettin :)
Andres F.

T veya null yerine İsteğe bağlı döndürmek mümkün olabilir: bu şekilde orElse () yöntemini doğrudan kullanabilirsiniz. 18 ay sonra, ama birine yardım edebilir.
Benj

Başka yaklaşımlar bu yayını belirtilen illegalargumentexception.blogspot.com/2015/03/... bunlardan biri çok ilginç bir sözdizimi vardır kütüphane adlı kludje kullanıyor,
Benj

Yanıtlar:


13

Çözümünüz çok akıllı. Gördüğüm Sorun şu ki sen var neden bilmiyorum gerçektir null? Evde oda olmadığı için miydi? Kasabanın evi olmadığı için mi? Ülkenin kasabası olmadığı için mi? Bir yoktu çünkü miydi nullpozisyonları 1'den itibaren evler vardır bile bir hata nedeniyle toplama 0 pozisyonunda?

NonPESınıfı yaygın olarak kullanırsanız, ciddi hata ayıklama sorunlarınız olacaktır. Zincirin tam olarak nerede kırıldığını bilmek nulldaha derin bir hatayı gizleyebilecek bir sessizlikten daha iyi olduğunu düşünüyorum.

Ayrıca, bu ihlal Demeter'in Kanunu : country.getTown().getHouses().get(0).getLivingRoom(). Çoğu zaman, bazı iyi prensipleri ihlal etmek, bu prensibi ihlal etmenin neden olduğu sorunu çözmek için alışılmadık çözümler uygulamanıza neden olur.

Benim tavsiyem, dikkatli bir şekilde kullanmanız ve tren kazası antipatternerinde (yani NonPEher yerde kullanmak zorunda kalmamanız) gereken tasarım kusurunu çözmeye çalışmanızdır . Aksi takdirde tespit edilmesi zor olan hatalarınız olabilir.


Mükemmel cevap. Evet, zincirde null değerini nereden bulduğumu bilemeyeceğim. Birçok durumda ben umurumda değil ve null kontrol zorunda değilsiniz kod daha okunabilir ve boilerplate hata daha az eğilimli olduğu anlamına gelir. Ama evet, bir üst nesne boşsa, farklı bir mantıksal karar vermem gereken bazı durumlarda haklısınız, o zaman bu bir soruna neden olacaktır. Geleneksel yöntem veya İsteğe bağlı sınıf, burada daha güvenli bir çözüm olabilir.
Eurig Jones

Genel olarak, Optionmonad'ı kullanırken , zincirde eksik değerin nerede olduğu umurumda değil. Bunu önemsediğinizde, muhtemelen farklı bir tür kullanırsınız Either.
Andres F.

OP'nin yaklaşımı C # 6'lara ?.ve ?[]operatörlere benzer. Böyle bir şeyi ne zaman kullanmak isteyebileceğinize bir örnek, hiyerarşik sunucu tarafı ayarlarıdır. var shouldDoThing = settings?.a?.b?.c ?? defaultSetting;Bunun bir kısmının neden boş olduğunu kim umursuyor? Belki de ayarları getiremediniz. Belki de ayarların bir bölümünü kaldırmaya karar verdiniz. Her durumda, hiçbir zaman sunucunun ayarlarını almaya güvenemezsiniz, bu nedenle bir varsayılan genellikle iyi bir fikirdir ve gerçek ayarı alamamanız gerektiğinde neden alamadığınızı umursamazsınız. .
chris

Şimdi bunun varsayılanları yerelleştirmek ve normal erişim yoluyla istediğiniz değeri geri almaktan kesinlikle daha iyi veya daha kötü olduğunu söylemiyorum settings.a.b.c. Sonra tekrar, bu tek bir izole örnek.
chris

10

Fikir iyi, aslında gerçekten iyi. Java 8 Optionaltürleri bulunduğundan, Java İsteğe bağlı türünde ayrıntılı bir açıklama bulunabilir . Gönderdiklerinize bir örnek

Optional.ofNullable(country)
    .map(Country::getTown)
    .map(Town::Houses);

Ve dahası.


1
Evet, Java 8 ve Guava'dan isteğe bağlı sınıfın farkındaydım ve gerçekten kullanışlılar. Ancak normalde kodu okumak biraz zorlaşır ve biraz daha az performans gösterir gibi bir nesneyi getiremezsiniz. Ancak yukarıdakiler, Optional sınıfının sağladığı birçok yararlı işleçler olmasıdır.
Eurig Jones

3
@EurigJones Kodun daha az performans gösterdiğini düşünmüyorum. Okuyucunun gözünde Optionalokunabilirlik, ancak ikisinin daha okunabilir çözümü olduğunu savunuyorum , çünkü sadece - teklifinizin aksine - çok yaygın bir deyim. Sizinkinden bile daha özlü!
Andres F.

0

Metodunuz amaçlanan amaç için yeterince iyi çalışıyor, ancak kötü tasarım gibi nullbir NullPointerExceptionses aldığınızda geri dönüyor .

nullNe zaman yapabileceğinizden kaçınmaya çalışın ve sadece bir şeyi temsil ettiklerinde veya özel bir anlamı olduğunda onları geçirin ve sadece bir şeyi temsil ettikleri / ifade ettikleri zaman iade edin - aksi takdirde a atmalısınız NullPointerException. Bu, böcek ve karışıklığı önler. Bir Objectolmaması gerekiyorsa nulla NullPointeratılmalıdır. Bir nesne olabiliyorsa null, bir şey iletildiğinde hiçbir şey yanlış gitmez. Aksi takdirde yukarıdaki yöntem işe yarar.


0

Acınızı hissedebiliyorum, ancak önerilen çözüm kötü bir fikir.

  • Eğer alıcılardan biri başka bir nedenden dolayı bir NPE fırlatırsa, bunu görmezden gelirsiniz.
  • Bu iç lambda'nın korkunç bir koda dönüşmesi riski var. Örneğin, kasabada ev olmadığında özel bir sabiti iade etmek için yeni bir gereksinim varsa, tembel bir programcı lamda'yı genişletebilir ve her şeyi sarılmış olarak bırakabilir NoNPE.get.
  • Daha önce de belirtildiği gibi, Optional.maparadığınız şey budur.
  • Yeni bir NullPointerException örneği oluşturmanın cezası genellikle önemlidir. Bu, özellikle çağrı yığınınız büyüdükçe birçok mikrosaniye. Yardımcı programınızın nerede kullanılacağını tahmin etmek zor.

Yan not olarak, NoNPEInterfacebir kopyasıdır java.util.function.Supplier.

Bazı durumlarda, birçok çerçevede mevcut olan bir ifade değerlendirme aracı kullanmayı düşünebilirsiniz (örneğin: EL, SpEL):

evaluateProperty(country, "town.houses[0].livingRoom")

Web sayfası şablonları için Tamam, ancak genellikle yavaş geliştirmek (derleme zamanı kontrolü yok) ve yavaş çalıştırmak için.
kevin cline
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.