2009-11-25 4 views
101

제 질문은 매우 기본적인 것이지만 여전히 질문 할 가치가 있다고 생각합니다. partialHits이는 HashMap이다&& (AND) 및 || (OR) in IF statement

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

: 나는 다음과 같은 코드가 있습니다. 첫 번째 진술이 사실이라면 어떻게됩니까? 자바는 여전히 두 번째 성명을 확인합니까? 첫 번째 명령문이 true가 되려면 HashMap에 주어진 키가 포함되어서는 안되므로 두 번째 명령문을 검사하면 NullPointerException이 표시됩니다. 그래서 간단한 단어에서
, 우리는 다음과 같은 코드가있는 경우

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

것 자바 체크 ba 경우는 첫 번째 경우에서 거짓과 a 경우 두 번째 경우에 사실입니까?

답변

158

아니요 평가되지 않습니다. 그리고 이것은 매우 유용합니다. 우리가 '단락'을하지 않았다면

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

의 둘레에, 다른 방법을

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

또는 : 당신이 문자열이 null 또는 비어 있지 않은 경우, 테스트해야처럼, 당신은 쓸 수 있습니다 자바, 우리는 위의 코드 줄에서 많은 NullPointerExceptions을받습니다.

+0

두 표현식을 모두 평가할 수 있도록 비트 단위 비교가 있습니까? 즉 if (str! = null | str.isEmpty())? (실제로 이것은 실용적인 예제가 아닙니다. 실제로 바보 같지만 아이디어를 얻습니다) – Kezzer

+5

표현식에 부작용이 없으면 단락 의미론은 논리적으로 완전한 평가와 동일합니다. 즉, A가 참이라면 B를 평가하지 않고 A || B가 참임을 알 수 있습니다. 차이가 나는 유일한 시간은 표현식에 부작용이 있는지 여부입니다. 다른 연산자의 경우,'*'와'+'를 논리'and'와'or'로 사용할 수 있습니다; ((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' (논리적) 연산자라고 생각한다. 같은 기호를 가지고 있음에도 불구하고 비트 연산자 (정수 연산자)와 다릅니다 ... –

27

아니요. 확인되지 않습니다. 이 동작은 short-circuit evaluation이라고하며 Java를 비롯한 여러 언어의 기능입니다.

+2

@Azimuth : 대단히 환영합니다. 당신이 무언가를 모르는 경우, 그것을 고치는 가장 좋은 방법은 묻는 것입니다. –

5

아니요 a가 true이면 (or 테스트에서) b 테스트는 수행되지 않습니다. 테스트 결과는 b 표현식의 값이 무엇이든 항상 true입니다.

간단한 테스트 확인 :

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

하지NullPointerException을 던질 것이다!

4

아니요, Java는 단락하고 결과를 알면 평가를 중단합니다.

18

여기에있는 모든 대답은 훌륭하지만이 문제의 출처를 설명하기 위해이 질문에 대해서는 소스로 이동하는 것이 좋습니다 : Java 언어 사양.

Section 15:23, Conditional-And operator (&&) 말한다 :

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

와 유사하게, Section 15:24, Conditional-Or operator (||)는 말한다 :

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

어쩌면 반복적 인 부분 일지 모르지만 정확히 작동하는 방식을 가장 잘 확인할 수 있습니다. NullPointerException이없는

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

: 값이 거짓 경우는 true, 오른쪽 절반이) 같은 표현의 사용을 허용하는 경우 마찬가지로 조건 연산자 (:)에만 해당하는 '반'(왼쪽 절반을 평가한다.

4

예, 부울 식에 대한 단락 회로 평가는 모든 C 계열과 같은 기본 동작입니다.

흥미로운 사실은 자바는 논리 피연산자로 &| 당신이 필요로 할 때 유용 표현, 모든 조건을 평가하기 위해 (그들이이 비트 연산을 것으로 예상된다 int 유형, 오버로드)를 사용한다는 것입니다 부작용.

+0

입니다. 부울을 반환하는 메서드 changeData (data)가 제공된 경우 if (a.changeData (data) || b.changeData (data)) {doSomething(); 에() {해봐요()}이 는 changeData을 실행 | a.changeData()가 true를 돌려주는 경우} 는 B에 changeData을 실행하지 않지만, 은 (b.changeData는 (데이터) a.changeData (데이터)) 경우 a 및 b 둘 다 호출 된 경우에도 true를 반환합니다. – Sampisa

51

자바는 5 가지 부울 비교 연산자를 가지고 &, & &을, |, ||^

& 및 & &이 "와"연산자 | 및 || "연산자"는 "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은 두 매개 변수에 따라 다르기 때문에 최적화 할 수 없습니다.

+2

"자바는 4 개의 다른 부울 비교 연산자를 가지고 있습니다 : && &&, |, ||"... 당신은'^'(xor)을 잊어 버리고 있습니다. – aioobe

+0

아, 나는 boolean 값도 검사한다는 것을 몰랐습니다. 지금까지 비트 마스크 용으로 만 사용되었습니다. – Hardcoded

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); 
} 
4

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

if (A & & B)는 A가 거짓이면 단락이됩니다.

(A & & B)이면 이 아닌은 A가 참이면 단락이됩니다.

만약 A가 참이면 (A || B)가 단락 될 것입니다.

(A || B)가 이 아닐 경우은 A가 거짓 인 경우 단락이됩니다.