Java neden koşullu ve koşullu veya işleçlerin bileşik atama sürümlerine sahip değil? (&& =, || =)


83

Yani boolelerde ikili operatörler için Java vardır &, |, ^, &&ve ||.

Burada yaptıklarını kısaca özetleyelim:

İçin &, sonuç değeri, trueher iki işlenen değerin true; aksi takdirde sonuç olur false.

İçin |, sonuç değeri, falseher iki işlenen değerin false; aksi takdirde sonuç olur true.

Çünkü ^, sonuç değeri, trueişlenen değerlerinin farklı olmasıdır; aksi takdirde sonuç olur false.

&&Operatör gibidir &ama onun sol elin değeridir işleneninin sağ işlenen yalnızca değerlendirir true.

||Operatör gibidir |, ama onun sol elin değeridir işleneninin sağ işlenen yalnızca değerlendirir false.

Şimdi, bütün 5 arasında olanların 3 yani bileşik atama sürümleri var |=, &=ve ^=. Öyleyse sorum açık: Java neden &&=ve ||=aynı zamanda sağlamıyor ? Bunlara ihtiyacım olandan daha fazlasına ihtiyacım olduğunu görüyorum &=ve |=.

Ve "çok uzun olduğu için" nin iyi bir cevap olduğunu düşünmüyorum, çünkü Java var >>>=. Bu ihmal için daha iyi bir neden olmalı.


Gönderen 15.26 Atama Operatörleri :

12 atama operatörü vardır; [...]= *= /= %= += -= <<= >>= >>>= &= ^= |=


Uygulanırsa &&=ve ||=uygulanırsa, ilk önce sağ tarafı değerlendirmeyen tek operatör olacağı yorumunda bulunuldu . Bir bileşik atama operatörünün önce sağ tarafı değerlendirdiği şeklindeki bu fikrin bir hata olduğuna inanıyorum.

15.26.2'den itibaren Bileşik Atama Operatörleri :

Formun bir bileşik atama ifadesi, yalnızca bir kez değerlendirilmesinin dışında , türünün olduğu yere E1 op= E2eşdeğerdir .E1 = (T)((E1) op (E2))TE1E1

Kanıt olarak, aşağıdaki kod parçası bir NullPointerExceptiondeğil a atar ArrayIndexOutOfBoundsException.

    int[] a = null;
    int[] b = {};
    a[0] += b[-1];

2
İkincisi için gidiyorum, kimsenin umurunda değil: P aynı zamanda, 'x özelliği neden y dilinde değil?' bize değil, dil tasarımcılarına
sorulmalı

1
& = Ne anlama geliyor? Lütfen birisi bana söyleyebilir mi?
Tarık

@Aaron: a = a & b. Söz konusu yazılı
Federico belki KLEZ Culloca


1
@jleedev: Bu soru daha eski, ancak daha fazla oy ve gelen bağlantılar var. Herhangi bir birleştirme varsa, eskisini bununla birleştirin (evet, bu yapılabilir) derim.
polygenelubricants

Yanıtlar:


28

Nedeni

Operatörler &&=ve Java'da||= mevcut değildir çünkü geliştiricilerin çoğu için bu operatörler şunlardır:

  • hataya açık
  • Faydasız

Örnek &&=

Java &&=operatöre izin veriyorsa , bu kod:

bool isOk = true; //becomes false when at least a function returns false
isOK &&= f1();
isOK &&= f2(); //we may expect f2() is called whatever the f1() returned value

şuna eşdeğer olacaktır:

bool isOk = true;
if (isOK) isOk = f1();
if (isOK) isOk = f2(); //f2() is called only when f1() returns true

Bu ilk kod hataya açıktır çünkü birçok geliştirici f2()her zaman f1 () tarafından döndürülen değer ne olursa olsun çağrıldığını düşünür . Bu gibi bool isOk = f1() && f2();durumlarda f2()sadece denir f1()döner true.

Geliştirici f2()yalnızca f1()döndüğünde çağrılmak istiyorsa true, bu nedenle yukarıdaki ikinci kod daha az hataya meyillidir.

Else &=yeterlidir çünkü geliştirici f2()her zaman çağrılmak ister:

Aynı örnek ama &=

bool isOk = true;
isOK &= f1();
isOK &= f2(); //f2() always called whatever the f1() returned value

Ayrıca, JVM yukarıdaki kodu aşağıdaki gibi çalıştırmalıdır:

bool isOk = true;
if (!f1())  isOk = false;
if (!f2())  isOk = false;  //f2() always called

Karşılaştır &&ve &sonuçlar

Operatörlerin sonuçları &&ve &boole değerlerine uygulandığında aynı mı?

Aşağıdaki Java kodunu kullanarak kontrol edelim:

public class qalcdo {

    public static void main (String[] args) {
        test (true,  true);
        test (true,  false);
        test (false, false);
        test (false, true);
    }

    private static void test (boolean a, boolean b) {
        System.out.println (counter++ +  ") a=" + a + " and b=" + b);
        System.out.println ("a && b = " + (a && b));
        System.out.println ("a & b = "  + (a & b));
        System.out.println ("======================");
    }

    private static int counter = 1;
}

Çıktı:

1) a=true and b=true
a && b = true
a & b = true
======================
2) a=true and b=false
a && b = false
a & b = false
======================
3) a=false and b=false
a && b = false
a & b = false
======================
4) a=false and b=true
a && b = false
a & b = false
======================

Bu nedenle EVET biz yerini alabilir &&tarafından &boole değerleri için ;-)

Bunun &=yerine daha iyi kullanın &&=.

Aynısı ||=

Aşağıdakilerle aynı nedenler &&=:
operatörden |=daha az hataya meyillidir ||=.

Bir geliştirici geri döndüğünde f2()çağrılmak istemiyorsa , aşağıdaki alternatifleri öneririm:f1()true

// here a comment is required to explain that 
// f2() is not called when f1() returns false, and so on...
bool isOk = f1() || f2() || f3() || f4();

veya:

// here the following comments are not required 
// (the code is enough understandable)
bool isOk = false;
if (!isOK) isOk = f1();
if (!isOK) isOk = f2(); //f2() is not called when f1() returns false
if (!isOK) isOk = f3(); //f3() is not called when f1() or f2() return false
if (!isOK) isOk = f4(); //f4() is not called when ...

1
Merhaba @StriplingWarrior. En iyi Java uzmanımız olan meslektaşım Yannick ile görüştüm. Cevabımı, o noktayı kontrol etmek için kullanılan Java kod kaynağını kullanarak güncelledim. Dediğiniz gibi &ve &&aynı sonuçları verir. Geri bildiriminiz için teşekkürler. Cevabımı beğendin mi Şerefe.
oHo

2
Ya bunu çok hızlı yapmak istersem? && =, olsaydı & = 'den daha hızlı olurdu, bu yüzden if (a) a = bhız için kullanmalısın
maceraperestTamam

Merhaba @adventurerOK. Maalesef ne demek istediğinizi anlayamıyorum ... Bence CPU kayıtlarında saklanan değerleri kullanmaktan a&=b;daha hızlı if(a) a=b;. Bununla birlikte, bharici bellekteyse (önbelleğe alınmamışsa) if(a) a=b;daha hızlıdır. Demek istediğin bu mu? Lütfen daha fazla örnek kod sağlayın ;-) Fikrinizi merak ediyorum. Görüşürüz. Şerefe
oHo

13
"Ve bizim istediğimiz bu değil" dediğinde katılmıyorum. Ben yazarsam isOK &&= f2();ben gibi kısa devre bunu isteyeyim &&yapar.
Tor Klingberg

4
Operatörlerin hataya açık veya işe yaramaz olacağı iddianıza katılmıyorum. Bileşik ödevleri kullanmak, her zamanki gibi bir kısayol kullanmak için A = A op Byaptığınız bir şeydir, böylece herkes ne yaptıklarını mükemmel bir şekilde bilir ve sonuçların kendileri ile ilgilenebilir. Sebepleriniz gerçekten onun yokluğunun nedeni olsaydı, bunu istenmeyen patronluk olarak görürdüm. Ancak, satırı eklediğiniz için size teşekkür etmek istiyorum bool isOk = f1() || f2() || f3() || f4();çünkü kendimi görmek için kör ettim.
Franz B.

17

Muhtemelen bir şey olduğu için

x = false;
x &&= someComplexExpression();

atama xve değerlendirme olması gerektiği gibi görünüyorsomeComplexExpression() , ancak değerlendirmenin değerine bağlı xolduğu gerçeği sözdiziminden anlaşılmıyor.

Ayrıca Java'nın sözdizimi C'ye dayandığından ve hiç kimse bu operatörleri eklemek için acil bir ihtiyaç görmedi. Yine de bir if ifadesiyle daha iyi durumda olursun.


38
Bir iddia olabilir, çünkü bu iyi bir cevap olmadığını düşünüyorum x() && y() görünüyor , ifade her iki tarafını değerlendirmek gerektiğini gibi. Açıkçası insanlar bunun &&kısa devre olduğunu kabul ediyor , bu yüzden bu da devam etmelidir &&=.
polygenelubricants

2
@jleedev, kabul etti. Bu durumlarda, bunun x = x && someComplexExpression () ile eşdeğer olmadığını, x = someComplexExpression () && x ile eşdeğer olduğunu hatırlamanın önemli olduğuna inanıyorum. Sağ taraf, diğer tüm atama operatörleriyle tutarlı olacak şekilde ilk önce değerlendirilecek / değerlendirilmelidir. Ve buna göre && = & = 'den farklı bir davranışa sahip olmayacaktır.
PSpeed

@polygene Bu adil. Yine de bir şeyin nasıl göründüğü aşina olduğunuz şeye dayanıyor ve sanırım yeni bir şey eklemek istemediler. C / C ++ / Java / C # ile ilgili sevdiğim bir şey, temel ifade sözdiziminin neredeyse aynı olmasıdır.
Josh Lee

1
@PSpeed, yanılıyorsunuz. JLS, bileşik görevin ne yapması gerektiği konusunda çok net. Yukarıdaki eklememe bakın.
poligenelubricants

1
@PSpeed: Bu durumda, a -= b;tamamen farklı çalışır a &&= b;.
David Thornley

11

Java'da bu böyledir, çünkü C'de böyledir.

Şimdi, C'de neden böyle olduğu sorusu, & ve && farklı operatörler olduğunda (bazen C'nin B'den inişinden önce), & = çeşitli operatörlerin basitçe gözden kaçırılmış olmasıdır.

Ancak cevabımın ikinci bölümünde onu destekleyecek herhangi bir kaynak yok.


1
Komik tarafta - soru yakın zamanda C forumunda sorulmuştu; ve bu cevap bağlantılıydı (yinelenen olarak işaretlenmemiş olsa da) Bu da döngüsel argümanı tamamlıyor!
UKMonkey

6

Büyük ölçüde Java sözdiziminin C'ye (veya en azından C ailesine) dayandığından ve C'de tüm bu atama operatörleri, tek bir kayıtta aritmetik veya bitsel derleme yönergelerine göre derlenir. Atama operatörü versiyonu, geçiciliği önler ve optimize edilmeyen ilk derleyicilerde daha verimli kodlar üretmiş olabilir. Mantıksal operatör (C'de ifade edildiği gibi) eşdeğerleri ( &&=ve ||=) tekli montaj talimatlarına bu kadar açık bir karşılık gelmez; genellikle bir test ve dal sırasına göre genişler.

İlginçtir, yakut gibi diller yok ve && = = || var.

Düzenleme: terminoloji Java ve C arasında farklılık gösterir


Koşullu operatör eşdeğerlerinin bu kadar bariz bir karşılığı olmadığını kastettiğine inanıyorum . JLS terminolojisinde, mantıksal mantıksal operatörler &, |ve ^; &&ve ||koşullu operatörler.
poligenelubricants

C terminolojisinde, && ve || ISO 9899: 1999'da "mantıksal operatörler", s6.5.13-14. Bitsel operatörler, tek bir bite (java'da bir boole) uygulandığında yalnızca "mantıksaldır"; C'de tek bit tipi yoktur ve buradaki mantıksal operatörler tüm skaler tipler için geçerlidir.
p00ya

C99'dan önce, C'nin bir booltürü bile yoktu . Dil tarihinde bool olmadan 20 yıl. Sahip olmak için hiçbir sebep yoktu &&=. bitsel işlemler yeterliydi.
v.oddou

4

Java'nın orijinal amaçlarından biri "Basit, Nesne Yönelimli ve Tanıdık" olmaktı. Bu duruma uygulandığında, & = tanıdıktır (C, C ++ 'ya sahiptir ve bu bağlamda tanıdık, bu ikisini bilen birine tanıdık anlamına gelir).

&& = tanıdık olmayacaktı ve bu, dil tasarımcılarının dile ekleyebilecekleri her operatörü düşünmemeleri anlamında basit olmayacaktı, bu yüzden daha az ekstra operatör daha basit.


3

Boolean değişkenleri için && ve || kısa devre değerlendirmesini kullanır, & ve | yok, bu nedenle && = ve || = 'nin de kısa devre değerlendirmesini kullanmasını beklersiniz. Bunun için iyi bir kullanım durumu var. Özellikle bir döngü üzerinde yineliyorsanız, hızlı, verimli ve kısa olmak istersiniz.

Yazmak yerine

foreach(item in coll)
{
   bVal = bVal || fn(item); // not so elegant
}

yazmak istiyorum

foreach(item in coll)
{
  bVal ||= fn(item);    // elegant
}

ve bVal doğru olduğunda, yinelemelerin geri kalanında fn () çağrılmayacağını bilin.


1
Bu döngü için muhtemelen sadece yapmak istersiniz if (fn(item)) { bVal = true; break; }.
Radiodef

2

' &' ve ' &&' ile aynı değildir ' &&', ilk işlenen yanlışsa &işe yaramayacak , ancak ' ' yine de yapacak (hem sayı hem de boole ile çalışır).

Var olmanın daha mantıklı olduğuna katılıyorum ama orada değilse o kadar da kötü değil. Sanırım orada değildi çünkü C'ye sahip değil.

Gerçekten neden olduğunu düşünemiyorum.


0

Ruby'de izin verilir.

Tahmin etseydim, sık kullanılmadığı için uygulanmadığını söyleyebilirim. Başka bir açıklama, ayrıştırıcının yalnızca = işaretinden önceki karaktere bakması olabilir.


1
Java << =, >> = ve >>> = 'yi destekler, bu yüzden bu kesinlikle doğru değildir.
Yishai

doğru. Ben bunları düşünmedim. Sanırım tek açıklama, ne kadar sıklıkla kullanıldığıdır.
zzawaideh

0

"İnanılmaz çirkin görünüyor!" Dan daha iyi bir neden düşünemiyorum.


9
Ama o zaman C / Java asla güzel olmamıştı.
EFraim

1
&&=Çirkin olmayı zar zor düşünürdüm
asgs

0

&

her iki işleneni de doğrular, bu bitsel bir işleçtir. Java, tam sayı türlerine, long, int, short, char ve byte'a uygulanabilen birkaç bitsel işleç tanımlar.

&&

ilk işlenen yanlış olarak değerlendirilirse değerlendirmeyi durdurur çünkü sonuç yanlış olacaktır, bu mantıksal bir operatördür. Booleanlara uygulanabilir.

&& operatörü & operatörüne benzer, ancak kodunuzu biraz daha verimli hale getirebilir. Tüm ifadenin doğru olması için & işleciyle karşılaştırılan her iki ifadenin de doğru olması gerektiğinden, ilk ifade false döndürürse ikinci ifadeyi değerlendirmek için hiçbir neden yoktur. & Operatörü her zaman her iki ifadeyi de değerlendirir. && operatörü ikinci ifadeyi yalnızca ilk ifade doğruysa değerlendirir.

Bir && = atama operatörüne sahip olmak dile gerçekten yeni işlevsellik katmaz. Bitsel operatörün aritmetiği çok daha açıklayıcıdır, Boole aritmetiğini içeren tamsayı bitsel aritmetik yapabilirsiniz. Mantıksal operatörler yalnızca Boole aritmetiğini yapabilir.


0

Brian Goetz (Oracle'da Java Dil Mimarı) şunu yazdı :

https://stackoverflow.com/q/2324549/ [bu soru] , bu operatörlere sahip olmanın bir ilgi olduğunu ve neden henüz var olmadıklarına dair net bir argüman olmadığını gösteriyor. Bu nedenle soru şudur: JDK ekibi geçmişte bu operatörleri eklemeyi tartıştı mı ve öyleyse bunları eklemeye karşı nedenler nelerdir?

Bu özel konuyla ilgili belirli bir tartışmanın farkında değilim, ancak birisi bunu teklif ederse, cevap muhtemelen şu olurdu: bu mantıksız bir istek değil, ama ağırlığını taşımıyor.

"Ağırlığını taşımak", maliyetleri ve faydaları ile ve diğer aday özelliklere göre maliyet-fayda oranı ile değerlendirilmelidir.

Sanırım ("faiz var" deyimiyle) maliyetin sıfıra yakın olduğunu ve faydanın sıfırdan büyük olduğunu varsayıyorsunuz, bu nedenle bariz bir kazanç gibi görünüyor. Ancak bu, yanlış bir maliyet anlayışını yalanlamaktadır; bunun gibi bir özellik dil spesifikasyonunu, uygulamayı, JCK'yı ve her IDE ve Java ders kitabını etkiler. Önemsiz dil özellikleri yoktur. Sıfırdan farklı olsa da fayda oldukça küçük.

İkincil olarak, biz sonsuz sayıda özellik vardır olabilir , ama biz almak hangi olarak çok dikkatli olmak zorunda Yani, biz sadece birkaç yılda bir avuç yapabilecek kapasiteye sahip (ve kullanıcıların yeni özellikleri emmek için. Sınırlı bir kapasiteye sahip) her özellik (önemsiz görünen bile) bu bütçenin bir kısmını tüketir ve her zaman diğerlerinden alır.
Bu "neden bu özellik olmasın" değil, "bunu yapabilmemiz için başka hangi özellikleri yapmayacağız (veya ertelemeyeceğiz) ve bu iyi bir ticaret mi?" Ve bunun üzerinde çalıştığımız herhangi bir şeye karşı iyi bir takas olduğunu gerçekten hayal edemiyorum.

Bu nedenle, "korkunç bir fikir değil" çıtasını kaldırıyor (ki bu zaten oldukça iyi, pek çok özellik isteği bunu netleştirmiyor bile), ancak "evrim bütçemizin daha iyi kullanılması her şeyden çok."


-1

a & b ve a && b aynı şey değildir.

a && b, bir boole döndüren bir boole ifadesidir ve a & b, bir int döndüren bitsel bir ifadedir (a ve b, ints ise).

neden aynı olduklarını düşünüyorsun?


1
a & b, a && b'nin aksine her zaman b değerini değerlendirmelidir.
Daniel Brückner
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.