Java Language
演算子
サーチ…
前書き
Javaプログラミング言語の演算子は、1つ、2つ、または3つのオペランドで特定の演算を実行し、結果を返す特殊なシンボルです。
備考
オペレータは 、1つ、2つまたは3つのオペランド上で操作を実行するJavaプログラムを伝えるシンボル(又はシンボル)です。演算子とそのオペランドが式を構成します (式のトピックを参照)。演算子のオペランドは、それ自体が式です。
このトピックでは、Javaで定義された40以上の異なる演算子について説明します。独立した式のトピックでは、
- 演算子、オペランドなどが式にどのように組み合わされているか、
- 式の評価方法、および
- 式の入力、変換、および式の評価の仕組み
文字列連結演算子(+)
+
記号は、Javaの3つの異なる演算子を意味します。
-
+
前にオペランドがない場合は、それは単項プラス演算子です。 - 2つのオペランドがあり、それらが両方とも数値である場合。それはバイナリ加算演算子です。
- 2つのオペランドがあり、それらのうちの少なくとも1つが
String
である場合、それは2進連結演算子です。
単純なケースでは、連結演算子は2つの文字列を結合して3番目の文字列を返します。例えば:
String s1 = "a String";
String s2 = "This is " + s1; // s2 contains "This is a String"
2つのオペランドの1つが文字列でない場合、次のようにString
変換されます。
型がプリミティブ型のオペランドは、boxed値の
toString()
を呼び出すことによって変換されます。型が参照型のオペランドは、オペランドの
toString()
メソッドを呼び出すことによって変換されます。オペランドがnull
場合、またはtoString()
メソッドがnull
返す場合は、代わりに文字列リテラル"null"
が使用されます。
例えば:
int one = 1;
String s3 = "One is " + one; // s3 contains "One is 1"
String s4 = null + " is null"; // s4 contains "null is null"
String s5 = "{1} is " + new int[]{1}; // s5 contains something like
// "{} is [I@xxxxxxxx"
s5
例の説明は、配列型のtoString()
メソッドがjava.lang.Object
から継承され、その動作は型名とオブジェクトのIDハッシュコードからなる文字列を生成することです。
式が定数式の場合を除いて、連結演算子を指定して新しいString
オブジェクトを作成します。後者の場合、式はコンパイル・タイプで評価され、ランタイム値は文字列リテラルと等価です。これは、長い文字列リテラルを次のように分割する際にランタイムオーバーヘッドがないことを意味します。
String typing = "The quick brown fox " +
"jumped over the " +
"lazy dog"; // constant expression
最適化と効率化
上記のように、定数式を除いて、各文字列連結式は新しいString
オブジェクトを作成します。このコードを考えてみましょう:
public String stars(int count) {
String res = "";
for (int i = 0; i < count; i++) {
res = res + "*";
}
return res;
}
上記のメソッドでは、ループの各繰り返しは、以前の繰り返しより1文字長い新しいString
を作成します。各連結は、新しいString
を形成するためにオペランドストリング内のすべての文字をコピーします。したがって、 stars(N)
は:
-
N
新しいString
オブジェクトを作成し、最後のものを除くすべてのオブジェクトをString
ます。 -
N * (N + 1) / 2
文字をコピーし、 - ゴミの
O(N^2)
バイトを生成します。
これは大きなN
に対して非常に高価です。実際、ループ内で文字列を連結するコードでは、この問題が発生する可能性があります。これを書くためのより良い方法は次のようになります:
public String stars(int count) {
// Create a string builder with capacity 'count'
StringBuilder sb = new StringBuilder(count);
for (int i = 0; i < count; i++) {
sb.append("*");
}
return sb.toString();
}
理想的には、容量に設定する必要がありStringBuilder
、これは実用的ではない場合、クラスが自動的にビルダーが文字を保持するために使用する補助配列を成長します。 (注:この実装では、 O(N^2)
ではなくO(N)
に文字のコピー量が保持されます。
このパターンをすべての文字列連結に適用する人もいます。ただし、JLS では Javaコンパイラが単一の式内の文字列連結を最適化できるため、これは不要です。例えば:
String s1 = ...;
String s2 = ...;
String test = "Hello " + s1 + ". Welcome to " + s2 + "\n";
通常 、バイトコードコンパイラによってこのようなものに最適化されます。
StringBuilder tmp = new StringBuilder();
tmp.append("Hello ")
tmp.append(s1 == null ? "null" + s1);
tmp.append("Welcome to ");
tmp.append(s2 == null ? "null" + s2);
tmp.append("\n");
String test = tmp.toString();
(JITコンパイラは、 s1
またはs2
がnull
はならないと推測できる場合には、それをさらに最適化することができます)。しかし、この最適化は単一の式内でのみ可能です。
要するに、文字列連結の効率を心配している場合、
- ループ内で繰り返し連結を行っている場合は、手を最適化してください(または類似したもの)。
- 単一の連結式を手で最適化しないでください。
算術演算子(+、 - 、*、/、%)
Java言語には、整数値と浮動小数点値の算術演算を実行する7つの演算子が用意されています。
-
+
演算子は2つあります。- 2進加算演算子は、1つの数値を別の数値に加算します。 (文字列連結を実行するバイナリ
+
演算子もあります。別の例で説明します)。 - 単項プラス演算子は、数値昇格のトリガーとは別に何もしません(下記参照)
- 2進加算演算子は、1つの数値を別の数値に加算します。 (文字列連結を実行するバイナリ
- 2つのがあります
-
演算子は、- バイナリ減算演算子は、別の数値から1つの数値を減算します。
- 単項マイナス演算子は、そのオペランドをゼロから減算するのと等価です。
- バイナリ乗算演算子(*)は、ある数値を別の数値に乗算します。
- 2進除算演算子(/)は、ある数値を別の数値で除算します。
- バイナリ剰余1演算子(%)は、ある数値を別の数値で割ったときの剰余を計算します。
これはしばしば「モジュラス」演算子と誤って呼ばれます。 「残余」は、JLSによって使用される用語です。 "Modulus"と "remainder"は同じものではありません。
オペランドと結果の型、および数値昇格
演算子は数値オペランドを必要とし、数値結果を生成します。オペランドの型は任意のプリミティブな数値型(つまり、 byte
、 short
、 char
、 int
、 long
、 float
またはdouble
)またはjava.lang
定義された任意の数値ラッパー型です。すなわち、( Byte
、 Character
、 Short
、 Integer
、 Long
、 Float
またはDouble
。
結果の型は、以下のように、オペランドまたはオペランドの型に基づいて決定されます。
- いずれかのオペランドが
double
またはDouble
場合、結果の型はdouble
ます。 - それ以外の場合、どちらかのオペランドが
float
またはFloat
場合、結果の型はfloat
です。 - それ以外の場合、オペランドのいずれかが
long
またはLong
場合、結果の型はlong
です。 - それ以外の場合、結果の型は
int
です。これはbyte
、short
、およびchar
オペランドと `int。
演算の結果の型によって、算術演算の実行方法と、そのオペランドの処理方法が決まります
- 結果の型である場合
double
、オペランドに昇格さdouble
、および動作は、64ビット(倍精度バイナリ)IEE 754浮動小数点演算を用いて行われます。 - 結果の型である場合
float
、オペランドがに昇格されたfloat
、及び動作は、32ビット(単精度バイナリ)IEE 754浮動小数点演算を用いて行われます。 - 結果のタイプがある場合
long
、オペランドに昇格されたlong
、および動作は、64ビットの符号付き2の補数バイナリ整数演算を用いて行われます。 - 結果の型である場合
int
、オペランドに昇格されているint
、および動作は、32ビット符号付き2の補数バイナリ整数演算を用いて行われます。
プロモーションは2つの段階で実行されます。
- オペランド・タイプがラッパー・タイプの場合、オペランド値は対応するプリミティブ・タイプの値にアンボックスされます。
- 必要に応じて、プリミティブ型を必要な型に昇格させます。
- する整数の推進
int
またはlong
ロスレスです。 -
float
double
は無損失です。 - 整数を浮動小数点値に昇格すると、精度が低下する可能性があります。変換は、IEE 768「最も近い丸め」セマンティクスを使用して実行されます。
- する整数の推進
分裂の意味
/演算子は、左側のオペランドn
( 被除数 )と右側のオペランドd
( 除数 )を除算し、結果q
( 商 )を生成します。
Java整数の除算はゼロに向かって丸めます。 JLSセクション15.17.2では、Java整数の振る舞いを次のように指定しています。
オペランド
n
およびd
について生成された商は、|d ⋅ q| ≤ |n|
を満足しながら可能な限り大きさの整数値q
である|d ⋅ q| ≤ |n|
。また、q
ときに正である|n| ≥ |d|
そしてn
及びd
同じ符号を持っていますが、q
負のとき|n| ≥ |d|
n
とd
は反対の符号があります。
特殊なケースが2つあります。
-
n
がMIN_VALUE
で除数が-1の場合、整数オーバーフローが発生し、結果はMIN_VALUE
ます。この場合、例外はスローされません。 -
d
が0の場合、 `ArithmeticExceptionがスローされます。
Javaの浮動小数点除算では、より多くのケースを考慮する必要があります。しかし、基本的な考え方は、結果q
がd . q = n
を満たすのに最も近い値であるということですd . q = n
。
浮動小数点数の除算で例外が発生することはありません。代わりに、ゼロで除算する演算は、INFとNaNの値になります。下記参照。
残余の意味
CおよびC ++とは異なり、Javaの残りの演算子は、整数演算と浮動小数点演算の両方で動作します。
整数の場合についての結果a % b
番号であると定義されるr
ように(a / b) * b + r
に等しく、 a
/
、 *
および+
適切なJava整数演算子です。これは、 b
が0の場合を除いて、すべての場合に適用されます。その場合、剰余はArithmeticException
ます。
これは、上記の定義から、次のa % b
場合のみ負であることができる負であり、場合のみ正で正です。 a
a
また、大きさのa % b
常にの大きさ未満であるb
。
浮動小数点の剰余演算は、整数の場合の一般化です。 a % b
の結果は剰余r
が数学的関係r = a - (b ⋅ q)
で定義されます。ここで、
-
q
は整数であり、 -
a / b
が負の場合にのみ負であり、a / b
が正である場合のみ正であり、 - その大きさは、真の数学的な商の大き超えることなく、可能な限り大きいと
a
b
。
浮動小数点の剰余は、 b
がゼロのときのように、エッジケースでINF
とNaN
値を生成できます。下記参照。例外をスローしません。
重要な注意点:
%
で計算された浮動小数点剰余演算の結果は、IEEE 754で定義された剰余演算によって生成されたものと同じではありません 。IEEE 754剰余は、Math.IEEEremainder
ライブラリメソッドを使用して計算できます。
整数オーバーフロー
Java 32および64ビットの整数値は符号付きで、2の補数の2進表現を使用します。例えば、数値の範囲は、(32ビット)として表現int
1 - 31 -2 +2スルー31。
2つのNビット整数(N = 32または64)を加算、減算、または複数回使用すると、演算結果が大きすぎてNビット整数として表すことができません。この場合、演算は整数オーバーフローにつながり、結果は次のように計算できます。
- 数学的演算は、数全体の中間2の補数表現を与えるために実行される。この表現はNビットより大きい。
- 中間表現の下位32または64ビットが結果として使用されます。
整数オーバーフローはどのような状況でも例外にならないことに注意してください。
浮動小数点のINF値とNAN値
Javaはfloat
とdouble
IEE 754浮動小数点表現を使用します。これらの表記には、実数の範囲外にある値を表すための特殊な値があります。
- 「無限」またはINF値は、大きすぎる数値を示します。
+INF
値は、大きすぎて正の数を示します。-INF
値は、大きすぎて負の数を表します。 - 「不定」/「数ではない」またはNaNは無意味な操作から生じる値を示します。
INF値は、オーバーフローを引き起こす浮動小数点演算、またはゼロ除算によって生成されます。
NaN値は、ゼロをゼロで除算するか、ゼロをゼロで計算することによって生成されます。
驚くべきことに、例外をトリガーせずにINFおよびNaNオペランドを使用して算術演算を実行することは可能です。例えば:
- + INFと有限の値を加えると+ INFが得られます。
- + INFと+ INFを追加すると+ INFが得られます。
- + INFと-INFを追加するとNaNが得られます。
- INFで除算すると、+0.0または-0.0が得られます。
- 1つまたは複数のNaNオペランドを使用するすべての演算でNaNが返されます。
詳細については、 JLS 15の関連するサブセクションを参照してください。これは主に「学術的」であることに注意してください。典型的な計算の場合、 INF
またはNaN
は何かが間違っていることを意味します。たとえば、入力データが不完全であるか間違っているか、計算が誤ってプログラムされているなどです。
等価演算子(==、!=)
==
演算子と!=
演算子は、オペランドが等しいかどうかによってtrue
またはfalse
と評価される2項演算子です。 ==
演算子は、オペランドが等しい場合はtrue
==
、そうでない場合はfalse
ます。 !=
演算子は、オペランドが等しい場合はfalse
返し、それ以外の場合はtrue
返します。
これらの演算子はプリミティブ型と参照型のオペランドで使用できますが、動作は大きく異なります。 JLSによると、これらの演算子には実際には3つの異なるセットがあります。
- Boolean
==
および!=
演算子。 - 数値
==
および!=
演算子。 - 参照
==
および!=
演算子。
ただし、すべての場合において、 ==
および!=
演算子の結果の型はboolean
です。
数値==
および!=
演算子
==
または!=
演算子のオペランドの一方(または両方)がプリミティブな数値型( byte
、 short
、 char
、 int,
long
、 float
またはdouble
)である場合、演算子は数値比較です。 2番目のオペランドは、プリミティブな数値型またはボックス化された数値型のいずれかでなければなりません。
他の数値演算子の動作は次のとおりです。
- オペランドの1つがボックス型であれば、ボックス化されません。
- いずれかのオペランドが
byte
、short
またはchar
場合、int
昇格されます。 - オペランドの型が同じでない場合、「より小さい」型のオペランドは「より大きい」型に昇格される。
- 比較は次のように実行されます。
- プロモートされたオペランドが
int
またはlong
場合、値が一致しているかどうかテストされます。 - プロモートされたオペランドが
float
またはdouble
場合は、次のようになります。- 0の2つのバージョン(
+0.0
と-0.0
)は等しいと-0.0
れます -
NaN
値は何にも等しくないとして扱われます。 - IEEE 754表現が同一であれば、他の値は等しくなります。
- 0の2つのバージョン(
- プロモートされたオペランドが
注意: ==
と!=
を使用して浮動小数点値を比較する場合は注意が必要です。
ブール値==
および!=
演算子
両方のオペランドがboolean
であるか、または一方がboolean
で、他方がBoolean
場合、これらの演算子はブール==
および!=
演算子です。動作は次のとおりです。
- オペランドの1つが
Boolean
場合、ボックスはアンボックスされます。 - ボックス化されていないオペランドがテストされ、ブール結果が次の真理値表に従って計算されます
A | B | A == B | A!= B |
---|---|---|---|
偽 | 偽 | 真実 | 偽 |
偽 | 真実 | 偽 | 真実 |
真実 | 偽 | 偽 | 真実 |
真実 | 真実 | 真実 | 偽 |
真偽値で==
と!=
控えめに使用することをお勧めする2つの「落とし穴」があります:
==
または!=
を使用して2つのBoolean
オブジェクトを比較すると、参照演算子が使用されます。予期しない結果が生じることがあります。 Pitfall:==を使用してIntegerなどのプリミティブラッパーオブジェクトを比較する==
演算子は簡単に=
と間違えることがあります。ほとんどのオペランドタイプでは、このエラーはコンパイルエラーにつながります。しかし、boolean
オペランドとBoolean
オペランドの間違いは、誤ったランタイム動作につながります。 落とし穴を見る- '=='を使ってブール値をテストする
参照==
および!=
演算子
両方のオペランドがオブジェクト参照である場合、 ==
演算子と!=
演算子は、2つのオペランドが同じオブジェクトを参照しているかどうかをテストします 。これはしばしばあなたが望むものではありません。 2つのオブジェクトが同じ値であるかどうかを調べるには、代わりに.equals()
メソッドを使用する必要があります。
String s1 = "We are equal";
String s2 = new String("We are equal");
s1.equals(s2); // true
// WARNING - don't use == or != with String values
s1 == s2; // false
警告: String
値を比較するために==
および!=
を使用すると 、ほとんどの場合正しくありません 。 http://www.riptuit.com/java/example/16290/pitfall--using-to-compare-stringsを参照してください 。同じような問題がプリミティブラッパー型にも当てはまります。 http://www.riptuit.com/java/example/8996/pitfall--using-to-compare-primitive-wrappers-objects-such-as-integerを参照してください 。
NaNのエッジケースについて
JLS 15.21.1は、以下のように述べています。
いずれかのオペランドが
NaN
場合、==
の結果はfalse
が、!=
の結果はtrue
です。実際、テストx != x
あるtrue
の価値場合に限りx
あるNaN
。
この動作は、(ほとんどのプログラマにとって)予期しないものです。 NaN
値がそれ自身と等しいかどうかをテストすると、答えは "いいえ、そうではありません!"です。言い換えれば、 ==
はNaN
値に対して再帰的ではありません。
しかし、これはJavaの「奇妙」ではなく、この動作はIEEE 754浮動小数点標準で規定されており、最新のプログラミング言語で実装されています。 (詳細については、 http ://stackoverflow.com/a/1573715/139985を参照してください ...これは、「決定が下されたときに部屋にいた」人が書いたことに注意してください )
インクリメント/デクリメント演算子(++ / - )
++
および--
演算子を使用して、変数を1ずつインクリメントまたはデクリメントできます。
++
演算子と--
演算子が変数に従うとき、それはポストインクリメントとポストデクリメントと呼ばれます。
int a = 10;
a++; // a now equals 11
a--; // a now equals 10 again
++
と--
演算子が変数の前にあるとき、演算はそれぞれプリ インクリメントとプリデクリメントと呼ばれます。
int x = 10;
--x; // x now equals 9
++x; // x now equals 10
演算子が変数に先行する場合、式の値はインクリメントまたはデクリメントされた後の変数の値です。演算子が変数の後に続く場合、式の値はインクリメントまたはデクリメントされる前の変数の値です。
int x=10;
System.out.println("x=" + x + " x=" + x++ + " x=" + x); // outputs x=10 x=10 x=11
System.out.println("x=" + x + " x=" + ++x + " x=" + x); // outputs x=11 x=12 x=12
System.out.println("x=" + x + " x=" + x-- + " x=" + x); // outputs x=12 x=12 x=11
System.out.println("x=" + x + " x=" + --x + " x=" + x); // outputs x=11 x=10 x=10
ポストインクリメントまたはデクリメントを上書きしないように注意してください。これは、イン/デクリメントされた変数自体に再割り当てされる式の最後にポストイン/デクリメント演算子を使用する場合に発生します。イン/デクリメントは効果を持ちません。左辺の変数が正しくインクリメントされても、その値は式の右辺から前に評価された結果で直ちに上書きされます:
int x = 0;
x = x++ + 1 + x++; // x = 0 + 1 + 1
// do not do this - the last increment has no effect (bug!)
System.out.println(x); // prints 2 (not 3!)
正しい:
int x = 0;
x = x++ + 1 + x; // evaluates to x = 0 + 1 + 1
x++; // adds 1
System.out.println(x); // prints 3
条件付き演算子(?:)
構文
{条件を評価する} ? {ステートメントが実行時にtrue} : {ステートメントが実行時にfalse}
構文に示されているように、条件演算子(三項演算子1とも呼ばれる)は?
(疑問符)と:
コロン)文字を使用して、2つの可能な結果の条件式を有効にします。これは、より長いif-else
ブロックを置き換えて、条件に基づいて2つの値の1つを返すために使用できます。
result = testCondition ? value1 : value2
同等です
if (testCondition) {
result = value1;
} else {
result = value2;
}
「testConditionがtrueの場合は、結果をvalue1に設定します。それ以外の場合は、result2をvalue2に設定します。
例えば:
// get absolute value using conditional operator
a = -10;
int absValue = a < 0 ? -a : a;
System.out.println("abs = " + absValue); // prints "abs = 10"
同等です
// get absolute value using if/else loop
a = -10;
int absValue;
if (a < 0) {
absValue = -a;
} else {
absValue = a;
}
System.out.println("abs = " + absValue); // prints "abs = 10"
一般的な使用法
条件付き代入(ヌルチェックなど)に条件演算子を使用できます。
String x = y != null ? y.toString() : ""; //where y is an object
この例は次のものと同等です。
String x = "";
if (y != null) {
x = y.toString();
}
条件演算子は、上記2番目に低い優先有するので代入演算子を 、そこ条件周り使用括弧の必要はほとんどありませんが、括弧は、他の演算子と組み合わせた場合に構築全体条件演算子の周り必要とされます。
// no parenthesis needed for expressions in the 3 parts
10 <= a && a < 19 ? b * 5 : b * 7
// parenthesis required
7 * (a > 0 ? 2 : 5)
条件演算子のネストは、3番目の部分で行うこともできます.3番目の部分では、チェーン化やswitch文のように動作します。
a ? "a is true" :
b ? "a is false, b is true" :
c ? "a and b are false, c is true" :
"a, b, and c are false"
//Operator precedence can be illustrated with parenthesis:
a ? x : (b ? y : (c ? z : w))
脚注:
1 - Java言語仕様とJavaチュートリアルの両方で( ? :
:)演算子を条件演算子と呼びます。このチュートリアルでは、(現在)Javaで定義されている唯一の三項演算子であるため、「三項演算子」とも呼ばれています。 「条件付き演算子」の用語は、同等の演算子を使用するCおよびC ++および他の言語と一貫しています。
ビット演算子と論理演算子(〜、&、|、^)
Java言語では、整数オペランドまたはブールオペランドに対してビット単位または論理演算を実行する4つの演算子が用意されています。
- 補数(
~
)演算子は、1つのオペランドのビットのビット反転または論理反転を実行する単項演算子です。 JLS 15.15.5を参照してください。 。 - AND(
&
)演算子は、2つのオペランドのビット単位または論理的な "and"を実行する2項演算子です。 JLS 15.22.2を参照してください。 。 - OR(
|
)演算子は2つのオペランドのビット単位または論理的な "包括的または"を実行する2項演算子です。 JLS 15.22.2を参照してください。 。 - XOR(
^
)演算子は、2つのオペランドのビットまたは論理「排他的論理和」を実行する2項演算子です。 JLS 15.22.2を参照してください。 。
オペランドがブール値のときにこれらの演算子によって実行される論理演算は、次のように要約できます。
A | B | 〜A | A&B | | B | A ^ B |
---|---|---|---|---|---|
0 | 0 | 1 | 0 | 0 | 0 |
0 | 1 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 0 | 1 | 1 |
1 | 1 | 0 | 1 | 1 | 0 |
整数オペランドの場合、上記の表は個々のビットについて何が起こるかを記述していることに注意してください。演算子は実際には、32ビットまたは64ビットのオペランドまたはオペランドのすべてを並列に処理します。
オペランドの型と結果の型。
通常の算術変換は、オペランドが整数の場合に適用されます。ビット演算子の一般的な使用例
~
演算子は、ブール値を反転するために、または整数オペランドのすべてのビットを変更するために使用されます。
&
演算子は、整数オペランドのビットの一部を「マスクする」ために使用されます。例えば:
int word = 0b00101010;
int mask = 0b00000011; // Mask for masking out all but the bottom
// two bits of a word
int lowBits = word & mask; // -> 0b00000010
int highBits = word & ~mask; // -> 0b00101000
|
演算子は、2つのオペランドの真理値を結合するために使用されます。例えば:
int word2 = 0b01011111;
// Combine the bottom 2 bits of word1 with the top 30 bits of word2
int combined = (word & mask) | (word2 & ~mask); // -> 0b01011110
^
演算子は、ビットをトグルまたはフリップするために使用されます。
int word3 = 0b00101010;
int word4 = word3 ^ mask; // -> 0b00101001
ビット演算子の使用例については、「 ビット操作 」を参照してください。
オペレータのインスタンス
この演算子は、オブジェクトが特定のクラス/インタフェース型であるかどうかをチェックします。 instanceof演算子は次のように記述されます。
( Object reference variable ) instanceof (class/interface type)
例:
public class Test {
public static void main(String args[]){
String name = "Buyya";
// following will return true since name is type of String
boolean result = name instanceof String;
System.out.println( result );
}
}
これにより、次の結果が得られます。
true
比較されるオブジェクトが右の型と互換性のある代入である場合、この演算子は引き続き真を返します。
例:
class Vehicle {}
public class Car extends Vehicle {
public static void main(String args[]){
Vehicle a = new Car();
boolean result = a instanceof Car;
System.out.println( result );
}
}
これにより、次の結果が得られます。
true
代入演算子(=、+ =、 - =、* =、/ =、%=、<< =、>> =、>>> =、&=、| =および^ =)
これらの演算子の左辺オペランドは、最終変数でも配列の要素でもなければなりません。右手オペランドは左手オペランドと割り当て互換性がなければなりません。これは、型が同じでなければならないか、または右オペランド型が左オペランド型にボクシング、アンボックス化または拡大の組み合わせによって変換可能でなければならないことを意味します。 (詳細については、 JLS 5.2を参照してください)。
「演算と代入」演算子の正確な意味は、 JLS 15.26.2で次のように指定されています。
フォームの複合代入式
E1 op= E2
と等価であるE1 = (T) ((E1) op (E2))
T
タイプであるE1
ことを除いて、E1
一度だけ評価されます。
最終的な割り当ての前に暗黙の型キャストがあることに注意してください。
1. =
単純代入演算子:右手オペランドの値を左手オペランドに代入します。
例:
c = a + b
の値を追加するa + b
値にc
とに割り当てるc
2. +=
"add and assign"演算子:左手オペランドの値に右手オペランドの値を加算し、左手オペランドに結果を代入する。左手オペランドがString
型であれば、これは "連結して代入する"演算子です。
例:
c += a
はc = c + a
とおおよそ同じです。
3 -=
"subtract and assign"演算子は、左辺オペランドの値から右辺値を減算し、結果を左辺オペランドに代入します。
例:
c -= a
はc = c - a
とおおよそ同じです
4. *=
"乗算と代入"演算子:右手オペランドの値に左手オペランドの値を乗算し、その結果を左手オペランドに代入する。 。
例:
c *= a
はc = c * a
とおおよそ同じです
5. /=
「除算と代入」演算子:右手オペランドの値を左手オペランドの値で除算し、その結果を左手オペランドに代入する。
例:
c /*= a
は、c = c / a
とおおよそ同じです。
6. %=
"modulus and assign"演算子:右手オペランドの値のモジュラスを左手オペランドの値で計算し、その結果を左手オペランドに代入する。
例:
c %*= a
は、c = c % a
とおおよそ同じです
7. <<=
"left shift and assign"演算子。
例:
c <<= 2
は、c = c << 2
とおおよそ同じです。
>>=
"算術右シフトと代入"演算子。
例:
c >>= 2
はc = c >> 2
とおおよそ同じです
>>>=
"論理右シフトと割り当て"演算子。
例:
c >>>= 2
は、c = c >>> 2
とおおよそ同じです。
&=
"bitwise and assign"演算子。
例:
c &= 2
はc = c & 2
とおおよそ同じです
|| |=
"bitwise or assign"演算子。
例:
c |= 2
はc = c | 2
とほぼ同じc = c | 2
12. ^=
「ビットごとの排他的andおよび代入」演算子。
例:
c ^= 2
は、c = c ^ 2
とおおよそ同じです
条件付きおよび条件付きまたは演算子(&&および||)は、
Javaには条件付きの条件付き演算子と条件付きの演算子が用意されており、いずれもboolean
型の1つまたは2つのオペランドをとり、 boolean
結果を生成します。これらは:
&&
- 条件付きAND演算子、||
- 条件付きOR演算子。<left-expr> && <right-expr>
の評価は、次の擬似コードに相当します。{ boolean L = evaluate(<left-expr>); if (L) { return evaluate(<right-expr>); } else { // short-circuit the evaluation of the 2nd operand expression return false; } }
<left-expr> || <right-expr>
の評価<left-expr> || <right-expr>
は、次の擬似コードに相当します。
{
boolean L = evaluate(<left-expr>);
if (!L) {
return evaluate(<right-expr>);
} else {
// short-circuit the evaluation of the 2nd operand expression
return true;
}
}
上の擬似コードが示すように、短絡演算子の動作はif
/ else
文を使用することと等価else
。
例 - &&を式のガードとして使用する
次の例は、 &&
演算子の最も一般的な使用パターンを示しています。これらの2つのバージョンのメソッドを比較して、指定されたInteger
がゼロかどうかをテストします。
public boolean isZero(Integer value) {
return value == 0;
}
public boolean isZero(Integer value) {
return value != null && value == 0;
}
ほとんどの場合、最初のバージョンが機能しますが、 value
引数がnull
場合、 NullPointerException
がスローされます。
2番目のバージョンでは、「ガード」テストを追加しました。 value != null && value == 0
式は、最初にvalue != null
testを実行するvalue != null
によって評価されvalue != null
。場合null
(それが評価され、すなわち、テストが成功したtrue
)、その後value == 0
式が評価されます。 null
が失敗した場合、 value == 0
評価はスキップ(短絡)され、 NullPointerException
はNullPointerException
しません。
例 - コストのかかる計算を避けるために&&を使用する
次の例は、 &&
を使用して比較的高価な計算を避ける方法を示しています。
public boolean verify(int value, boolean needPrime) {
return !needPrime | isPrime(value);
}
public boolean verify(int value, boolean needPrime) {
return !needPrime || isPrime(value);
}
最初のバージョンでは、 |
常に評価されるので、(高価な) isPrime
メソッドは不必要に呼び出されます。 2番目のバージョンは、 ||
を使用して不要な呼び出しを回避します。 |
代わりに|
。
シフト演算子(<<、>>および>>>)
Java言語は、32ビットおよび64ビットの整数値をビット単位でシフトする3つの演算子を提供します。これらはすべてバイナリ演算子であり、最初のオペランドはシフトされる値であり、2番目のオペランドはどれだけシフトするかです。
<<
または左シフト演算子は、第1オペランドによって与えられる値を、第2オペランドによって与えられるビット位置の数だけ左にシフトする。右端の空の位置はゼロで埋められます。'>>'または算術シフト演算子は、第1オペランドによって与えられる値を、第2オペランドによって与えられるビット位置の数だけ右にシフトする。左端の空の位置は、一番左のビットをコピーすることによって埋められます。このプロセスは符号拡張として知られています。
'>>>'または論理右シフト演算子は、第1オペランドによって与えられる値を、第2オペランドによって与えられるビット位置の数だけ右にシフトする。左端の空の位置は0で埋められます。
ノート:
これらの演算子は、第1オペランドとして
int
値またはlong
値を必要とし、第1オペランドと同じ型の値を生成します。 (シフトの結果をbyte
、short
またはchar
変数に代入するときは、明示的な型キャストを使用する必要があります)。最初のオペランドが
byte
、char
またはshort
であるシフト演算子を使用すると、それはint
昇格され、演算はint
生成します。第2オペランドは、シフト量を与えるために、演算のビット数を法として減じられる。 modの数学的概念の詳細については、 Modulusの例を参照してください。
操作によって左端または右端からシフトされたビットは破棄されます。 (Javaはプリミティブな "回転"演算子を提供しません)。
算術シフト演算子は、(2の補数)数を2の累乗で除算して等価です。
左シフト演算子は、aの(2の補数)数に2の累乗を掛けることと等価です。
次の表は、3つのシフト演算子の効果を確認するのに役立ちます。 (数字は仮想化を助けるために2進表記で表現されています)。
オペランド1 | オペランド2 | << | >> | >>> |
---|---|---|---|---|
0b0000000000001011 | 0 | 0b0000000000001011 | 0b0000000000001011 | 0b0000000000001011 |
0b0000000000001011 | 1 | 0b0000000000010110 | 0b0000000000000101 | 0b0000000000000101 |
0b0000000000001011 | 2 | 0b0000000000101100 | 0b0000000000000010 | 0b0000000000000010 |
0b0000000000001011 | 28 | 0b1011000000000000 | 0b0000000000000000 | 0b0000000000000000 |
0b0000000000001011 | 31 | 0b1000000000000000 | 0b0000000000000000 | 0b0000000000000000 |
0b0000000000001011 | 32 | 0b0000000000001011 | 0b0000000000001011 | 0b0000000000001011 |
... | ... | ... | ... | ... |
0b1000000000001011 | 0 | 0b1000000000001011 | 0b1000000000001011 | 0b1000000000001011 |
0b1000000000001011 | 1 | 0b0000000000010110 | 0b1100000000000101 | 0b0100000000000101 |
0b1000000000001011 | 2 | 0b0000000000101100 | 0b1110000000000010 | 0b00100000000000100 |
0b1000000000001011 | 31 | 0b1000000000000000 | 0b1111111111111111 | 0b0000000000000001 |
ビット操作におけるシフト演算子の使用例
ラムダ演算子( - >)
Java 8以降では、Lambda演算子( ->
)はLambda式を導入するために使用される演算子です。これらの例に示すように、共通の構文が2つあります。
a -> a + 1 // a lambda that adds one to its argument
a -> { return a + 1; } // an equivalent lambda using a block.
ラムダ式は、匿名関数、またはより正確には、 機能インタフェースを実装する匿名クラスのインスタンスを定義します 。
(この例は、完全性のためにここに含まれています。完全な扱いについては、 Lambda Expressionsのトピックを参照してください)。
関係演算子(<、<=、>、> =)
演算子<
、 <=
、 >
および>=
は、数値型を比較するための2項演算子です。演算子の意味は期待通りです。たとえば、 a
とb
がbyte
、 short
、 char
、 int
、 long
、 float
、 double
または対応するボックス型のいずれかと宣言されている場合a
- `a < b` tests if the value of `a` is less than the value of `b`.
- `a <= b` tests if the value of `a` is less than or equal to the value of `b`.
- `a > b` tests if the value of `a` is greater than the value of `b`.
- `a >= b` tests if the value of `a` is greater than or equal to the value of `b`.
これらの演算子の結果の型は、すべての場合においてboolean
です。
関係演算子を使用すると、異なるタイプの数値を比較できます。例えば:
int i = 1;
long l = 2;
if (i < l) {
System.out.println("i is smaller");
}
関係演算子は、一方または両方の数値がボックス化された数値型のインスタンスである場合に使用できます。例えば:
Integer i = 1; // 1 is autoboxed to an Integer
Integer j = 2; // 2 is autoboxed to an Integer
if (i < j) {
System.out.println("i is smaller");
}
正確な動作は次のように要約されます。
- オペランドの1つがボックス型であれば、ボックス化されません。
- いずれかのオペランドが
byte
、short
またはchar
場合、int
昇格されます。 - オペランドの型が同じでない場合、「より小さい」型のオペランドは「より大きい」型に昇格される。
- 比較は結果の
int
、long
、float
またはdouble
値に対して実行されます。
浮動小数点数を含む関係比較には注意が必要です。
- 浮動小数点数を計算する式では、コンピュータ浮動小数点表現の精度が限られているため、丸め誤差が発生することがよくあります。
- 整数型と浮動小数点型を比較する場合、整数を浮動小数点に変換すると、丸め誤差が発生する可能性もあります。
最後に、Javaは、上記以外の任意の型の関係演算子の使用を少しサポートします。たとえば、これらの演算子を使用して文字列、数値の配列などを比較することはできません 。