Java의 바로 가기 "또는 할당"(| =) 연산자


89

Java에서 수행 할 긴 비교 세트가 있으며 그중 하나 이상이 사실로 나오는지 알고 싶습니다. 비교 문자열이 길고 읽기 어려웠 기 때문에 가독성을 위해 분리했고 자동으로 . |=대신 단축키 연산자를 사용했습니다 negativeValue = negativeValue || boolean.

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

negativeValuedefault <something> 값이 음수이면 true가 될 것으로 예상 합니다. 이것이 유효합니까? 내가 기대하는대로 작동할까요? Sun의 사이트 또는 stackoverflow에서 언급 된 것을 볼 수 없었지만 Eclipse에는 문제가없는 것 같고 코드가 컴파일되고 실행됩니다.


마찬가지로 여러 논리적 교차를 수행하려면 &=대신 &&?를 사용할 수 있습니다 .


13
해보지 그래?
Roman

이것은 Java만이 아닌 일반적인 부울 논리입니다. 다른 곳에서도 찾아 볼 수 있습니다. 그리고 그냥 해보지 그래?
Dykam

16
@Dykam : 아니요, 여기에 특정 동작이 있습니다. Java 는 LHS가 이미 참인 경우 RHS를 평가하지 않도록 | = 단락을 만들 있지만 그렇지 않습니다.
Jon Skeet

2
@Jon Skeet : 단락은 존재하지 않는 ||=연산자에 적합하지만 |=비트 또는 연산자의 조합 형식입니다.
David Thornley

1
@ 존 스키트 : 물론,하지만 만들기 |=때문에 단락은, 다른 복합 할당 연산자와 일치하지 않는 것 a |= b;과 동일하지 않을 것이라고 a = a | b;평가에 대한 일반적인주의로, a(이 중요한 경우)를 두 번 누릅니다. 큰 언어 행동 결정이없는 ||=것 같아서 요점을 놓치고 있습니다.
David Thornley

답변:


204

|=복합 할당 연산자이다 ( JLS 15.26.2 부울 논리 연산자) |( JLS 15.22.2 ); conditional-or ||( JLS 15.24 ) 와 혼동하지 마십시오 . 또한 거기 &=^=논리적 부울의 화합물 할당 버전에 대응 &하고 ^, 각각.

즉,의 boolean b1, b2경우이 두 가지는 동일합니다.

 b1 |= b2;
 b1 = b1 | b2;

논리 연산자의 차이 ( &|그 조건 대응 (비교) &&과는 ||) 전자는 "단락"을하지 않는 것입니다; 후자는합니다. 그건:

  • &그리고 | 항상 두 피연산자를 평가
  • &&그리고 ||우측 피연산자를 평가 조건부 ; 오른쪽 피연산자는 해당 값이 이진 연산의 결과에 영향을 미칠 수있는 경우에만 평가됩니다. 즉, 다음과 같은 경우 오른쪽 피연산자가 평가되지 않습니다.
    • 의 왼쪽 피연산자는 다음과 같이 &&평가됩니다.false
      • (오른쪽 피연산자가 무엇으로 평가 되든 전체 표현식이이므로 false)
    • 의 왼쪽 피연산자는 다음과 같이 ||평가됩니다.true
      • (오른쪽 피연산자가 무엇으로 평가 되든 전체 표현식이이므로 true)

그래서 원래의 질문으로 돌아가서, 예, 그 구조는 유효하며 |==||에 대한 바로 가기는 아니지만 원하는 것을 계산합니다. |=사용 하는 연산자 의 오른쪽 은 간단한 정수 비교 연산이므로 |단락되지 않는 사실 은 중요하지 않습니다.

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

다른 언어와 달리 Java에는 &&=||=. 이것은 왜 Java에 conditional-and and conditional-or 연산자의 복합 할당 버전이 없습니까? 라는 질문에서 논의되었습니다 . (&& =, || =) .


+1, 매우 철저합니다. RHS에 부작용이 없다고 판단 할 수 있다면 컴파일러가 단락 연산자로 변환 할 수있을 것입니다. 그것에 대한 단서가 있습니까?
Carl

RHS가 사소하고 SC가 필요하지 않을 때 "스마트 한"SC 운영자는 실제로 약간 느립니다. 사실이라면 일부 컴파일러가 특정 상황에서 SC를 NSC로 변환 할 수 있는지 궁금해하는 것이 더 흥미 롭습니다.
polygenelubricants

@polygenelubricants 단락 연산자는 내부적으로 일종의 분기를 포함하므로 연산자와 함께 사용되는 진리 값에 대한 분기 예측 친화적 패턴이 없거나 사용중인 아키텍처에 좋은 분기 예측이없는 경우 ( 컴파일러 및 / 또는 가상 머신이 자체적으로 관련 최적화를 수행하지 않는다고 가정하면 SC 운영자는 비 단락에 비해 약간의 속도가 느려집니다. 컴파일러에서 무엇이든하는 가장 좋은 방법은 SC 대 NSC를 사용하여 프로그램을 컴파일 한 다음 바이트 코드를 비교하여 다른지 확인하는 것입니다.
JAB

또한, 비트 OR 연산자와 혼동되지 |
user253751

16

그런 식으로 "단축"(또는 단락) 연산자가 아닙니다 || &&는 (LHS를 기반으로 한 결과를 이미 알고있는 경우 RHS를 평가하지 않는다는 점에서) 작업 측면에서 원하는 작업을 수행 합니다.

차이점의 예로서이 코드 text는 null이면 괜찮습니다 .

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

그러나 이것은 :

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

(분명히 당신은 "".equals(text)그 특정한 경우에 대해 할 수 있습니다 -나는 단지 원리를 보여주기위한 것입니다.)


3

당신은 단지 하나의 진술을 가질 수 있습니다. 여러 줄로 표현하면 샘플 코드와 거의 똑같이 읽습니다.

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

가장 간단한 표현식의 경우 using 이 비교를 피하더라도 암시 적으로 분기를 사용하는 것을 의미하며 훨씬 더 많은 비용이들 수 있기 때문에 사용 |이 더 빠를 ||수 있습니다.


나는 단지 하나로 시작했지만 원래 질문에서 언급했듯이 "비교 문자열이 길고 읽기가 어려웠 기 때문에 가독성을 위해 분리했다"고 느꼈습니다. 그 외에도이 경우에는이 특정 코드를 작동시키는 것보다 | =의 동작을 배우는 데 더 관심이 있습니다.
David Mason

1

그것은 당신의 문제에 과잉 일 수 있지만, Guava 라이브러리는 Predicates와 함께 멋진 구문을 가지고 있으며 or / and Predicates에 대한 단락 평가를 수행 합니다.

기본적으로 비교는 객체로 변환되고 컬렉션으로 패키징 된 다음 반복됩니다. 또는 술어의 경우 첫 번째 실제 적중이 반복에서 리턴되고 and의 경우 그 반대의 경우도 마찬가지입니다.


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

'비교 문자열'보다 읽기 쉽고 단락 (배열 할당 및 메서드 호출 비용)이라는 성능 이점도 있습니다.

편집 : varargs 매개 변수를 사용하면 더 많은 가독성을 얻을 수 있습니다.

메소드 서명은 다음과 같습니다.

boolean checkIfAnyNegative(DataType ... data)

그리고 호출은 다음과 같이 보일 수 있습니다.

checkIfAnyNegative( defaultStock, defaultWholesale, defaultRetail, defaultDelivery );

1
배열 할당 및 메서드 호출은 비교에서 비용이 많이 드는 작업이없는 한 단락에 대한 꽤 큰 비용입니다 (문제의 예제는 저렴합니다). 하지만 대부분의 경우 코드의 유지 관리 가능성이 성능 고려 사항보다 우선합니다. 여러 장소에서 다르게 비교하거나 4 개 이상의 값을 비교하는 경우 아마도 이와 같은 것을 사용할 것입니다. 그러나 단일 사례의 경우 내 취향에 따라 다소 장황합니다.
David Mason

@DavidMason 동의합니다. 그러나 대부분의 최신 계산기는 이러한 종류의 오버 헤드를 몇 밀리 초 미만으로 삼킬 것입니다. 개인적으로 나는 성능 문제까지 오버 헤드를 걱정하지 않을 합리적인 것으로 보인다 . 또한 코드의 자세한 정보는 특히 javadoc이 JAutodoc에 의해 제공되거나 생성되지 않은 경우 장점입니다.
Krzysztof Jabłoński

1

오래된 게시물이지만 초보자에게 다른 관점을 제공하기 위해 예를 들어보고 싶습니다.

비슷한 복합 연산자의 가장 일반적인 사용 사례는 +=. 나는 우리 모두가 다음과 같이 썼다고 확신합니다.

int a = 10;   // a = 10
a += 5;   // a = 15

이것의 요점은 무엇입니까? 요점은 상용구를 피하고 반복적 인 코드를 제거하는 것이 었습니다.

따라서 다음 줄은 b1동일한 줄에 변수를 두 번 입력하는 것을 피하면서 정확히 동일합니다.

b1 |= b2;

1
특히 이름이 긴 경우 작업 및 운영자 이름에서 실수를 발견하기가 더 어렵습니다. longNameOfAccumulatorAVariable += 5;longNameOfAccumulatorAVariable = longNameOfAccumulatorVVariable + 5;
안드레이

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

내가 선호하는 것 같아요 negativeValue = defaultStock < 0 || defaultWholesale < 0 모든 권투와 포장이 여기에 무슨의 비 효율성에서 제외 등, 내가 무엇 코드는 것 정말 뜻을 이해하는 거의 쉽게 그것을 찾을 수 없습니다.
Jon Skeet

나는 4 개 이상의 매개 변수를 가지고 있으며 기준은 모두 동일하며 내 솔루션이 마음에 들지만 가독성을 위해 여러 줄로 구분합니다 (예 : 목록 생성, 최소값 찾기, 최소값 비교 0). .
Roman

그것은 많은 수의 비교에 유용 해 보입니다. 이 경우에는 내가 명확성의 감소가 입력 등의 절약 가치가 없다 생각
데이비드 메이슨

0

|| 논리 부울 OR
| 비트 OR

| = 비트 포함 OR 및 할당 연산자

| =가 단락되지 않는 이유는 논리 OR이 아닌 비트 OR을 수행하기 때문입니다. 즉 말하자면:

C | = 2는 C = C | 2

자바 연산자를위한 튜토리얼


부울을 사용한 비트 OR이 없습니다! 연산자 |는 정수 비트 OR 이지만 논리 OR 이기도합니다. Java 언어 사양 15.22.2를
user85421

단일 비트 (부울)의 경우 비트 및 논리 OR이 동일하므로 정확합니다. 실제로 결과는 동일합니다.
oneklc 2013 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.