web-dev-qa-db-ja.com

Javaのショートカット "or-assignment"(| =)演算子

Javaで行う比較の長いセットがあり、それらの1つ以上が真であるかどうかを知りたいです。比較の文字列は長くて読みにくいため、読みやすくするために分割し、自動的にショートカット演算子|= のではなく negativeValue = negativeValue || boolean

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

Default <something>値のいずれかが負の場合、negativeValueがtrueになることを期待しています。これは有効ですか?私が期待することはできますか? Sunのサイトやstackoverflowでは言及されていませんでしたが、Eclipseには問題がなく、コードがコンパイルされて実行されているようです。


同様に、複数の論理的交差を実行したい場合は、&= の代わりに &&

83
David Mason

|=は、ブール論理演算子|JLS 15.22.2 )の複合代入演算子( JLS 15.26.2 )です。条件付きまたは||JLS 15.24 )と混同しないでください。ブール論理&=^=の複合割り当てバージョンにそれぞれ対応する&^もあります。

つまり、boolean b1, b2の場合、これら2つは同等です。

 b1 |= b2;
 b1 = b1 | b2;

論理演算子(&|)の対応する条件(&&||)との違いは、前者が「短絡」しないことです。後者は行います。あれは:

  • &および|alwaysは両方のオペランドを評価します
  • &&および||は、右側のオペランドを条件付きで評価します;右側のオペランドは、その値がバイナリ演算の結果に影響を与える可能性がある場合にのみ評価されます。これは、次の場合に右オペランドが評価されないことを意味します。
    • &&の左オペランドは、false に評価されます。
      • (正しいオペランドの評価に関係なく、式全体はfalseです)
    • ||の左オペランドは、true に評価されます。
      • (正しいオペランドの評価に関係なく、式全体はtrueです)

元の質問に戻ります。はい、その構成は有効です。|==および||のショートカットとまったく同じではありませんが、必要なものを計算します。使用法の|=演算子の右側は単純な整数比較演算であるため、|が短絡しないという事実は重要ではありません。

短絡が必要な場合や必要な場合もありますが、シナリオはそれらの1つではありません。

他のいくつかの言語とは異なり、Javaには&&=||=がありません。これは質問- なぜJavaには、条件付きANDおよび条件付きOR演算子の複合割り当てバージョンがありませんか?(&& =、 ))==

194

||のように「ショートカット」(または短絡)演算子ではありませんおよび&&は(LHSに基づいた結果を既に知っている場合、RHSを評価しないという点で)ですが、workingに関して望みのことを行います。

違いの例として、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)を行うことができます-私は単に原理を実証しようとしています。)

16
Jon Skeet

ステートメントを1つだけ持つことができます。複数行にわたって表現されているため、サンプルコードとほぼ同じように読み取れます。

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

最も単純な式では、|を使用すると||よりも高速になります。比較を行わなくても、暗黙的にブランチを使用することを意味し、何倍も高価になる可能性があるためです。

3
Peter Lawrey

あなたの問題にとってはやり過ぎかもしれませんが、 Guava ライブラリにはPredicatesを使用したNice構文があり、またはPredicatesの短絡評価を行います。

基本的に、比較はオブジェクトに変換され、コレクションにパッケージ化された後、繰り返されます。 or述語の場合、最初の真のヒットは反復から返されます。

1
Carl

これは古い記事ですが、初心者に異なる視点を提供するために、例を挙げたいと思います。

同様の複合演算子の最も一般的なユースケースは+=。私たちは皆このようなものを書いたと確信しています:

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

これのポイントは何でしたか?要点は、定型文を避け、繰り返しコードを排除することでした。

したがって、次の行はまったく同じことを行い、変数b1同じ行で2回。

b1 |= b2;
1
oxyt

読みやすさについてであれば、テストロジックから分離テストデータの概念があります。コードサンプル:

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

||論理ブールOR
|ビット単位のOR

| =ビット単位の包括的ORおよび代入演算子

| =がショートサーキットを行わない理由は、ビット単位のORではなく論理ORを行うためです。つまり、

 
 C | = 2はC = C |と同じです。 2 
 

Java演算子)のチュートリアル

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