67

저는 Java에서 수행 할 비교 작업이 길고, 그 중 하나 이상이 true인지를 알고 싶습니다. 비교 문자열은 길고 읽기가 어려웠으므로 가독성을 위해 깨졌으며 negativeValue = negativeValue || boolean이 아닌 바로 가기 연산자 |=을 자동으로 사용했습니다. Java의 바로 가기 "또는 - 할당"연산자 (| =)

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

나는 기본 < 일 중 하나가 > 값이 부의 경우 negativeValue 사실이 될 것으로 기대합니다. 이게 유효합니까? 그것이 내가 기대하는 것을 할 것인가? Sun의 사이트 또는 stackoverflow에서 언급 한 내용을 볼 수 없었지만 Eclipse에 문제가없는 것으로 보이며 코드가 컴파일되어 실행됩니다. 나는 몇 가지 논리적 교차점을 수행하기를 원한다면


마찬가지로, 나는 &= 대신 && 사용할 수 있을까?

+13

당신은 그것을 왜 시도하지 않습니까? – Roman

+0

이것은 Java가 아닌 일반적인 부울 논리입니다. 그래서 당신은 다른 장소에서 그것을 볼 수 있습니다. 그리고 왜 그냥 해보지 않으시겠습니까? – Dykam

+14

@Dyam : 아니요, 여기에는 구체적인 행동이 있습니다. Java *는 단락 회로를 선택하여 LHS가 이미 참인 경우 RHS를 평가하지 않을 수 있지만 그렇지 않습니다. –

답변

171

|=은 부울 논리 연산자 | (JLS 15.22.2)에 대한 복합 대입 연산자 (JLS 15.26.2)입니다. 조건부와 혼동하지 마십시오. || (JLS 15.24). 부울 논리 값 &^의 복합 할당 버전에 각각 해당하는 &=^=도 있습니다. 환언

, boolean b1, b2, 이들 두은 동일

b1 |= b2; 
b1 = b1 | b2; 

들은 조건부 대응 (&&||) 비교 논리 연산자 (&|)의 차이는 전자는 없다는 것이다 "단락 회로"; 후자는. 즉 :

  • & 항상 | 두 피연산자
  • &&||가 오른쪽 피연산자 조건부을 평가 평가; 오른쪽 피연산자는 해당 값이 2 진 조작의 결과에 영향을 줄 수있는 경우에만 평가됩니다.그 때 오른쪽 피연산자는 평가되지 않음을 의미합니다 : 이
    • &&의 왼쪽 피연산자는 false
      • 로 평가
    • (오른쪽 피연산자로 평가한다 상관없이, 전체 표현식은 false 때문에) 는
    • ||의 왼쪽 피연산자 (true
      • 평가 없음 m 때문에 오른쪽 피연산자는 전체 식) true입니다 평가 무엇 atter
그래서

원래의 질문으로 되돌아 가고, 그래, 그 구조는 유효하며, |= 정확히 동등한 바로 가기 아니지만 =||의 경우 원하는대로 계산됩니다. 사용중인 |= 연산자의 오른쪽이 간단한 정수 비교 연산이므로 |이 단락되지 않는다는 사실은 중요하지 않습니다.

단락이 필요하거나 필요하지만 시나리오가 그 중 하나가 아닌 경우가 있습니다.

다른 언어와 달리 Java에는 &&=||=이없는 것은 불행합니다. 이것은 Why doesn't Java have compound assignment versions of the conditional-and and conditional-or operators? (&&=, ||=)의 질문에서 논의되었습니다.

+0

+1, 매우 철저합니다. RHS에 부작용이 없다고 판단 할 수 있다면 컴파일러가 단락 회로 연산자로 변환 될 가능성이 높습니다. 그것에 관한 어떤 단서? – Carl

+0

RHS가 사소하고 SC가 필요하지 않은 경우 "스마트"SC 운영자는 실제로 조금 느립니다. 그렇다면 특정 환경에서 일부 컴파일러가 SC를 NSC로 변환 할 수 있는지 궁금해하는 것이 더 흥미 롭습니다. – polygenelubricants

+0

@polygenelubricants 단락 된 연산자는 후드 아래에서 일종의 분기를 포함하므로 연산자에 사용되는 진리 값 및/또는 사용중인 아키텍처에 양호한 분기 예측이없는 분기 예측 친화적 패턴이없는 경우 (그리고 컴파일러 및/또는 가상 머신이 관련 최적화를 수행하지 않는다고 가정 할 때) 그렇다면 SC 운영자는 비 단락 회로에 비해 느려질 수 있습니다. 컴파일러에서 찾을 수있는 가장 좋은 방법은 SC 대 NSC를 사용하여 프로그램을 컴파일 한 다음 바이트 코드를 비교하여 다른지 확인하는 것입니다. – JAB

15

"바로 가기"(또는 단락) 연산자가 || & & (LHS를 기반으로 결과를 이미 알고있는 경우 RHS를 평가하지 않음) 으로 원하는대로 처리 할 것입니다. 이 반면

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

이되지 않습니다 :

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

가 (물론 당신이 특정에 대한 "".equals(text)을 할 수 text가 null의 경우의 차이의 예로서

이 코드는 잘 될 것입니다 예 - 원리를 설명하려고합니다.)

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

나는'negativeValue = defaultStock <0 ||을 선호한다고 생각한다. defaultWholesale <0' 외에도 여기에 진행되는 모든 복싱과 배치의 비효율을 제외하고는 코드가 실제로 의미하는 바를 거의 쉽게 이해할 수 없습니다. –

+0

그는 4 개 이상의 매개 변수를 가지고 있으며 기준은 모두 동일합니다. 그런 다음 솔루션이 마음에 들지만 가독성을 위해 여러 줄로 구분합니다 (예 : List 만들기, minvalue 찾기, minvalue와 0 비교). – Roman

+0

많은 수의 비교에 유용합니다. 이 경우 명확함의 감소가 타이핑 등의 절약에 가치가 없다고 생각합니다. –

1

하나의 진술 만있을 수 있습니다. 만 덜 필수적이 샘플 코드처럼 거의 정확하게 읽고 여러 줄에 걸쳐 표현 : 간단한 표현을 위해

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

, 그것은 암시 적 분기를 사용하여 그 의미를 비교하고 피한다하더라도 때문에 ||보다 더 빠를 수 있습니다 |를 사용하여 그것은 여러 번 더 비쌀 수 있습니다.

+0

원래 질문에서 언급했듯이 "비교 문자열은 길었고 읽기가 어려웠습니다. 그래서 나는 가독성을 위해 그것을 깨었다. " 그건 그렇고,이 경우 나는이 특정 코드를 작동시키는 것보다 | =의 행동을 배우는 것에 더 관심이 있습니다. –

1

Guava 라이브러리에는 Predicate과 같은 멋진 구문이 있고/또는 Predicate의 단락 회로 평가가 있습니다.

기본적으로 비교는 개체로 변환되고 컬렉션으로 패키징 된 다음 반복됩니다. For 또는 술어의 경우 첫 번째 true 히트는 반복에서 반환되고 그 반대도 마찬가지입니다.

0

|| 논리 부울 OR
| 비트 OR

| = 비트 포함 OR와 대입 연산자

이유 | = 그것은 비트를 수행 또는 논리적하지 OR 때문이다 shortcircit하지 않습니다. 그 말을하는 것입니다 :

 

C |= 2 is same as C = C | 2 

Tutorial for java operators

+0

부울과 비트 OR이 없습니다! 연산자'|'는 비트 연산 OR **이지만 ** 논리 OR입니다 - [Java 언어 사양 15.22.2] (http://docs.oracle.com/javase/specs/jls/se7/html/)을 참조하십시오. jls-15.html # jls-15.22.2 "JLS 15.22.2") –

+0

단일 비트 (부울 값) 비트와 논리 OR이 동일하기 때문에 정확합니다. 실제적으로 결과는 동일합니다. – oneklc

1

은 분리의 개념은 테스트 로직의 데이터를 테스트 내가있어 가독성에 관한합니다.코드 샘플 :

// 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; 
} 

코드가 더 자세하게 보이며 자명합니다. 그것은 '비교 문자열'보다 더 읽을 수있어

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

, 또한 (배열 할당 및 메서드 호출의 비용으로) 단락의 성능 이점이있다 : 당신은이 같은 메소드 호출의 배열을 만들 수 있습니다.

편집 : 더욱 가독성이 단순히 가변 인자 매개 변수를 사용하여 달성 할 수는 :

boolean checkIfAnyNegative(DataType ... data) 

그리고 호출은 다음과 같을 수 있습니다 :

방법 서명이 될 것

checkIfAnyNegative(defaultStock, defaultWholesale, defaultRetail, defaultDelivery); 
+1

배열 할당과 메서드 호출은 비교에서 비싼 연산을하지 않는 한 단락에 매우 큰 비용입니다 (질문의 예는 저렴합니다). 그렇지만, 대부분의 경우 코드의 유지 보수성이 성능 고려 사항보다 우선합니다. 다른 곳에서 다르게 비교를하거나 4 가지 이상의 값을 비교하는 경우 아마 이런 식으로 사용할 것입니다. 그러나 한 가지 경우에 대해서는 내 취향에 다소 장황합니다. –

+0

@DavidMason 동의합니다. 그러나 대부분의 최신 계산기는 수 밀리미터 이내에 이런 종류의 오버 헤드를 삼킨다는 것을 명심하십시오. 개인적으로는 성능 문제가 발생할 때까지 오버 헤드를 신경 쓰지 않습니다. [http://en.wikipedia.org/wiki/Program_optimization#When_to_optimize]. 또한 코드 길쌈 성은 장점이며 특히 javadoc이 JAutodoc에 의해 제공되거나 생성되지 않은 경우 이점이 있습니다. –