&&(AND)および|| (OR)IFステートメント内


137

私は次のコードを持っています:

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

partialHitsHashMapはどこですか。
最初のステートメントが真実の場合はどうなりますか? Javaは2番目のステートメントを引き続きチェックしますか?最初のステートメントがtrueになるためには、HashMapに指定されたキーが含まれていてはならないため、2番目のステートメントがチェックされている場合はを取得しNullPointerExceptionます。
簡単に言えば、次のコードがある場合

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

Javaはチェックするb場合はa最初のケースではとの場合はfalseをされたa第二の場合には本当ですか?

回答:


202

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

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

または、その逆

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

Javaに「短絡」がない場合、上記のコード行で多くのNullPointerExceptionsを受け取ります。


両方の式評価できるようにビットごとの比較はありますか?すなわちif(str!= null | str.isEmpty())?(もちろん、これは実用的な例ではありませんが、実際には愚かですが、アイデアは
わかり

5
式に副作用がない限り、短絡セマンティクスは完全な評価と論理的に同等です。つまり、Aが真であれば、B |を評価しなくてもA || Bが真であることがわかります。違いが生じるのは、式に副作用があるかどうかだけです。他の事業者として、あなたは使用することができます*し、+論理などandor((A?1:0) * (B?1:0)) == 1((A?1:0) + (B?1:0)) > 0。あなたも行うことができますxor((A?1:0) + (B?1:0)) == 1
outis

1
@ケツァー:それは本当にビットごとの比較ですか?boolean(論理的な)演算子だと思います。それはよりも異なるのですbitwise...同じシンボルを持つにもかかわらず、(整数)演算子
user85421

4
「&&」と「||」を切り替えたいときに便利なトリック :表現があるように、式全体を否定することです !(str != null && !str.isEmpty()) :となり (str !(!=) null !(&&) !(!)str.isEmpty()) 、その後と: (str == null || str.isEmpty()) :ので !(!=) is == !(&&) is || !(!) eliminates itself :他の有用な否定である !(<) is >= !(>) is <= とその逆
egallardo

68

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

&と&&は「and」演算子です| そして|| 「or」演算子、^は「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は両方のパラメーターに依存しているため、最適化できません。


3
"Javaには4つの異なるブール比較演算子があります:&、&&、|、||" ... ^(xor)を忘れています。
aioobe

ああ、私はそれがブール値のブール値もチェックすることを知らなかった。これまでは、ビットマスクにのみ使用されていました。
ハードコード化された


20

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

セクション15:23、条件付きAND演算子(&&)は次のように述べています。

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

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

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

少し反復的かもしれませんが、それらがどのように機能するかを正確に確認するのに最適です。同様に、条件演算子(?:)は適切な「半分」(値がtrueの場合は左半分、falseの場合は右半分)のみを評価するため、次のような式を使用できます。

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

NullPointerExceptionなし。


6

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

簡単なテストを行います:

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

ではない投げますNullPointerException


6

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

(A && B)は、AがFalseの場合に短絡を引き起こします。

(A && B)の場合、AがTrueであれば短絡しません

If(A || B)は、AがTrueの場合に短絡します。

If(A || B)は、AがFalseの場合、短絡を引き起こしません


4

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


4

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

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


これは覚えておくことは興味深いです。たとえば、ブール値を返すメソッドchangeData(data)を指定すると、次のようになります。if(a.changeData(data)|| b.changeData(data)){doSomething(); a.changeData()がtrueを返す場合、}はbでchangeDataを実行しませんが、(a.changeData(data)| b.changeData(data)){doSomething()}は、aとbの両方でchangeData()を実行します。 trueが返されたときに呼び出された場合。
サンピサ2017

0

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

ところで、同じタスクを何度も実行します。効率が問題かどうかはわかりません。重複の一部を削除できます。

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);   
} 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.