Koşullu ise set.add () işlevinin Boole dönüşü?


15

Set sınıfının add işleci, bir öğe (eklenecek olan) zaten orada değilse doğru, aksi halde false olan bir boole döndürür. Yazıyor

if (set.add(entry)) {
    //do some more stuff
}

temiz kod yazma açısından iyi bir stil olarak kabul edildi? Bir kerede iki şey yaptığınızdan beri merak ediyorum. 1) eleman eklemek ve 2) elemanın mevcut olup olmadığını kontrol etmek.


6
Öğe zaten orada olmadığında java.util.Setdoğru olan standarttan bahsediyorsun add, değil mi?
user2357112 Monica

1
Genellikle karşı testi if (!set.add(entry)) {// entry already present, possibly a case you want to handle}
düşünürdüm

Aynı anda iki şey yapmakta yanlış bir şey mi var?
user207421

@ user2357112 evet, doğru.
Andreas Braun

Yanıtlar:


19

Evet öyle.

Bir işlemin Boole değerini döndürmesinin olağan noktası, bunu karar vermek için, yani bir ifyapı içinde kullanabilmenizdir . Bu potansiyelin farkına varmanın diğer tek yolu, dönüş değerini bir değişkende saklamak ve hemen onu bir aptalda kullanmaktır if, ki bu sadece aptalca ve kesinlikle hiçbir şekilde yazmaya tercih edilmez if(operation()) { ... }. Sadece devam edin ve yapın, sizi yargılamayacağız (bunun için).


Cevabınız için teşekkürler. @Niels vanReijmersdal'ın cevabında dikkat çektiği gibi, bu komut ve sorgu ayırmayı bozuyor, değil mi? Bunun önemli olduğunu düşünmüyor musun?
Andreas Braun

4
@AndreasBraun şahsen komut sorgusu ayırma aptal olduğunu düşünüyorum. Bir yöntemin hem bir eylem gerçekleştirmesi hem de o eylemle ilgili bir değer döndürmesi genellikle mantıklıdır. İkisi arasında yapay bir ayrımın uygulanması gereksiz yere ayrıntılı koda yol açar.

1
@ dan1111: gerçekten. Ayrıca, "komut ve sorgu ayırma", "kontrol et ve sonra harekete geç" işlemine ve çok iş parçacıklı bağlamlarda kırılabilen benzer anti kalıplara yol açar. Dünyanın geri kalanı, aynı zamanda sağlam ve verimli SMP çözümleri için atomik birleştirilmiş operasyonlar oluşturmaya çalışırken böyle bir ayrımın reklamını yapmak oldukça garip…
Holger

2
@ Jörg W Mittag: sayfa 759'dan ne? Atomik bir işlem, “kontrol et ve sonra harekete geç” anti-paternine karşı özünde bağışık olduğundan, onu bulmak için ne yapılacağını, yapı ipliğinin nasıl güvenli hale getirileceğini “bölümünün tamamını” okumak için ayırmak faydalı görünmüyor. tekrar. Hiçbir gerçek argümanı isimlendirmediğiniz için “bu argümanlara karşı itirazım yok”.
Holger

1
@ Jörg W Mittag: Bu sayfadaki cevaptan bahsediyorum, Set.addalternatif isimlendirmeden tek işlem olarak kullanmaktan vazgeçiyorum. Eğer amaçlanan işlem tek bir eleman eklemek ve eklenip eklenmediğini öğrenmekse, yine de faydasız çalışmayı zorlaştıran daha güçlü bir alternatife gerek yoktur. Umarım Set.addilk önce> 700 sayfalık bir kitap üzerinde çalışmadan kullanılabilecek yerleşik bir JRE yöntemi olduğunun farkındasınızdır .
Holger

12

Mümkün olduğunca temiz olmadığını söyleyebilirim, çünkü bakıcıyı dönüş değerinin ne anlama geldiğini zaten bilmeye veya aramaya zorlar. Zaten var olan, henüz var olmayan değerin başarıyla eklendiği anlamına mı geliyor? Çok fazla kullanmazsanız, bilemezsiniz ve yapsanız bile, bu çok daha zihinsel yüktür.

Aşağıdakileri tercih ederim:

boolean added = set.add(entry);

if (added) {
    //do some more stuff
}

Evet, biraz daha ayrıntılı, ancak derleyici hemen hemen aynı bayt kodunu üretmeli ve yıllar içinde Java setlerini kullanmayan insanlar bile hiçbir şey bakmadan mantığı takip edebilir.



9
Bir yönteme bakmak, orijinal geliştiricinin, kullanıldığı kapsam dışında bildirilen fazlalık bir değişken için niyeti anlamaya çalışmaktan daha az bir yüktür. Tüm modern Java IDE'lerinde, bir geliştirici fare işaretçisini bir yöntemin üzerine getirebilir ve belgelerine anında erişebilir. İyi geliştiriciler, bilmediğiniz herhangi bir API ile çalışırken bunu sürekli olarak yapar.
Kevin Krumwiede

9
İkinci olarak @Holger. Eğer bilmiyorsanız Set.add, size deneyimsiz ve sen gerektiğini onları öğrenmek ve daha deneyimli hale için bu yöntemleri kadar bakıyor.
Monica

7
notAlreadyPresenten iyi ifade değildir. Ben kullanırım addedve değer Set eklenemez neden okuyucu bilmek bekliyoruz.
njzk2

3
@JustinTime: Kodun ne yaptığını açıklamak için yorumları kullanmak yaygın olarak kötü uygulama olarak kabul edilir. Kodunuz kendi kendini tanımlamalı olmalıdır. Bir kod incelemesinde, örneğinizi kabul edilemez olarak işaretlerdim.
BlueRaja - Danny Pflughoeft

8

Eğer doğru başarı demekse, o zaman iyi, açık bir koddur.

Bir işlev veya yöntemin başarı üzerine doğru (veya doğru olarak değerlendirilen bir şey) döndürdüğü yaygın bir kural vardır. Kodunuzu takip ettiği sürece, yöntemi koşullu koymak iyi olduğunu düşünüyorum.

Böyle bir kod benim görüşüme göre gereksiz bir şekilde dağınık:

boolean frobulate_succeeded = thing.frobulate();

if (frobulate_succeeded) {
    ...
}

Kendinizi tekrarlıyormuşsunuz gibi geliyor.

Ancak, soru dönüş değerinin anlamı konusunda belirsizdir. "Eklenen öğenin zaten var olup olmadığını gösteren bir boolean" diyorsunuz, bu doğru öğenin var olduğu (ve ekleme gerçekleşmediği) anlamına gelebilir. Bu durumda, ideal olarak yöntemin geri dönüş davranışını daha geleneksel olacak şekilde değiştirirdim. Bu mümkün değilse, açıkça (başkaları tarafından önerildiği gibi) kodunuzdaki dönüş sonucu etiketlemek için izin veren ekstra bir ara değişken eklemek istiyorum.


Bir kümeye öğe ekleme bağlamında başarı ne anlama gelir? İstisna atmamak başarı demektir; true vs. false bu bağlamda daha spesifik bir şey ifade eder.
Monica

@ Solomonoff'sSecret Bu durumda, bir istisna, öğeyi eklemeyi reddettiği falseanlamına gelir, öğenin zaten içerildiği için eklenmediği ve trueöğenin zaten bulunmadığı anlamına gelir. As add(), kümeyi içermiyorsa öğeyi kümeye ekler, truebu nedenle öğenin kümeye başarıyla eklendiği anlamına gelir.
Justin Time - Monica'yı

@ JustinTime İki davaya kendi değer yargılarınızı ekliyorsunuz. Başka bir yorum, başarının, yöntem döndüğünde öğenin kümede olmasıdır. Öğe zaten addkümedeyse, hiçbir şey yapmadan başarılı olur. Öğe zaten kümede değilse, öğeyi kümeye addekleyerek başarılı olur. Hangi yorumun doğru olduğu keyfi. Başarının daha az keyfi tanımı, dilden bir tanesidir: yöntem normal şekilde dönerse başarılı olur.
Monica

1
Başarının en az keyfi tanımı, yöntemin gerçekleştirmek için verdiği görevi başarıyla gerçekleştirmesidir. Ben bir yöntemi varsa firstLessThanSecond(int l, int r)ve bu döndüren trueise l > rveya falseeğer l <= ryöntemdir o, değil normalde döner rağmen başarılı.
Justin Time - Monica'yı

1
@ JustinTime add, sözleşmenin ciddi bir kısaltmasıdır. Dokümantasyon, "Önceden mevcut değilse, belirtilen elemanı bu sete ekler" ile başlar; bu, öğenin sette olup olmadığından memnun kalır. Dönüş değerini istediğiniz gibi yorumlamakta özgürsünüz, ancak sonuçta bu sadece sizin yorumunuzdur. İkinci örneğinizde yöntem, bir koşulun doğru olup olmadığını değerlendirir. Koşul yanlışsa, koşul başarıyla başarıyla değerlendirildiği için yöntem kesinlikle başarısız olmamıştır.
Monica

2

Çok C benzeri olduğunu söyleyebilirim. Çoğu zaman bir mutasyon sonucu için tanımlayıcı olarak adlandırılmış bir değişkene sahip olmayı tercih ederim ve bir ifdurumda hiçbir mutasyon gerçekleşmez .

Derleyici hemen yeniden kullanılırsa bu değişkeni ortadan kaldıracaktır. Bir insan kaynağı okumak için daha kolay zaman geçirecektir; benim için daha önemli.

Birisi if durumuna bir and/ orcümlesi ekleyerek durumu uzatmak zorunda kalırsa, .add()kısa devre değerlendirmesi nedeniyle bazı durumlarda çağrı yapmayabilir . Kısa devre özellikle öngörülmedikçe, bu bir hata olarak ortaya çıkabilir.


Eğer if (set.contains(entry)){set.add(entry); //do more stuff}yazarsam bu derleyici tarafından da ortadan kaldırılır mı?
Andreas Braun

1
@AndreasBraun: Ben öyle düşünmüyorum; derleyicinin containsve arasındaki anlamsal bağlantı hakkında hiçbir fikri yoktur add. Ayrıca, entrysete bakmanın iki katını yapar ; bu çok büyük setler ve çok hafif döngüler için rol oynayabilir.
9000

1
Öyleyse yazmayı tercih edersiniz, if (set.contains(entry)){set.add(entry); //do more stuff}bunun yerine örneğin Karl Bielefeldt'in cevabı ile devam edersiniz ?
Andreas Braun

@AndreasBraun: tam olarak (bu cevabı iptal etti).
9000

1
iyi bir nokta. İlerideki mutasyonlar yanıltıcıdır, çünkü gelecekteki bir geliştiricinin kısa devrelerle başka koşulları olabilir.
njzk2

0

Kodunuz Komut Sorgusu Ayrımı'nı bozuyor gibi görünüyor . Bu, Temiz Kod kitabı ve İşlev Yapısı videosunda ele alınmıştır. Temiz Kod perspektifinden bakıldığında iyi bir stil olarak görülmediğini düşünüyorum.

“Temiz kod basit ve doğrudan. Temiz kod, iyi yazılmış nesir gibi okunur. Temiz kod asla tasarımcının niyetini gizlemez, aksine net soyutlamalar ve basit kontrol çizgileriyle doludur.

- Grady Booch, Nesneye Dayalı Analiz ve Tasarım Uygulamaları ile Yazar ”

Benim için kodunuzun amacı belirsiz. Her ikisi de, giriş eklendiğinde veya zaten var olduğunda yürütülür mü? Ne add()dönüyor? eşya? Hata kodu?


2
Evet, ben de öyle düşünmüştüm. Ama bence @Kilian Foth'un bir anlamı var. Sorgu ve komutu ayırmak istesem if (set.contains(entry)){set.add(entry); //do more stuff}, aptalca görünen bir şey yazmak zorunda kalırdım. Bu konudaki görüşünüz nedir?
Andreas Braun

Alan adı ve iyi bir isim önermek için bu kodun bağlamı bilmiyorum, ama bunu açık niyetle bir işlev ile sarın. Örneğin: doesEntryExistOrCreateEntry (giriş), bu, include () + add () mantığınızı içerebilir ve bir boolean döndürebilir. Burada benzer soru: bu uygulamayı temiz kodun dışında tartışan softwareengineering.stackexchange.com/questions/149708/… .
Niels van Reijmersdal

6
Komut sorgusu ayırma kuralı aptal olduğunu düşünüyorum, özellikle böyle bir durumda uygulandığında, bir yöntem hem bir eylem gerçekleştirir ve eylemin başarı durumunu döndürür. Ama aynı zamanda, kuralın ne olduğunu açıklamıyor ya da gerekçe için çok fazla şey sağlamıyorsunuz. Bu nedenlerle reddedildi.

1
"Add () ne döndürür?" Kod inceleme yapan herhangi bir java geliştirici CollectionAPI bilmek umuyoruz .
njzk2

3
@ Dan1111 ile aynı fikirde. Bu var özellikle bu yarış koşulları için verimli bir zemin kılan tür şeyler çünkü dilsiz.
Paul Draper
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.