Java에 조건부 및 조건부 또는 연산자의 복합 할당 버전이없는 이유는 무엇입니까? (&& =, || =)


82

그래서 논리 값이 이진 사업자, 자바가 &, |, ^, &&||.

여기에서 그들이하는 일을 간단히 요약 해 보겠습니다.

의 경우 &결과 값은 true두 피연산자 값이 모두 다음 과 같은 경우입니다 true. 그렇지 않으면 결과는 false입니다.

의 경우 |결과 값은 false두 피연산자 값이 모두 다음 과 같은 경우입니다 false. 그렇지 않으면 결과는 true입니다.

의 경우 ^결과 값은 true피연산자 값이 다른 경우입니다. 그렇지 않으면 결과는 false입니다.

&&연산자 비슷 &하지만 좌측의 값이 피연산자는 우측 피연산자 만 평가한다 true.

||연산자 비슷 |하지만, 그 좌측의 값이 피연산자는 우측 피연산자 만 평가한다 false.

자, 모두 5 중, 그 중 3, 즉 화합물 할당 버전을 가지고 |=, &=하고 ^=. 내 질문은 분명하다 그래서 왜 자바는 제공하지 않습니다 &&=||=뿐만 아니라? 나는 그보다 내가 필요한 것보다 필요한 것을 발견 &=하고 |=.

그리고 Java가 .NET을 가지고 있기 때문에 "너무 길기 때문에"가 좋은 대답이라고 생각하지 않습니다 >>>=. 이 누락에 대한 더 나은 이유가있을 것입니다.


15.26 할당 연산자 부터 :

12 개의 할당 연산자가 있습니다. [...]= *= /= %= += -= <<= >>= >>>= &= ^= |=


&&=||=구현 된 경우 오른쪽을 먼저 평가하지 않는 유일한 연산자라는 의견이 작성 되었습니다. 복합 할당 연산자가 오른쪽을 먼저 평가한다는이 개념은 실수라고 생각합니다.

가입일 15.26.2 화합물 할당 연산자 :

형태의 복합 대입 식을 E1 op= E2동등 E1 = (T)((E1) op (E2))여기서 T의 타입 E1즉 제외 E1한번만 평가된다.

증거로 다음 스 니펫 NullPointerExceptionArrayIndexOutOfBoundsException.

    int[] a = null;
    int[] b = {};
    a[0] += b[-1];

2
나는 두 번째로 가고, 아무도 신경 쓰지 않는다. : P 또한 '왜 기능 x가 언어 y가 아닌가?'에 대한이 모든 질문 언어의 디자이너에게 질문해야한다,하지 우리에게 : P
페데리코 정보 Klez Culloca

1
& =는 무엇을 의미합니까? 누군가 나에게 말할 수 있습니까?
Tarik

@Aaron : a = a & b. 그것은 질문에 쓰여졌습니다
Federico klez Culloca


1
@jleedev : 그 질문은 오래되었지만 더 많은 투표와 수신 링크가 있습니다. 병합이 있으면 이전 항목을이 항목에 병합합니다 (예, 가능합니다).
polygenelubricants 2010 년

답변:


27

이유

대부분의 개발자에게 이러한 연산자는 다음과 같기 때문에 연산자 &&=Java||= 에서는 사용할 수 없습니다 .

  • 발생하기 쉬운 오류
  • 쓸모없는

&&=

Java가 &&=연산자를 허용하면 해당 코드는 다음과 같습니다.

bool isOk = true; //becomes false when at least a function returns false
isOK &&= f1();
isOK &&= f2(); //we may expect f2() is called whatever the f1() returned value

다음과 동일합니다.

bool isOk = true;
if (isOK) isOk = f1();
if (isOK) isOk = f2(); //f2() is called only when f1() returns true

이 첫 번째 코드는 많은 개발자 가 항상 f1 () 반환 값이 무엇이든 호출 된다고 생각 하기 때문에 오류가 발생 하기 쉽습니다f2() . 반환 할 때만 호출 bool isOk = f1() && f2();되는 곳 과 같습니다 .f2()f1()true

개발자가 f2()f1()반환 할 때만 호출 되기를 원하는 경우 true위의 두 번째 코드는 오류가 덜 발생합니다.

Else &=는 개발자가 f2()항상 호출 되기를 원하기 때문에 충분합니다 .

같은 예이지만 &=

bool isOk = true;
isOK &= f1();
isOK &= f2(); //f2() always called whatever the f1() returned value

또한 JVM은 위의 코드를 다음과 같이 실행해야합니다.

bool isOk = true;
if (!f1())  isOk = false;
if (!f2())  isOk = false;  //f2() always called

비교 &&&결과

연산자의 결과인가 &&&부울 값을 적용 할 때 같은?

다음 Java 코드를 사용하여 확인해 보겠습니다.

public class qalcdo {

    public static void main (String[] args) {
        test (true,  true);
        test (true,  false);
        test (false, false);
        test (false, true);
    }

    private static void test (boolean a, boolean b) {
        System.out.println (counter++ +  ") a=" + a + " and b=" + b);
        System.out.println ("a && b = " + (a && b));
        System.out.println ("a & b = "  + (a & b));
        System.out.println ("======================");
    }

    private static int counter = 1;
}

산출:

1) a=true and b=true
a && b = true
a & b = true
======================
2) a=true and b=false
a && b = false
a & b = false
======================
3) a=false and b=false
a && b = false
a & b = false
======================
4) a=false and b=true
a && b = false
a & b = false
======================

따라서 YES 우리는 대체 할 수 있습니다 &&에 의해 &부울 값 ;-)

그래서 더 나은 사용하는 &=대신 &&=.

동일 ||=

와 같은 이유 &&=:
연산자 |=||=.

개발자가 반환 f2()할 때 호출되지 않도록 하려면 다음 대안을 조언합니다.f1()true

// here a comment is required to explain that 
// f2() is not called when f1() returns false, and so on...
bool isOk = f1() || f2() || f3() || f4();

또는:

// here the following comments are not required 
// (the code is enough understandable)
bool isOk = false;
if (!isOK) isOk = f1();
if (!isOK) isOk = f2(); //f2() is not called when f1() returns false
if (!isOK) isOk = f3(); //f3() is not called when f1() or f2() return false
if (!isOK) isOk = f4(); //f4() is not called when ...

1
안녕하세요 @StriplingWarrior. 저는 최고의 Java 전문가 인 제 동료 Yannick에게 확인했습니다. 그 점을 확인하는 데 사용되는 Java 코드 소스를 사용하여 답변을 업데이트했습니다. 당신이 말했듯이 &&&같은 결과를 제공합니다. 의견을 보내 주셔서 감사합니다. 내 대답이 마음에 드십니까? 건배.
oHo

2
이 작업을 매우 빠르게 수행하려면 어떻게해야합니까? && = 당신은 사용해야 빠른 및보다 것 =이 존재한다면, 그래서 if (a) a = b속도
adventurerOK

안녕하세요 @adventurerOK. 죄송합니다. 무슨 뜻인지 잘 모르겠습니다 ... CPU 레지스터에 저장된 값을 사용할 a&=b;때보 if(a) a=b;다 빠르다고 생각 합니다. 그러나 b외부 메모리 (캐시되지 않음)에 if(a) a=b;있으면 더 빠릅니다. 그게 무슨 뜻입니까? 더 많은 예제 코드를 제공 해주세요 ;-) 귀하의 의견이 궁금합니다. 뵙겠습니다. 건배
거봉

12
나는 당신이 "그리고 이것은 우리가 원하는 것이 아니다"라고 말할 때 동의하지 않습니다. 내가 글을 쓰면 isOK &&= f2();단락처럼 단락되기를 원할 것 &&입니다.
Tor Klingberg 2013-06-04

3
운영자가 오류가 발생하기 쉬우거나 쓸모 없다는 귀하의 주장에 동의하지 않습니다. 복합 할당을 사용하는 것은 일반적인 작업에 대한 지름길을 사용하기 위해 수행하는 작업 A = A op B이므로 모든 사람이 자신이하는 일을 완벽하게 알고 영향을 직접 처리 할 수 ​​있습니다. 귀하의 이유가 실제로 부재의 원인이라면 원치 않는 후원으로 볼 것입니다. 하지만 그 대사를 추가 해주셔서 감사하고 싶습니다. bool isOk = f1() || f2() || f3() || f4();그게 제가 제 자신을보기 위해 눈이 멀었 기 때문입니다.
Franz B.

16

아마도 뭔가

x = false;
x &&= someComplexExpression();

할당 x하고 평가 해야하는 것처럼 보이지만someComplexExpression() 평가가의 값에 달려 있다는 사실 x은 구문에서 명확하지 않습니다.

또한 Java의 구문은 C를 기반으로하기 때문에 아무도 이러한 연산자를 추가해야하는 절박한 필요성을 느끼지 못했습니다. 어쨌든 if 문을 사용하는 것이 더 나을 것입니다.


37
하나는 그 주장 할 수 있기 때문에,이 좋은 답변 아니라고 생각 x() && y() 외모 는 표현의 양쪽을 평가한다고처럼. 분명히 사람들은 그것이 &&단락 이라는 것을 받아들이 기 때문에 또한 따라야 &&=합니다.
polygenelubricants 2010

2
@jleedev, 동의했습니다. 나는 이러한 상황에서 이것이 x = x && someComplexExpression ()과 동등하지 않지만 x = someComplexExpression () && x와 동등하다는 것을 기억하는 것이 중요하다고 생각합니다. 오른쪽은 다른 모든 할당 연산자와 일치하도록 먼저 평가되어야합니다. 그리고 그것이 주어지면 && =는 & =와 다른 동작을하지 않을 것입니다.
PSpeed

@polygene 공평합니다. 어떻게 보이는지는 당신이 익숙한 것에 기반을두고 있으며 새로운 것을 추가하고 싶지 않은 것 같습니다. C / C ++ / Java / C #에 대해 제가 좋아하는 한 가지는 표현식의 기본 구문이 거의 동일하다는 것입니다.
Josh Lee

1
@PSpeed, 당신은 착각합니다. JLS는 복합 할당이 수행해야하는 작업에 대해 매우 명확합니다. 위의 추가 사항을 참조하십시오.
polygenelubricants 2010

1
@PSpeed :이 경우, a -= b;완전히 다른 방식으로 작동합니다 a &&= b;.
David Thornley

10

Java에서는 이런 방식입니다. C에서는 이런 방식이기 때문입니다.

이제 C에서 왜 그렇게 되는가에 대한 질문은 &와 &&가 다른 연산자가되었을 때 (때로는 B에서 C의 하강 이전에) & = 다양한 연산자를 간과했기 때문입니다.

그러나 내 대답의 두 번째 부분에는이를 뒷받침 할 출처가 없습니다.


1
재미있는 측면에서-질문은 최근 C 포럼에서 요청되었습니다. 그리고이 대답은 연결되었습니다 (중복으로 표시되지는 않았지만) 순환 인수를 완료합니다!
UKMonkey

5

Java 구문은 C (또는 적어도 C 계열)를 기반으로하고 C에서 이러한 모든 할당 연산자는 단일 레지스터의 산술 또는 비트 어셈블리 명령어로 컴파일되기 때문입니다. 할당 연산자 버전은 임시를 피하고 초기 비 최적화 컴파일러에서 더 효율적인 코드를 생성했을 수 있습니다. 논리 연산자 (C로 표시됨) 등가물 ( &&=||=)은 단일 어셈블리 명령에 대한 명백한 대응이 없습니다. 일반적으로 테스트 및 분기 명령 시퀀스로 확장됩니다.

흥미롭게도, 루비 같은 언어는 않습니다 및 && = || 있습니다.

편집 : Java와 C의 용어가 다릅니다.


조건부 연산자 등가물에는 그러한 명백한 대응이 없다는 것을 의미한다고 생각합니다 . JLS 용어에서 부울 논리 연산자는 &, |^;입니다. &&그리고 ||조건 연산자입니다.
polygenelubricants 2010

C 용어로 && 및 || ISO 9899 : 1999의 "논리 연산자", s6.5.13-14입니다. 비트 연산자는 단일 비트 (자바에서는 부울)에 적용될 때만 "논리적"입니다. C에는 단일 비트 유형이 없으며 논리 연산자는 모든 스칼라 유형에 적용됩니다.
p00ya 2010

C99 이전에는 C에 bool유형 이 없었습니다 . 그것은 bool이없는 언어 역사상 20 년입니다. 가질 이유가 없었습니다 &&=. 비트 연산으로 충분했습니다.
v.oddou

4

Java의 원래 목표 중 하나는 "단순하고 객체 지향적이며 친숙한"것이 었습니다. 이 경우에 적용하면 & =는 익숙합니다 (C, C ++는이 두 가지를 알고있는 사람에게 친숙 함을 의미하며이 컨텍스트에서 익숙 함을 의미합니다).

&& =는 익숙하지 않을 것이며, 언어 설계자들이 언어에 추가 할 수있는 모든 연산자를 생각하지 않기 때문에 간단하지 않을 것입니다. 따라서 추가 연산자가 덜 간단합니다.


3

부울 변수의 경우 && 및 || & 및 | 동안 단락 평가를 사용합니다. 그렇지 않으면 && = 및 || =도 단락 평가를 사용할 것으로 예상됩니다. 이에 대한 좋은 사용 사례가 있습니다. 특히 루프를 반복하는 경우 빠르고 효율적이며 간결해야합니다.

쓰는 대신

foreach(item in coll)
{
   bVal = bVal || fn(item); // not so elegant
}

나는 쓰고 싶다

foreach(item in coll)
{
  bVal ||= fn(item);    // elegant
}

bVal이 참이면 나머지 반복에 대해 fn ()이 호출되지 않습니다.


1
그 루프를 위해 당신은 아마하고 싶을 것 if (fn(item)) { bVal = true; break; }입니다.
Radiodef

2

' &'와 ' &&'는 같지 않습니다. ' &&'는 첫 번째 피연산자가 거짓이면 수행하지 않는 바로 가기 연산이며 ' &'는 어쨌든 수행합니다 (숫자 및 부울 모두에서 작동).

나는 존재하는 것이 더 합리적이라는 데 동의하지만 그것이 존재하지 않아도 그렇게 나쁘지는 않습니다. C가 가지고 있지 않기 때문에 거기에 없었던 것 같아요.

정말 이유를 생각할 수 없습니다.


0

Ruby에서 허용됩니다.

짐작하면 자주 사용하지 않아 구현되지 않았다고 말할 수 있습니다. 또 다른 설명은 파서가 = 앞의 문자 만 본다는 것입니다.


1
Java는 << =, >> = 및 >>> =를 지원하므로 엄격히 사실이 아닙니다.
Yishai

진실. 나는 그것들을 생각하지 않았다. 유일한 설명은 얼마나 자주 사용되는지입니다.
zzawaideh

0

'정말 못 생겼어!'보다 더 좋은 이유는 생각 나지 않습니다.


9
하지만 C / Java는 결코 아름답 지 않았습니다.
EFraim

1
나는 간신히 &&=못생긴 것으로 간주 합니다
asgs

0

&

두 피연산자를 확인하며 비트 연산자입니다. Java는 정수 유형, long, int, short, char 및 byte에 적용될 수있는 여러 비트 연산자를 정의합니다.

&&

결과가 거짓이기 때문에 첫 번째 피연산자가 거짓으로 평가되면 평가를 중지합니다. 이는 논리 연산자입니다. 부울에 적용 할 수 있습니다.

&& 연산자는 & 연산자와 비슷하지만 코드를 좀 더 효율적으로 만들 수 있습니다. 전체 표현식이 참이 되려면 & 연산자로 비교되는 두 표현식이 모두 참이어야하므로 첫 번째 표현식이 거짓을 반환하면 두 번째 표현식을 평가할 이유가 없습니다. & 연산자는 항상 두 표현식을 모두 평가합니다. && 연산자는 첫 번째 표현식이 참인 경우에만 두 번째 표현식을 평가합니다.

&& = 할당 연산자가 있다고해서 언어에 새로운 기능이 추가되는 것은 아닙니다. 비트 연산자의 산술은 훨씬 더 표현력이 뛰어나며 부울 산술을 포함하는 정수 비트 산술을 수행 할 수 있습니다. 논리 연산자는 단순히 부울 산술을 수행 할 수 있습니다.


0

Brian Goetz (Oracle의 Java Language Architect) 다음과 같이 썼습니다 .

https://stackoverflow.com/q/2324549/ [이 질문] 은 이러한 연산자에 관심이 있고 아직 존재하지 않는 이유에 대한 명확한 주장이 없음을 보여줍니다. 따라서 질문은 다음과 같습니다. JDK 팀이 과거에 이러한 연산자를 추가하는 것에 대해 논의 했습니까? 그렇다면 이러한 연산자를 추가하는 이유는 무엇입니까?

이 특정 문제에 대한 구체적인 논의는 알지 못하지만 누군가 제안한다면 대답은 아마도 불합리한 요청은 아니지만 무게를 지탱하지 못합니다.

"무게 운반"은 비용과 이점, 그리고 다른 후보 기능과 비교 한 비용-편익 비율로 판단해야합니다.

비용이 거의 제로에 가깝고 이익이 제로보다 크다고 ( "이자가있다"라는 표현으로) 암시 적으로 가정하고 있다고 생각하므로 명백한 승리로 보입니다. 그러나 이것은 비용에 대한 잘못된 이해를 의미합니다. 이와 같은 기능은 언어 사양, 구현, JCK, 모든 IDE 및 Java 교과서에 영향을줍니다. 사소한 언어 기능이 없습니다. 그리고 이점은 0이 아니지만 매우 작습니다.

두 번째로, 우리가 할 수 있는 기능은 무한히 많지만 몇 년에 한 번 씩만 수행 할 있는 능력이 있습니다 (사용자는 새로운 기능을 흡수 할 수있는 능력이 제한되어 있습니다). 따라서 우리가 선택할 수있는 기능은 매우주의해야합니다. 각 기능 (사소 해 보이는 기능이라도)은이 예산의 일부를 소비하고 항상 다른 기능에서 빼앗습니다.
그것은 "왜이 기능이 아닌가?"가 아니라 "우리가이 기능을 수행 할 수 있도록 어떤 다른 기능을 수행하지 않을 것입니까 (또는 지연시킬 것입니까). 이것이 좋은 거래입니까?" 그리고 저는 이것이 우리가 작업하고있는 다른 것에 대한 좋은 거래라고 정말로 상상할 수 없습니다.

따라서 "끔찍한 아이디어가 아님"(이미 꽤 훌륭하고 많은 기능 요청이이를 명확하지 않음)의 기준을 제거하지만 "진화 예산을 더 잘 사용하는 것"이라는 기준을 제거 할 가능성은 거의없는 것 같습니다. 무엇보다. "


-1

a & b와 a && b는 같은 것이 아닙니다.

a && b는 부울을 반환하는 부울 식이고 a & b는 int를 반환하는 비트 식입니다 (a 및 b가 int 인 경우).

똑같다고 생각하십니까?


1
a & b는 a와 달리 && b는 항상 b를 평가해야합니다.
Daniel Brückner
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.