web-dev-qa-db-ja.com

&&(AND)と|| IFステートメント内の(OR)

次のようなコードがあります。

if(!partialHits.get(req_nr).containsKey(z) || partialHits.get(req_nr).get(z) < tmpmap.get(z)){  
    partialHits.get(z).put(z, tmpmap.get(z));  
}

partialHitsはHashMapです。
最初の陳述が真実であればどうなりますか? Javaはまだ2番目のステートメントをチェックしますか? 最初のステートメントが真になるように、HashMapは与えられたキーを含むべきではないので、2番目のステートメントがチェックされるとNullPointerExceptionが得られます。
つまり、簡単に言うと、次のようなコードがあるとします。

if(a && b)  
if(a || b)

最初のケースでbがfalseで、2番目のケースでaがtrueの場合、Javaはaをチェックしますか。

122
Azimuth

いいえ、評価されません。そしてこれはとても便利です。たとえば、Stringがnullでも空でもないかどうかをテストする必要がある場合は、次のように記述できます。

if (str != null && !str.isEmpty()) {
  doSomethingWith(str.charAt(0));
}

または、その逆

if (str == null || str.isEmpty()) {
  complainAboutUnusableString();
} else {
  doSomethingWith(str.charAt(0));
}

Javaに「ショートサーキット」がなければ、上記のコード行で多数のNullPointerExceptionが発生します。

185
Andreas_D

Javaには、5つの異なるブール比較演算子、&、&&、|、||、^があります。

&と&&は "and"演算子です。と|| "または"演算子、^は "xor"です。

単一のものは、パラメータの値をチェックする前に、値に関係なくすべてのパラメータをチェックします。二重のものは最初に左のパラメータとその値をチェックし、true||)またはfalse&&)が第2のものをそのままにします。音がまとまった?簡単な例を見ればわかります。

すべての例で考えます。

 String aString = null;

そして:

 if (aString != null & aString.equals("lala"))

評価が完了する前に両方のパラメータがチェックされ、2番目のパラメータに対してNullPointerExceptionがスローされます。

 if (aString != null && aString.equals("lala"))

最初のパラメータがチェックされてfalseが返されるので、結果はとにかくfalseなので、2番目のパラメータはチェックされません。

ORについても同じです。

 if (aString == null | !aString.equals("lala"))

NullPointerExceptionも発生します。

 if (aString == null || !aString.equals("lala"))

最初のパラメータがチェックされてtrueが返されるので、結果はとにかくtrueなので、2番目のパラメータはチェックされません。

XORは両方のパラメータに依存するため、最適化できません。

61
Hardcoded

いいえそれはチェックされません。この動作は 短絡評価 と呼ばれ、Javaを含む多くの言語の機能です。

26

ここでのすべての答えは素晴らしいですが、これがどこから来たのかを説明するために、このような質問についてはソースに行くのは良いことです:Java言語仕様。

セクション15:23、条件付きAnd演算子(&&)

&&演算子は&(15.22.2)に似ているが、その右側のオペランドを評価するのはその左側のオペランドの値が真である場合だけである。 [...]実行時に、左側のオペランド式が最初に評価されます。結果の値がfalseで、条件付きand式の値がfalseで、右側のオペランド式が評価されない場合。左側のオペランドの値が真であれば、右側の式が評価され[...]、結果の値が条件付きand式の値になります。したがって、&&は、ブールオペランドの&と同じ結果を計算します。異なるのは、右辺のオペランド式が常にではなく条件付きで評価されるという点だけです。

同様に、 セクション15:24、条件付きOR演算子(||) は、次のように述べています。

||演算子はこんな感じです(15.22.2)ただし、その右側のオペランドは、その左側のオペランドの値が偽の場合にのみ評価されます。 [...]実行時に、左側のオペランド式が最初に評価されます。 [...]結果の値がtrueの場合、条件式or式の値はtrueになり、右側のオペランド式は評価されません。左側のオペランドの値がfalseの場合は、右側の式が評価されます。 [...]結果の値は、条件付きOR式の値になります。したがって、|| |と同じ結果を計算します。ブール値またはブール値のオペランド。異なるのは、右辺のオペランド式が常にではなく条件付きで評価されるという点だけです。

多少繰り返しますが、正確にはそれらがどのように機能するのかを確認するのに最適です。同様に、条件演算子(?:)は適切な 'half'(値がtrueの場合は左半分、falseの場合は右半分)のみを評価し、次のような式を使用できるようにします。

int x = (y == null) ? 0 : y.getFoo();

nullPointerExceptionなしで。

19
Cowan

いいえ、aがtrue(orテストで)の場合、bの式の値にかかわらず、テストの結果は常にtrueになるため、bはテストされません。

簡単なテストをします。

if (true || ((String) null).equals("foobar")) {
    ...
}

notNullPointerExceptionをスローします。

6
Romain Linsolas

ここでの短絡は、2番目の条件が評価されないことを意味します。

AがFalseの場合、(A && B)が短絡になる場合。

AがTrueの場合、(A && B)がではない場合、短絡になります。

AがTrueの場合、(A || B)が短絡の原因になります。

AがFalseの場合、(A || B)が ではなく の場合、短絡になります。

5
user3211238

はい、ブール式の短絡評価は、すべてのCライクファミリーのデフォルトの動作です。

興味深い事実は、Javaは論理オペランドとしても&|を使用し(これらはオーバーロードされ、int型は期待されるビット演算です)、副作用が必要な場合にも有用です。 。

4
fortran

いいえ、そうではありません。Javaは結果を知ったら、短絡して評価を中止します。

4
abyx

これは、&と&&の基本的な違いに戻ります。と||

ところで、あなたは何度も同じタスクを実行します。効率が問題であるかどうかわからない。あなたはいくつかの重複を取り除くことができます。

Z z2 = partialHits.get(req_nr).get(z); // assuming a value cannout be null.
Z z3 = tmpmap.get(z); // assuming z3 cannot be null.
if(z2 == null || z2 < z3){   
    partialHits.get(z).put(z, z3);   
} 
0
Peter Lawrey