Javaに条件演算子と条件演算子の複合代入バージョンがないのはなぜですか?(&& =、|| =)


82

だから、ブール型の二項演算子のために、Javaがあり&|^&&||

ここで彼らが何をしているのかを簡単に要約しましょう:

の場合&、結果値はtrue、両方のオペランド値がtrue;の場合です。それ以外の場合、結果はfalseです。

の場合|、結果値はfalse、両方のオペランド値がfalse;の場合です。それ以外の場合、結果はtrueです。

の場合^、結果値はtrue、オペランド値が異なる場合です。それ以外の場合、結果はfalseです。

&&オペレータは次のようである&が、その左側の値がオペランドその右側のオペランドた場合にのみ評価されますtrue

||オペレータは次のようである|が、その左側の値がオペランドその右側のオペランドた場合にのみ評価されますfalse

現在、5つすべてのうち、3つには複合代入バージョン、つまり、、|=&=あり^=ます。だから私の質問は明白です:なぜJavaは提供しません&&=||=同様?必要以上に必要だ&=と思います|=

そして、「長すぎるから」というのは良い答えではないと思います。Javaには>>>=。この省略にはもっと良い理由があるに違いありません。


15.26代入演算子から:

12個の代入演算子があります。[...]= *= /= %= += -= <<= >>= >>>= &= ^= |=


&&=||=が実装された場合、最初に右側を評価しないのはそれだけであるというコメントがありました。複合代入演算子が最初に右側を評価するというこの概念は間違いだと思います。

15.26.2複合代入演算子

フォームの複合代入式は、E1 op= E2と同等ですE1 = (T)((E1) op (E2))。ここTで、はのタイプですがE1E1評価されるのは1回だけです。

証拠として、次のスニペットは、NullPointerExceptionではなく、をスローしArrayIndexOutOfBoundsExceptionます。

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

2
私は2番目に行きます、誰も気にしません:Pまた、「なぜ機能xが言語yにないのか?」に関するこれらすべての質問 私たちではなく、言語の設計者に尋ねるべきです:P
Federico klez Culloca 2009年

1
&=はどういう意味ですか?誰か教えてくれませんか?
タリック

@アーロン:a = a&b。それは質問に書かれています
Federico klez Culloca 2009年


1
@jleedev:その質問は古いですが、これにはより多くの投票と受信リンクがあります。マージがある場合は、古いものをこれにマージします(はい、それは可能です)。
polygenelubricants

回答:


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、したがって、上記の2番目のコードはエラーが発生しにくくなります。

&=開発者は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
======================

したがって、はい、交換できます&&によって&ブール値のため;-)

だからより良い使用 &=代わりに勧めし&&=ます。

についても同じ ||=

&&=
演算子と同じ理由|=||=。よりもエラーが発生しにくいです。

開発者が戻ってきた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 2012

2
これを非常に高速に実行したい場合はどうすればよいですか?&& =は、存在する場合は&=よりも高速になるif (a) a = bため、速度を上げるために使用する必要があります
adventurerOK

こんにちは@adventurerOK。申し訳ありませんが、意味がわかりません... CPUレジスタに格納されている値を使用するa&=b;よりも高速だと思いますif(a) a=b;。ただし、bが外部メモリ(キャッシュされていない)にある場合if(a) a=b;は、より高速です。それはどういう意味ですか?より多くのサンプルコードを提供してください;-)私はあなたの意見に興味があります。またね。乾杯
oHo 2012年

12
あなたが「そしてこれは私たちが望んでいることではない」と言うとき、私は同意しません。私が書くなら、私はisOK &&= f2();それがそうであるようにそれを短絡させたいでしょう&&
Tor Klingberg 2013年

3
オペレーターがエラーを起こしやすい、または役に立たないというあなたの主張に同意しません。複合割り当てを使用することは、通常のショートカットを取るために行うことですA = A op B。そのため、誰もが自分が何をしているかを完全に理解しており、その影響を自分で気にすることができます。あなたの理由が本当にその欠如の原因であるならば、私はそれを望まないひいきとして見るでしょう。しかし、それbool isOk = f1() || f2() || f3() || f4();が私が自分自身を見るために盲目にしたものだったので、私は行を追加してくれてありがとうございます。
フランツB.

16

おそらく

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

に割り当ててx評価する必要があるように見えますsomeComplexExpression()が、評価がの値に依存しているという事実xは、構文からは明らかはありません。

また、Javaの構文はCに基づいており、これらの演算子を追加する差し迫った必要性を誰も見ていなかったためです。とにかく、ifステートメントを使用したほうがよいでしょう。


37
これは良い答えではないと思います。なぜなら、表現の両側を評価する必要x() && y() があるように見えるからです。明らかに人々はそれ&&が短絡していることを受け入れているので、それも同様に続くべき&&=です。
polygenelubricants

2
@jleedev、同意しました。これらの状況では、これはx = x && someComplexExpression()と同等ではなく、x = someComplexExpression()&& xと同等であることを覚えておくことが重要だと思います。右側は、他のすべての代入演算子と一致するように最初に評価されます/評価されるべきです。そして、それを考えると、&& =は&=と同じ動作をします。
pSpeed 2010

@polygeneそれは公平です。しかし、何かがどのように見えるかは、あなたが精通していることに基づいており、彼らは新しいものを追加したくなかったと思います。C / C ++ / Java / C#について私が気に入っていることの1つは、式の基本的な構文がほぼ同じであるということです。
Josh Lee

1
@PSpeed、あなたは間違っています。JLSは、複合代入が何をすることになっているのかについて非常に明確です。上記の私の追加を参照してください。
polygenelubricants

1
@PSpeed:その場合、はとa -= b;はまったく異なる動作をしa &&= b;ます。
David Thornley 2010年

10

これは、Javaではこの方法です。Cではこの方法だからです。

ここで、なぜCでそうなるのかという疑問は、&と&&が異なる演算子になると(CがBから降下する前に)、&=のさまざまな演算子が単に見落とされていたためです。

しかし、私の答えの2番目の部分には、それをバックアップするためのソースがありません。


1
面白い面としては、最近Cフォーラムで質問がありました。そして、この答えはリンクされていました(重複とマークされていませんが)これで循環論法が完成します!
UKMonkey

5

主な理由は、Java構文がC(または少なくともCファミリ)に基づいており、Cでは、これらすべての割り当て演算子が単一のレジスタで算術またはビット単位のアセンブリ命令にコンパイルされるためです。代入演算子バージョンは一時的なものを回避し、初期の非最適化コンパイラーでより効率的なコードを生成した可能性があります。論理演算子(Cで呼ばれる)と同等のもの(&&=および||=)は、単一のアセンブリ命令にそれほど明白に対応していません。それらは通常、命令のテストおよび分岐シーケンスに拡張されます。

興味深いことに、ルビーのような言語 ないと&& = = ||持っています。

編集:用語はJavaとCで異なります


条件演算子の同等物には、そのような明白な対応がないことを意味すると思います。JLS用語では、ブール論理演算子であり&|かつ^&&および||は条件演算子です。
polygenelubricants

Cの用語では、&&と|| は「論理演算子」、ISO 9899:1999のs6.5.13-14です。ビット単位の演算子は、単一のビット(Javaではブール値)に適用された場合にのみ「論理的」です。Cにはシングルビット型はなく、そこでの論理演算子はすべてのスカラー型に適用されます。
p00ya 2010

C99以前は、Cにはboolタイプすらありませんでした。これは、ブール値のない言語の歴史の20年です。持つ理由はありませんでした&&=。ビット演算で十分でした。
v.oddou

4

Javaの当初の目的の1つは、「シンプルで、オブジェクト指向で、なじみのある」ことでした。この場合に適用されるように、&=はよく知られています(C、C ++はそれを持っており、このコンテキストでよく知っているということは、これら2つを知っている人によく知られていることを意味します)。

&& =はなじみがなく、言語設計者が言語に追加できるすべての演算子について考えていなかったという意味で単純ではないため、余分な演算子が少ないほど単純です。


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 2015年

2

' &'と ' &&'は' 'と同じではありません ' &&'はショートカット操作であり、 'の間に最初のオペランドがfalseの場合は実行されません& 'はとにかく実行されます(数値とブール値の両方で機能します)。

存在する方が理にかなっていることには同意しますが、存在しなくてもそれほど悪くはありません。Cにはないのでなかったと思います。

本当に理由が思いつかない。


0

Rubyでは許可されています。

推測すると、あまり使われていないので実装されていなかったと思います。別の説明は、パーサーが=の前の文字のみを見るということかもしれません。


1
Javaは<< =、>> =、>>> =をサポートしているため、厳密には当てはまりません。
Yishai

本当。私はそれらについて考えていませんでした。唯一の説明は、それがどれくらいの頻度で使用されるかということだと思います。
zzawaideh 2009年


0

両方のオペランドを検証します。これはビット演算子です。Javaは、整数型、long、int、short、char、およびbyteに適用できるいくつかのビット演算子を定義しています。

&&

結果がfalseになるため、最初のオペランドがfalseと評価された場合、評価を停止します。これは論理演算子です。ブール値に適用できます。

&&演算子は&演算子に似ていますが、コードを少し効率的にすることができます。式全体がtrueになるには、&演算子で比較される両方の式がtrueである必要があるため、最初の式がfalseを返した場合、2番目の式を評価する理由はありません。&演算子は常に両方の式を評価します。&&演算子は、最初の式が真の場合にのみ2番目の式を評価します。

&& =代入演算子を使用しても、言語に新しい機能が実際に追加されるわけではありません。ビット単位の演算子の算術ははるかに表現力があり、ブール代数を含む整数のビット単位の算術を実行できます。論理演算子は単にブール算術を実行できます。


0

Brian Goetz(OracleのJava言語アーキテクト)は次のように書いています。

https://stackoverflow.com/q/2324549/ [この質問]は、これらの演算子を持つことに関心があり、なぜそれらがまだ存在しないのか明確な議論がないことを示しています。したがって、問題は次のとおりです。JDKチームは、過去にこれらの演算子を追加することについて話し合ったことがありますか。もしそうなら、それらを追加する理由はどこにありますか。

私はこの特定の問題に関する具体的な議論を知りませんが、誰かがそれを提案した場合、答えはおそらく次のようになります:それは不合理な要求ではありませんが、その重みはありません。

「その重みを運ぶ」は、そのコストとメリット、および他の候補機能と比較したコストとメリットの比率によって判断する必要があります。

コストはゼロに近く、利益はゼロより大きいと暗黙のうちに想定していると思います(「関心がある」というフレーズによって)ので、それは明らかな勝利のようです。しかし、これはコストの誤った理解に反します。このような機能は、言語仕様、実装、JCK、およびすべてのIDEとJavaの教科書に影響を与えます。些細な言語機能はありません。そして、そのメリットはゼロではありませんが、かなり小さいものです。

第二に、私たちができる機能は無限にありますが、私たちには数年ごとにほんの一握りしか実行できない(そしてユーザーは新しい機能を吸収する能力が限られています)。各機能(些細なように見える機能でも)はこの予算の一部を消費し、常に他の機能からそれを奪います。
これは「なぜこの機能ではないのか」ではなく、「他にどのような機能を実行しない(または遅延させる)ので、これを実行できるのでしょうか。それは良い取引ですか?」そして、これが私たちが取り組んでいる他のものとの良い取引であるとは本当に想像できません。

したがって、「ひどいアイデアではない」という基準をクリアしますが(これはすでにかなり良いですが、多くの機能要求はそれをクリアしていません)、「進化予算のより良い使用」の基準をクリアする可能性は低いようです。何よりも」


-1

a&bとa && bは同じものではありません。

a && bはブール式を返すブール式であり、a&bはintを返すビット単位の式です(aとbがintの場合)。

それらは同じだと思いますか?


1
a&bは、&& bとは異なり、常にbを評価する必要があります。
ダニエルブリュックナー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.