Java'da kısayol "veya atama" (| =) operatörü


89

Java'da yapmam gereken uzun bir dizi karşılaştırma var ve bunlardan birinin veya daha fazlasının doğru çıkıp çıkmadığını bilmek istiyorum. Karşılaştırmalar dizisi uzun ve okunması zordu, bu yüzden okunabilirlik için ayırdım ve otomatik olarak |=yerine bir kısayol operatörü kullanmaya başladım negativeValue = negativeValue || boolean.

boolean negativeValue = false;
negativeValue |= (defaultStock < 0);
negativeValue |= (defaultWholesale < 0);
negativeValue |= (defaultRetail < 0);
negativeValue |= (defaultDelivery < 0);

negativeValueVarsayılan <something> değerlerinden herhangi biri negatifse doğru olmayı bekliyorum . Bu geçerli mi? Beklediğim şeyi yapacak mı? Sun'ın sitesinde veya stackoverflow'da bahsedildiğini göremedim, ancak Eclipse'in bununla ilgili bir sorunu yok gibi görünüyor ve kod derleniyor ve çalışıyor.


Benzer şekilde, birkaç mantıksal kesişim yapmak istersem, &=yerine kullanabilir miyim &&?


13
Neden denemiyorsun
Roman

Bu genel boole mantığıdır, yalnızca Java değildir. böylece başka yerlere bakabilirsiniz. Ve neden denemiyorsun?
Dykam

16
@Dykam: Hayır, burada belirli bir davranış var. Java olabilir yapmayı tercih | = LHS zaten doğruysa o ÜSÖ değerlendirmek olmaz öyle ki, kısa devre - ama öyle değil.
Jon Skeet

2
@Jon Skeet: Kısa devre, var olmayan ||=operatör için uygun olabilir , ancak |=bitsel veya operatörün kombinasyon biçimidir.
David Thornley

1
@Jon Skeet: Elbette, ancak |=kısa devre yapmak diğer bileşik atama operatörleri ile tutarsız olacaktır, çünkü (eğer önemliyse) iki kez değerlendirme konusundaki olağan uyarı ile a |= b;aynı olmayacaktır . Bana öyle geliyor ki, büyük bir dil davranışı kararı vermemişti , bu yüzden amacını kaçırıyorum. a = a | b;a||=
David Thornley

Yanıtlar:


204

|=Bir bileşik atama operatörü (olup JLS 15.26.2 Boole mantıksal operatör için) |( JLS 15.22.2 ); koşullu veya ||( JLS 15.24 ) ile karıştırılmamalıdır . Orada da &=ve ^=mantıksal Boole bileşiği atama versiyonuna karşılık gelen &ve ^sırasıyla.

Başka bir deyişle, boolean b1, b2bu ikisi eşdeğerdir:

 b1 |= b2;
 b1 = b1 | b2;

Mantıksal operatörler ( &ve |) ile koşullu meslektaşları ( &&ve ||) arasındaki fark, ilkinin "kısa devre" yapmamasıdır; ikincisi yapar. Yani:

  • &ve | daima her iki operandı da değerlendirin
  • &&ve ||doğru işleneni koşullu olarak değerlendirin ; doğru işlenen, yalnızca değeri ikili işlemin sonucunu etkileyebiliyorsa değerlendirilir. Bu, doğru işlenenin şu durumlarda DEĞERLENDİRİLMEDİĞİ anlamına gelir:
    • Sol işleneni şu şekilde &&değerlendirir:false
      • (çünkü doğru işlenen ne olarak değerlendirilirse değerlendirilsin, tüm ifade öyle false)
    • Sol işleneni şu şekilde ||değerlendirir:true
      • (çünkü doğru işlenen ne olarak değerlendirilirse değerlendirilsin, tüm ifade öyle true)

Yani orijinal sorunuza geri dönersek, evet, bu yapı geçerlidir ve |=tam olarak eşdeğer bir kısayol değildir =ve ||istediğinizi hesaplar. |=Kullanımınızda operatörün sağ tarafı basit bir tamsayı karşılaştırma işlemi olduğu için |kısa devre yapmama gerçeği önemsizdir.

Kısa devre yapmanın istendiği veya hatta gerekli olduğu durumlar vardır, ancak senaryonuz onlardan biri değildir.

Bazı diğer dillerden farklı olarak, Java yok talihsiz &&=ve ||=. Bu soru Java'da neden koşullu ve koşullu veya işleçlerin bileşik atama sürümlerine sahip değildir? (&& =, || =) .


+1, çok kapsamlı. RHS'nin hiçbir yan etkisinin olmadığını belirleyebilirse, bir derleyicinin kısa devre operatörüne dönüşmesi makul görünmektedir. bunun hakkında herhangi bir ipucu?
Carl

RHS önemsiz olduğunda ve SC gerekli olmadığında, "akıllı" SC operatörlerinin aslında biraz daha yavaş olduğunu okudum. Doğruysa, bazı derleyicilerin belirli koşullar altında SC'yi NSC'ye dönüştürebileceğini merak etmek daha ilginçtir.
poligenel yağlayıcılar

@polygenelubricants kısa devreli operatörler, kaputun altında bir tür dal içerir, bu nedenle, operatörlerle kullanılan doğruluk değerlerine yönelik dal tahmini dostu bir model yoksa ve / veya kullanımdaki mimari iyi / herhangi bir dal tahminine sahip değilse ( ve derleyicinin ve / veya sanal makinenin ilgili optimizasyonları kendilerinin yapmadığını varsayarsak, evet, SC operatörleri kısa devre yapmama ile karşılaştırıldığında biraz yavaşlık getirecektir. Derleyicinin herhangi bir şey yapıp yapmadığını öğrenmenin en iyi yolu, SC'ye karşı NSC'yi kullanarak bir program derlemek ve sonra bayt kodunu karşılaştırarak farklı olup olmadığını görmek olacaktır.
JAB

Ayrıca, bitsel OR operatörü olan ile karıştırılmamalıdır da |
user253751

16

|| şeklinde bir "kısayol" (veya kısa devre yapan) operatörü değildir. ve && (çünkü sonucu LHS'ye göre zaten biliyorlarsa RHS'yi değerlendirmeyeceklerdir) ancak çalışma açısından istediğinizi yapacaktır .

Farkın bir örneği olarak, bu kod textboş ise iyi olacaktır :

boolean nullOrEmpty = text == null || text.equals("")

oysa bu olmaz:

boolean nullOrEmpty = false;
nullOrEmpty |= text == null;
nullOrEmpty |= text.equals(""); // Throws exception if text is null

(Açıkçası "".equals(text)bu özel durum için yapabilirsiniz - sadece prensibi göstermeye çalışıyorum.)


3

Sadece bir ifadeniz olabilir. Birden çok satır üzerinden ifade edildiğinde, neredeyse tam olarak sizin örnek kodunuz gibi okur, yalnızca daha az zorunludur:

boolean negativeValue
    = defaultStock < 0 
    | defaultWholesale < 0
    | defaultRetail < 0
    | defaultDelivery < 0;

En basit ifadeler için kullanmak |, ||karşılaştırma yapmaktan kaçınmasına rağmen, dolaylı olarak bir dalı kullanmak anlamına geldiğinden ve bu birçok kez daha pahalı olabileceğinden daha hızlı olabilir.


Sadece bir tane ile başladım, ancak orijinal soruda belirtildiği gibi "Karşılaştırmalar dizisi uzun ve okunması zordu, bu yüzden okunabilirlik için ayırdım" diye hissettim. Bunun yanı sıra, bu durumda, bu özel kod parçasının çalışmasını sağlamaktan çok | = davranışını öğrenmekle ilgileniyorum.
David Mason

1

Probleminiz için aşırı bir şey olsa da, Guava kütüphanesinin Predicates ile bazı güzel sözdizimi vardır ve veya / ve s'lerin kısa devre değerlendirmesini yapar Predicate.

Esasen, karşılaştırmalar nesnelere dönüştürülür, bir koleksiyon halinde paketlenir ve ardından tekrarlanır. Veya tahminler için, ilk gerçek isabet yinelemeden geri döner ve bunun tersi ve için.


1

Okunabilirlikle ilgiliyse, test mantığından ayırma testine tabi tutulmuş veriler kavramına sahibim. Kod örneği:

// declare data
DataType [] dataToTest = new DataType[] {
    defaultStock,
    defaultWholesale,
    defaultRetail,
    defaultDelivery
}

// define logic
boolean checkIfAnyNegative(DataType [] data) {
    boolean negativeValue = false;
    int i = 0;
    while (!negativeValue && i < data.length) {
        negativeValue = data[i++] < 0;
    }
    return negativeValue;
}

Kod daha ayrıntılı ve kendini açıklayıcı görünüyor. Yöntem çağrısında şöyle bir dizi bile oluşturabilirsiniz:

checkIfAnyNegative(new DataType[] {
    defaultStock,
    defaultWholesale,
    defaultRetail,
    defaultDelivery
});

"Karşılaştırma dizesi" nden daha okunabilir ve ayrıca kısa devre yapmanın performans avantajına sahiptir (dizi tahsisi ve yöntem çağrısı pahasına).

Düzenleme: Varargs parametreleri kullanılarak daha da fazla okunabilirlik elde edilebilir:

Yöntem imzası şöyle olacaktır:

boolean checkIfAnyNegative(DataType ... data)

Çağrı şöyle görünebilir:

checkIfAnyNegative( defaultStock, defaultWholesale, defaultRetail, defaultDelivery );

1
Karşılaştırmalarda bazı pahalı işlemleriniz yoksa (sorudaki örnek ucuz olsa da), dizi ayırma ve yöntem çağrısı kısa devre için oldukça büyük bir maliyettir. Bunu söyledikten sonra, çoğu zaman kodun sürdürülebilirliği performansla ilgili hususları gölgede bırakacaktır. Karşılaştırmayı bir grup farklı yerde farklı yapıyor olsaydım veya 4'ten fazla değeri karşılaştırsaydım muhtemelen böyle bir şey kullanırdım, ancak tek bir durumda zevklerime göre biraz ayrıntılı.
David Mason

@DavidMason Katılıyorum. Ancak, çoğu modern hesap makinesinin bu tür bir ek yükü birkaç miliden daha kısa sürede yutacağını unutmayın. Şahsen, makul görünen performans sorunları olana kadar genel masrafları umursamam . Ayrıca, özellikle javadoc JAutodoc tarafından sağlanmadığında veya oluşturulmadığında, kod ayrıntı düzeyi bir avantajdır.
Krzysztof Jabłoński

1

Eski bir gönderi ama yeni başlayanlara farklı bir bakış açısı sağlamak için bir örnek vermek istiyorum.

Bence benzer bir bileşik operatör için en yaygın kullanım durumu olacaktır +=. Eminim hepimiz şöyle bir şey yazmışızdır:

int a = 10;   // a = 10
a += 5;   // a = 15

Bunun amacı neydi? Amaç, standart metinden kaçınmak ve tekrarlayan kodu ortadan kaldırmaktı.

Böylece, sonraki satır tam olarak aynı şeyi yapar ve değişkeni b1aynı satıra iki kez yazmaktan kaçınır .

b1 |= b2;

1
Özellikle isimler uzun olduğunda operasyondaki ve operatör isimlerindeki hataları tespit etmek daha zordur. longNameOfAccumulatorAVariable += 5; vs. longNameOfAccumulatorAVariable = longNameOfAccumulatorVVariable + 5;
Andrei

0
List<Integer> params = Arrays.asList (defaultStock, defaultWholesale, 
                                       defaultRetail, defaultDelivery);
int minParam = Collections.min (params);
negativeValue = minParam < 0;

Sanırım bunu tercih ederim negativeValue = defaultStock < 0 || defaultWholesale < 0. Buradaki tüm kutulama ve paketlemelerin verimsizliği bir yana, kodunuzun gerçekte ne anlama geldiğini anlamak kadar kolay bulmuyorum.
Jon Skeet

Bende 4'ten fazla parametre var ve kriter hepsi için aynı, sonra çözümümü seviyorum, ancak okunabilirlik uğruna onu birkaç satıra ayırırdım (yani Liste oluşturun, minvalue bulun, minvalue'yu 0 ile karşılaştırın) .
Roman

Bu, çok sayıda karşılaştırma için faydalı görünüyor. Bu durumda, netlikteki azalmanın yazma vb. Tasarruflara değmeyeceğini düşünüyorum
David Mason

0

|| mantıksal boole VEYA
| bitsel VEYA

| = bitsel kapsayıcı OR ve atama operatörü

| = 'Nin kısa devre yapmamasının nedeni, bitsel VEYA mantıksal OR olmamasıdır. Demek ki:

C | = 2, C = C | ile aynıdır | 2

Java operatörleri için eğitim


Boole'lerle bitsel VEYA HİÇBİR! Operatör |bitsel tamsayı VEYA'dır ancak aynı zamanda mantıksal OR'dir
user85421

Haklısınız çünkü tek bir bit için (boole) bitsel ve mantıksal OR eşdeğerdir. Pratik olarak da sonuç aynı.
oneklc
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.