&& (AND) 및 || 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가 여전히 두 번째 명령문을 점검합니까? 첫 번째 문이 true이기 때문에 HashMap에 주어진 키가 포함되어서는 안되므로 두 번째 문을 확인하면을 얻습니다 NullPointerException.
간단한 코드로, 다음 코드가 있다면

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

Java 는 첫 번째 경우 false b인지 확인 하고 두 번째 경우에는 true입니까?aa

답변:


202

아니요, 평가되지 않습니다. 그리고 이것은 매우 유용합니다. 예를 들어, 문자열이 null인지 비어 있는지 테스트해야 할 경우 다음과 같이 작성할 수 있습니다.

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

또는 다른 방법으로

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

Java에 '단락'이 없으면 위의 코드 줄에서 많은 NullPointerException이 발생합니다.


비트 비교가 존재하므로 두 표현식을 모두 평가할 있습니까? 즉 if (str! = null | str.isEmpty ())? (물론 이것은 실제 사례는 아니지만 실제로는 어리석지 만 아이디어를 얻습니다)
Kezzer

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
@Kezzer : 정말 비트 비교입니까? 나는 그것이 boolean(논리적) 연산자 라고 생각합니다 . 그것은 다른입니다 bitwise... 같은 기호에도 불구하고, (정수) 연산자
user85421

4
'&&'와 '||'사이를 전환 할 때 유용한 요령 표현은 같은 방법으로한다는 점에서, 전체 표현식을 부정하는 것입니다 !(str != null && !str.isEmpty()) :이됩니다 (str !(!=) null !(&&) !(!)str.isEmpty()) 다음과 : (str == null || str.isEmpty()) 때문에 : !(!=) is == !(&&) is || !(!) eliminates itself 다른 도움이 부정은 다음과 같습니다 !(<) is >= !(>) is <= viceversa에와
egallardo

68

Java에는 5 가지 부울 비교 연산자가 있습니다. &, &&, |, ||, ^

& 및 &&는 "and"연산자입니다. | 그리고 || "or"연산자, ^은 "xor"

단일 값은 매개 변수 값을 확인하기 전에 값에 관계없이 모든 매개 변수를 확인합니다. 이중은 먼저 왼쪽 매개 변수와 해당 값을 확인하고 true( ||) 또는 false(&& )는 두 번째 그대로 둡니다. 컴파일 된 소리? 쉬운 예는 그것을 분명히해야합니다 :

모든 예에 대해 주어진다 :

 String aString = null;

과:

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

평가가 완료되기 전에 두 매개 변수를 모두 확인하고 두 번째 매개 변수에 대해 NullPointerException이 발생합니다.

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

첫 번째 매개 변수가 확인되고가 반환 false되므로 결과가 false어쨌든 두 번째 매개 변수가 확인되지 않습니다 .

OR에 대해서도 동일합니다.

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

NullPointerException도 발생합니다.

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

첫 번째 매개 변수가 확인되고가 반환 true되므로 결과가 true어쨌든 두 번째 매개 변수가 확인되지 않습니다 .

XOR은 두 매개 변수에 따라 다르므로 최적화 할 수 없습니다.


3
"자바에는 4 가지 부울 비교 연산자가 있습니다 : &, &&, |, ||"... 잊고 있습니다 ^(xor).
aioobe

부울 부울 값도 확인한다는 것을 알지 못했습니다. 지금까지 비트 마스크에만 사용했습니다.
하드 코딩 된


20

여기에있는 모든 대답은 훌륭하지만 이것이 어디에서 왔는지 설명하기 위해 이와 같은 질문에 대해서는 소스 : Java 언어 사양으로 이동하는 것이 좋습니다.

섹션 15:23, 조건부 연산자 (&&) 는 다음과 같이 말합니다.

&& 연산자는 & (§15.22.2)와 비슷하지만 왼쪽 피연산자의 값이 참인 경우에만 오른쪽 피연산자를 평가합니다. [...] 런타임시 왼쪽 피연산자 표현식이 먼저 평가됩니다. [...] 결과 값이 false이면 조건부 및 표현식의 값이 false이고 오른쪽 피연산자 표현식이 평가되지 않습니다. . 왼쪽 피연산자의 값이 true이면 오른쪽 표현식이 평가되고 [...] 결과 값이 조건부 및 표현식의 값이됩니다. 따라서 &&는 부울 피연산자에서 &와 동일한 결과를 계산합니다. 오른쪽 피연산자 표현식이 항상이 아니라 조건부로 평가된다는 점만 다릅니다.

마찬가지로, 조건부 또는 연산자 (||) 섹션 15:24 는 다음과 같이 말합니다.

|| 연산자는 같다 | (§15.22.2), 왼쪽 피연산자의 값이 false 인 경우에만 오른쪽 피연산자를 평가합니다. [...] 런타임에 왼쪽 피연산자 표현식이 먼저 평가됩니다. [...] 결과 값이 true이면 조건부 또는 표현식의 값이 true이고 오른쪽 피연산자 표현식이 평가되지 않습니다. 왼쪽 피연산자의 값이 false이면 오른쪽 표현식이 평가됩니다. [...] 결과 값은 조건부 또는 표현식의 값이됩니다. 따라서 || 와 동일한 결과를 계산합니다 | 부울 또는 부울 피연산자에서. 오른쪽 피연산자 표현식이 항상이 아니라 조건부로 평가된다는 점만 다릅니다.

약간 반복적이지만, 작동 방식을 정확히 확인하는 것이 가장 좋습니다. 마찬가지로 조건부 연산자 (? :)는 적절한 '반'(값이 true이면 왼쪽 절반, false이면 오른쪽 절반) 만 평가하여 다음과 같은 표현식을 사용할 수 있습니다.

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

NullPointerException이 없습니다.


6

아니오, a가 ( or시험에서) 참이면 b의 값이 무엇이든 시험 결과가 항상 참이므로 b는 시험되지 않습니다.

간단한 테스트를 수행하십시오.

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

것입니다 하지 을 던져 NullPointerException!


6

여기서 단락은 두 번째 조건이 평가되지 않음을 의미합니다.

A가 False이면 (A && B)가 단락됩니다.

A가 True 이면 (A && B)가 단락 되지 않습니다 .

(A || B)이면 A가 True 인 경우 단락됩니다.

만약 (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를 호출 한 경우.
Sampisa

0

이것은 &와 &&의 기본적인 차이점으로 되돌아갑니다. | 그리고 ||

BTW 같은 작업을 여러 번 수행합니다. 효율성이 문제인지 확실하지 않습니다. 일부 중복을 제거 할 수 있습니다.

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.