Javaでオペレータを使う方法

著者は、「書いて寄付」プログラムの一環として、フリーかつオープンソース基金に寄付をすることを選びました。

以下は日本語での自然な言い回しの一つです。

イントロダクション

演算子は、よく知られた算術演算子である引き算(-)や足し算(+)や、より高度なinstanceofなど、1つ以上の記号の組み合わせです。演算子を値や変数に適用すると、その演算による結果が得られます。このような演算は、変数に割り当てられるか、プログラムの最終目標が達成されるまでさらに評価されるため、プログラミングにおいて基本的です。

このチュートリアルでは、演算子が適用される値または変数であるオペランドについての理解が必要です。オペランドの数によって、演算子は3つのグループに分けることができます。最初に、操作に1つのオペランドしかない場合、演算子は単項と呼ばれます。同様に、2つのオペランドを関与する二項演算子があります。最後に、3つのオペランドがある場合、演算子は三項です。この分類に従い、このチュートリアルは各タイプの演算子に対して3つの主要な部分に分けられています。

このチュートリアルでは、数学の方程式などで使用されるようなプリミティブデータ型を操作するために、3種類の演算子をすべて使用します。また、参照型でも演算子を使用したより高度なシナリオや、演算子の優先順位のいくつかのルールについても調べます。

前提条件

このチュートリアルに従うためには、以下が必要です:

  • An environment in which you can execute Java programs to follow along with the examples. To set this up on your local machine, you will need the following:Java (version 11 or above) installed on your machine, with the compiler provided by the Java Development Kit (JDK). For Ubuntu and Debian, follow the steps for Option 1 in our tutorial, How To Install Java with Apt on Ubuntu 22.04. For other operating systems, including Mac and Windows, see the download options for Java installation.
    To compile and run the code examples, this tutorial uses Java Shell, which is a Read-Evaluate-Print Loop (REPL) run from the command line. To get started with JShell, check out the Introduction to JShell guide.
  • Familiarity with Java and object-oriented programming, which you can find in our tutorial, How To Write Your First Program in Java.
  • An understanding of Java data types, which is discussed in our tutorial, Understanding Data Types in Java
    .

単項演算子

一項演算子は、1つの被演算子に適用されるため、最も直感的です。一項演算子はコードを簡潔かつ読みやすくするためによく使用されます。増減値などの操作を明示的に記述する必要がなくなります。ただし、他の演算子と組み合わせると、一項演算子の使用は難しくなる場合もあります。このセクションで後で説明します。

次に、単項演算子を使用して値を増減させ、また真偽値を反転させます。

増加と減少演算子

増減演算子は、その名前が示すように、数字を増加させたり減少させたりします。増加演算子は、二つのプラス記号(++)の組み合わせであり、減少演算子は二つのマイナス記号(–)です。これらの演算子は、オペランドの前後に使用されます。

前置増分と前置減分

オペランドの前に演算子を使用すると、++または–を使用するかによってインクリメント前またはデクリメント前が行われます。プレ演算子を使用すると、オペランドの値が使用する前に変更されます。したがって、実際に値を使用するときにはすでに変更されています。

Info

情報:このチュートリアルの例コードに従って進めるには、jshellコマンドを実行して、ローカルシステム上でJava Shellツールを開いてください。その後、jshell>プロンプトの後に例を追加するか、コピー、貼り付け、編集することができます。jshellを終了するには、/exitと入力してください。

プリインクリメント演算子を使用するには、以下のコードをjshellに入力します。

  1. int theAnswer = 42;
  2. System.out.println(“Preincrementing: “ + ++theAnswer);

 

最初の行で、theAnswerという変数を値42で定義します。2行目では、println()メソッドを使用して変数を出力し、それがどのように変化したかを示します。

上記の例での前置インクリメント演算子は++であり、theAnswerの前に配置されます。このように前置インクリメント演算子を使用することで、まずtheAnswerの値が43にインクリメントされます。その後、println()が処理する時点では既に43になっているため、出力されるのは43です。

Output

theAnswer ==> 42 Preincrementing: 43

プリデクリメントは同様に機能しますが、増やす代わりにオペランドの値を減らします。この例題では、プリインクリメント演算子++の代わりにプリデクリメント演算子–を使用してください。

後置増分演算子と後置減分演算子

前置演算子とは対照的に、後置演算子はオペランドの値を使用後に変更します。特定の事例では、後置あるいは前置演算子がよく使用されますが、全体的には個人の好みの問題です。

ポストオペレータの動作を説明するために、theAnswerの値を後置インクリメントし、その値の変化を確認します。以下の行をjshellに追加してください。

  1. int theAnswer = 42;
  2. System.out.println(“Postincrementing: “ + theAnswer++);
  3. System.out.println(“Final value: “ + theAnswer);

 

最初に、変数「theAnswer」は42と等しい値です。それから、それが表示され、その後にインクリメントされます。最後の行では、最終的な値を確認するために再度表示します。

あなたの出力結果は以下の通りです:

Output

theAnswer ==> 42 Postincrementing: 42 Final value: 43

ご覧の通り、後置増分の間はtheAnswerは42のままです。後置増分の後に再び印刷すると、43になります(最終値:43)。

後置デクリメントも同じように動作します。まず値が取得され、使用された後にデクリメントされます。練習として、後置インクリメント演算子++を後置デクリメント演算子–に置き換えてみたり、あるいは前置演算子のいずれかを含めてみてください。

請求された内容をネイティブな日本語で言い換えると、「NOTオペレーター」となります。

論理否定演算子としても知られるNOT演算子は、ブール型のオペランドの値を反転させます。その記号は、感嘆符「!」で表されます。通常は、ブール型の変数や値を持っていて、逆の値を使い回したい場合にNOT演算子を使用します。これにより、無駄なく逆の値を持つ別の変数を作成する必要がありません。

ここには、NOT演算子が動作する例があります。単純化するために、trueの値を反転させます。

  1. boolean isJavaFun = !true;
  2. System.out.println(isJavaFun);

 

isJavaFunというブール変数をtrueと定義します。ただし、NOT演算子がtrueの前にあるため、trueの値が反転してfalseになります。上記のコードを実行すると、以下の出力が表示されます。

Output

isJavaFun ==> false false

これがNOT演算子の働き方です。時々混乱することもありますし、見つけるのも難しいことがあるので、控えめに使用するべきです。

上記のケースでは、!trueの代わりにfalseを使うことができます。これは、より見やすく直感的なアプローチですので、正しい方法です。一般的なルールとしては、追加の操作が必要とされる代替手段よりも、直接リテラルやメソッドを使用することがベストプラクティスです。ただし、場合によってはそれが意味をなさないか、または不可能な場合もあります。例えば、ブール値を反転させるために、NOT演算子を使用することが一般的です。

例えば、文字列が別の文字列を含んでいるかどうかを確認するには、contains()メソッドを使用することができます。しかし、逆の場合(つまり、文字列が別の文字列を含んでいない場合)には、組み込みの代替メソッドはありません。NOT演算子を使用してcontains()を使う必要があります。

「Java is smart.」という文字列があると想像してみてください。そして、以下の条件を確認したい場合、

    1. 文字列にはスマートが含まれています。

 

    文字列にはハードが含まれていません。

これらを確認するためには、以下のコードを使用します。

  1. String javaIsSmart = “Java is smart.”;
  2. boolean isSmartPartOfJava = javaIsSmart.contains(“smart”);
  3. boolean isHardNotPartOfJava = !javaIsSmart.contains(“hard”);

 

最初の行で、String型の変数javaIsSmartを定義します。2行目では、contains()メソッドの結果を使って、boolean型の変数isSmartPartOfJavaを定義します。この場合、文字列smartがjavaIsSmart文字列の一部であるかどうかを示します。同様に、3行目では、boolean型の変数isHardNotPartOfJavaを定義します。これは、javaIsSmartの中にhardが見つからない場合に決まります。

jshellでこのコードを実行すると、以下の出力が得られます。

Output

javaIsSmart ==> “Java is smart.” isSmartPartOfJava ==> true isHardNotPartOfJava ==> true

上記の出力によると、

  • isSmartPartOfJava is true because smart is found in javaIsSmart.
  • isHardNotPartOfJava is also true because hard is not found in javaIsSmart.

このセクションでは、オペランドを1つ使用してインクリメント、デクリメント、および反転演算子を調査しました。これらの演算子はオペランドが1つしかないにもかかわらず、NOT演算子のように使用するのが難しい場合があります。次のステップでは、2つのオペランドを持つ演算子を使用してこの知識をさらに発展させます。

バイナリ演算子

二項演算子は2つのオペランドに作用し、加算や減算といった算術演算に関連して一般的に使われます。論理演算子や特殊な関係演算子instanceofといった数学以外の二項演算子もあります。このセクションでは、おなじみの算術二項演算子から始めます。

算術的な2進演算子

これらは、加算(+)や減算(-)などの算術演算に使用されるよく知られた演算子です。以下に加算の例を示します。

  1. int theAnswer = 40 + 2;
  2. System.out.println(“The result is: “ + theAnswer);

 

最初の行で、2に40を足してtheAnswer変数に結果を代入します。それを表示すると、最終値は42になります。

Output

The result is: 42

Note

**NOTE:** 算術演算だけでなく、文字列を結合するためにもプラス記号(+)が使用されます。この使用法は、すでに例で見てきたように、値を出力する際に使われます。そこでは、プラス記号を使って、”The result is: “と変数theAnswerを結合しています。しかしこのプラス記号の使用法は例外であり、他の算術演算子は参照型に対して同様に使用することはできません。したがって、例えば文字列の一部を削除するためにマイナス記号を使用することはできません。

追加の練習として、Javaのドキュメントに記載されている他の算術演算子を使用してみてください。

代入演算子

代入演算子は左のオペランドを右のオペランドの値に割り当てます。通常、左のオペランドは変数であり、右のオペランドは値またはオブジェクトへの参照です。これはおそらくおなじみの音に聞こえるかもしれませんが、すべての例でこのような代入を使用してきました。このセクションでは、基本的な代入演算子、いくつかの複合代入演算子、およびキャスト演算子の使用方法を練習します。

基本的な代入演算子(=)は、よく知られており、一般的に使用される演算子です。

  1. int x = 1;

 

この例では、int型の変数xを宣言し、その値を1に割り当てます。イコール記号(=)を使用して変数に値を割り当てることができます。

複合代入演算子 (ふくごうだいにゅうえんざんし)

複合代入演算子(+=、-=、*=、\=)は、代入と加算や減算などの追加の算術演算を組み合わせたものです。これらの演算子を使用すると、煩雑なコードを避けることができます。特に簡単に理解できる算術演算において、この演算子を使用することで効率的なコードを作成することができます。

たとえば、追加と代入を組み合わせるために、複合的な+=代入演算子を使用します。

  1. int x = 1;
  2. int y = 1;
  3. x += y;
  4. System.out.println(“x is: “ + x);

 

最初の2行では、xとyという2つの整数変数を宣言し、両方に値1を割り当てます。次に、xを複合代入演算子として再代入します。これは、xにyが加算された後、再びxに割り当てられるという意味です。

上記のコードは、次のような出力を返します。

Output

x ==> 1 y ==> 1 $11 ==> 2 x is: 2

上記の出力によると、xとyは値1を取得します。3行目には、ランダムに割り当てられた名前($11)を持つ一時変数があります。これは複合代入演算の結果としてxの値を保持しています。最後の行では、xの値が2として出力されます。

同じコードは、複合代入演算子を使用せずに次のように書き直すこともできます。

  1. int x = 1;
  2. int y = 1;
  3. x = x + y;
  4. System.out.println(“x is: “ + x);

 

前の例とは対照的に、3行目にxとyの加算を明示的に記述するために追加のコードを書きます。

このコードを実行すると、以下の出力が返されます。

Output

x ==> 1 y ==> 1 x ==> 2 x is: 2

最終的に、両例でxは2に等しいです。ただし、2番目の例では、jshellは$11などの一時変数名を出力しませんでした。代わりに、値が変化したことを示すためにxを直接使用しました(x ==> 2)。このような冗長な出力は学習に非常に役立ち、jshellでのみ利用可能です。

複合代入演算子の残りの組み合わせには、減算(-=)、乗算(*=)、除算(/=)が含まれています。上記の例を変更して、それらがどのように機能するかを試してみてください。

複合演算子について知っておくことは重要です。なぜなら、よく使用されるからです。ただし、複合演算子を使用することにはパフォーマンス上の利点はありませんので、使用するかどうかは個人の選択です。もしも複合演算子が不必要に混乱を招くようであれば、使用する必要はありません。

キャスティング演算子

最後に確認するのは、キャスティング演算子です。これはデータタイプを括弧で囲んだもの、つまり(データタイプ)です。キャスティング演算子は、値をキャストするために使用されます。つまり、あるデータタイプを別のデータタイプとして解釈することです。

データ型は互換性が必要です。どのデータ型が互換性を持つかは、クラスが親や兄弟関係にあるかどうかなどの関係によって決まります。例えば、整数を格納するためにint型とshort型は変換できます。しかし、int型をboolean型に変換することはできません。これらのデータ型は互換性がないからです。

このセクションでは、キャストの一般的な例や問題について探究します。教育目的で、まずは正しくなく互換性のないキャストから始めます。

  1. boolean y = (boolean) 1;

 

この行では、整数の1をブール値にキャストして、変数yに割り当てようとしています。これをjshellに貼り付けると、以下のエラーが表示されます。

Output

| Error: | incompatible types: int cannot be converted to boolean | boolean y = (boolean) 1; |

エラーメッセージに説明されているように、intの値をbooleanに変換することはできません。booleanの値はtrueまたはfalseのいずれかであり、1がどのboolean値になるかを特定することは不可能です。

今度は、互換性のあるデータ型を使った例を試してみましょう。整数を保存するために、2つのプリミティブなデータ型、intとshortを使用します。その違いは容量にあります。つまり、情報を保存するための利用可能なメモリ量です。intはより大きな容量を持ち、したがってより大きな数値を保存することができます。

jshellに以下の行を追加してください。

  1. int prize = 32767;
  2. short wonPrize = (short) prize;
  3. System.out.println(“You won: “ + wonPrize);

 

最初の行では、32767という値を持つintのプリミティブ型を抽選賞金として定義します。しかしながら、2行目では、wonprizeの値にはshortのプリミティブ型の方が適していると判断し、(short)を使ってprizeをshortにキャストします。

上記のコードをjshellで実行すると、出力結果は次の通りです。

Output

prize ==> 32767 wonPrize ==> 32767 You won: 32767

上記の出力は、賞と獲得賞金の値が正しく32767に設定されていることを確認しています。最後の行では、獲得賞金変数を使用して、あなたがいくら勝ったかを述べています。

intとshortの場合、キャスティングは不要のように見え、実際にはそのようなキャスティングを見ることはほぼありません。しかし、この例はキャスティングの考え方を示すために役立ちます。

キャストは簡単なようですが、一つ注意点があります。大容量のデータ型から小容量のデータ型にキャストする場合、小容量の制限を超える可能性があるため、オーバーフローと呼ばれます。この問題を示すために、前の例を再利用して、賞金を32768に増やしてみましょう。

  1. int prize = 32768;
  2. short wonPrize = (short) prize;
  3. System.out.println(“You won: “ + wonPrize);

 

上記をjshellで実行すると、以下の出力が得られます。

Output

prize ==> 32768 wonPrize ==> -32768 You won: -32768

この場合、情報を失い、予期しない結果を得ます。short型にキャストすると、32768の値が-32768になります。これは、shortのストレージ容量が-32768から32767までの範囲にあるためです。最大値より大きな値を格納しようとすると、オーバーフローが発生し、最初から開始されます。この場合、32768を格納しようとすると最大容量(32767)を超えるため、次の値は最小可能値から割り当てられます。この場合、最小値である-32768です。

以上の出力が予想外に見えるのはそのためです – 最終的な報酬がマイナスの数値になってしまいました。このような問題は常に簡単には見つけられないので、注意深くキャストを使用する必要があります。Javaシリーズの将来のチュートリアルで扱われるようなより複雑なシナリオでは、キャストを使用することができます。

関係演算子 (Kankei enzanshi)

関係演算子は2つのオペランドを比較し、真偽値の結果を返します。もし関係が成立する場合、結果は真です。そうでなければ、結果は偽です。

最初の種類の関係演算子は等しい == と等しくない != です。これらは値やオブジェクトの等価性を主張するために使用されます。基本値やリテラルの場合、数学と同様に使用されます。

等号演算子を示すために、2つの整数リテラルを比較します。実際には、同じ数である1です。自分自身と比較して等しいかどうかを比較し、真の結果を得ることができます。以下のコードをjshellに貼り付けてください。

  1. System.out.println(1==1);

 

上記のコードでは、1が1と等しいかどうかをアサートしています。数値が等しいので、この式はtrueと評価されます。したがって、println()はtrueを出力します。

Output

true

練習として、偽の結果を得るために値の一つを変更してみてください。

Note

注意:等号(==)と代入演算子(=)の違いを確実に区別してください。それらが異なることを知っていても、混同することが簡単です。コードに構文エラーが生じない場合もあり、これによりデバッグが困難な問題が発生する可能性があります。

原始値を比較するのとは異なり、オブジェクトを等しいかどうか比較する方が複雑です。なぜなら、二つの変数が同じオブジェクトを指しているかを判断するからです。例えば、二つのIntegerを比較してみてください。

  1. Integer myAnswer = Integer.valueOf(42);
  2. Integer yourAnswer = Integer.valueOf(42);
  3. System.out.println(myAnswer == yourAnswer);

 

上記のコードでは、値が42の2つの整数変数を作成します。最後の行では、それらを等しく比較し、等しい場合にはtrueを出力します。以前のチュートリアル「Javaにおけるデータ型の理解」では、Integer.valueOf()がまずキャッシュを確認し、同じ値のオブジェクトがすでに存在する場合は同じオブジェクトを返します。そのため、myAnswerとyourAnswerは同じオブジェクトを受け取ることになります。

上記のコードをjshellに貼り付けると、下記の出力が得られます。

Output

myAnswer ==> 42 yourAnswer ==> 42 true

そのようなオブジェクトの比較は簡単に思えますが、時には難しいこともあります。最も混乱する例は文字列です。同じ値を持つ二つの文字列を比較してみてください。

  1. String answer1 = new String(“yes”);
  2. String answer2 = new String(“yes”);
  3. System.out.println(answer1 == answer2);

 

最初に、”yes”という値を持つ二つの新しいString変数(answer1とanswer2)を宣言します。ただし、新しいキーワードを使用して新しいStringオブジェクトを作成しました。そのため、二つの変数は同じオブジェクトを指しているのではなく、実際には値が同じである別々のオブジェクトを指しています。

上記のコードをjshellに貼り付けると、以下の出力が表示されます。

Output

answer1 ==> “yes” answer2 ==> “yes” false

回答1と回答2は同じ値(「はい」)を持っているにもかかわらず、それらの等価性はfalseと評価されます。つまり、彼らは等しくありません。もし、回答が両方とも肯定的であるかどうかを比較することを意図している場合、そして下層のオブジェクトには興味がない場合、これは混乱するかもしれません。この目的のために、Stringを含む多くのクラスには等価性を確認するための専用のメソッドがあります。

Stringの場合、このメソッドはequals()です。次のようにコードを変更して、equals()を使ってみてください(==の代わりに)。

  1. String answer1 = new String(“yes”);
  2. String answer2 = new String(“yes”);
  3. System.out.println(answer1.equals(answer2));

 

equals()メソッドは、比較されたオブジェクトに含まれる文字列が等しいかを検証します。

このコードをjshellに貼り付けると、次の出力が得られます。

Output

answer1 ==> “yes” answer2 ==> “yes” true

上記の出力は前の出力と似ていますが、trueで終わり、それにより2つのオブジェクトの値が等しいことが確認されます。この例は、参照型を比較する際に注意が必要で、利用可能な対応するメソッドを使用する必要があることを示しています。

代替の等号演算子である「!=」は、同様に使用されますが、二つの変数または値が同じではない(または等しくない)かどうかを確認します。練習として、以前の例のいくつかで「==」を「!=」に置き換えてみてください。

<と<=、>と=>は、同じく数学から派生した次の四つの関係演算子です。

次は、大なり演算子を使った例をご紹介します。

  1. System.out.println(4 > 5);

 

このコードをjshellで実行すると、次のような出力が得られます。

Output

false

上記のコードはまず、4が5より大きいかどうかを比較します。しかし、そうではないため、式はfalseと評価されます。比較結果のfalseは、println()メソッドによって出力されます。

最後の関係演算子はinstanceofです。この演算子は、変数が特定のクラス(またはサブクラス)のインスタンスであるか、あるいはインターフェースの実装であるかを評価します。Javaチュートリアル「Javaにおけるデータ型の理解」で説明されているように、インターフェースは要件のグループを持つ抽象的なエンティティです。

以下の例を使用して、instanceofの動作を調べてみましょう。

  1. String greeting = “hello”;
  2. System.out.println(greeting instanceof String);

 

まず、greetingという名前の変数を作成します。次に、括弧内でgreetingがStringのインスタンスであるかどうかを評価します。

jshellにコードを貼り付けると、次の出力が表示されます。

Output

greeting ==> “hello” true

あいさつはStringの一種であるため、式は真と評価され、println()によって画面に表示されます。

論理演算子 (ろんりえんざんし)

論理演算子は、論理積(&)、論理和(|)、排他的論理和(^)です。これらはすべて2つの値を以下のように評価します。

  • Logical AND is true when both values are true.
  • Logical OR is true when at least one of the values is true.
  • Exclusive OR is true if one value is true and the other is false.

上記の条件に当てはまらない場合、論理演算子は偽となります。

「論理的なAND(&)演算子を使用するには、次の例をjshellに貼り付けてください。」

  1. boolean isJavaFun = true;
  2. boolean isJavaPowerful = true;
  3. System.out.println(isJavaFun & isJavaPowerful);

 

最初の2行は、isJavaFunとisJavaPowerfulというブール変数を両方ともtrueに定義します。3行目では、括弧内でisJavaFunとisJavaPowerfulの論理AND演算を行い、その結果がprintln()によって出力されます。

このコードをjshellに貼り付けると、以下の出力が得られます。

Output

isJavaFun ==> true isJavaPowerful ==> true true

両方の変数が true に設定され、論理積の操作の結果として最終的に true が表示されます。

スキルを向上させるために、前のコード例をいくつかのバリエーションで試してみてください。変数の値をtrueとfalseの間で切り替える試みや、論理演算子を論理和(|)や排他的論理和(^)に変更する試みなどができます。

論理演算子の拡張版には、いわゆるショートサーキット論理演算子があります:ショートサーキットAND(&&)およびショートサーキットOR(||)です。これらは通常の論理ANDおよびOR演算子と類似していますが、重要な違いがあります:最初の演算子の評価が操作に十分な場合、2番目の演算子は評価されません。したがって、ショートサーキットANDが真であるためには、それを取り囲む両側が真でなければなりません。しかし、左側が偽であれば、右側は評価されません。同様に、ショートサーキットORでも、左側が偽であれば、右側は評価されません。

ここに短絡論理演算子ORを使用した例があります。

  1. boolean isJavaFun = true;
  2. Boolean isNullFun = null;
  3. System.out.println(isJavaFun || isNullFun);

 

最初に、変数isJavaFunにtrueという値を割り当てます。以前の例との整合性を保つため、この変数はbooleanという基本データ型です。ただし、次の変数であるisNullFunには、nullを割り当てるためにBoolean参照型を使用します。この例では、nullを参照する変数が必要なので、Javaのデータ型に関するチュートリアルで説明したように、基本データ型はnullにすることができず、それが参照型を使用している理由です。

括弧内で短絡評価の”または”が発生すると、左側がtrueとなるためisNullFunは無視され、これだけで式全体がtrueとなります。したがって、jshellでコードを実行すると、以下の出力が表示されます。

Output

isJavaFun ==> true isNullFun ==> null true

最初の行と2行目は、変数がtrueとnullに割り当てられていることを確認しています。3行目では、ショートサーキットのOR演算がtrueを返したため、trueが表示されます。

上記の例は、isNullFunが評価されないということと、ショートサーキット演算子の動作を示すために、nullを特定の目的で選ばれました。isNullFunが評価されるのを確認するためには、次のようにショートサーキットORを通常のORに変更してみてください。

  1. boolean isJavaFun = true;
  2. Boolean isNullFun = null;
  3. System.out.println(isJavaFun | isNullFun);

 

通常の論理和(OR)では、式の両側を評価します。

このコードをjshellで実行すると、次の出力が得られます。

isJavaFun ==> true
isNullFun ==> null
|  Exception java.lang.NullPointerException
|        at (#3:1)

論理ORがnullを評価しようとすると、java.lang.NullPointerExceptionが発生します。そのため、ショートサーキット演算子が優先され、通常の論理演算子の代わりにほとんど常に使用されます。

練習の一環として、最も人気で便利な短絡論理演算子 && と || を使ってみてください。

このセクションでは、基本的な算術からオブジェクトのキャストや等価性の比較まで、さまざまな例を用いてバイナリ演算子を使用しました。次のセクションでは、3つのオペランドを使って作業を行います。

三項演算子

前のセクションでは、1つまたは2つのオペランドを使用した演算子の使用方法を練習しました。この最後のセクションでは、三項演算子を使用します。これは三つのオペランドのみを扱う演算子です。構文は次のようになります:最初のオペランド ? 第二のオペランド : 第三のオペランド。最初のオペランドはブール値でなければなりません。もし最初のオペランドがtrueであれば、式から第二のオペランドが返されます。もし最初のオペランドがfalseであれば、第三のオペランドが返されます。

三項演算子は人気があり、頻繁に使用される。なぜならば、条件分岐などの複雑な文を書く必要がなく、結果を一時変数に格納する手間も省けるからです。

以下の例で三項演算子を試してみてください:

  1. boolean isJavaFun = true;
  2. String shouldILearnJava = isJavaFun ? “yes” : “no”;
  3. System.out.println(“Should I learn Java: “ + shouldILearnJava);

 

isJavaFunがtrueに設定されており、変数shouldILearnJavaはそれに基づいて三項演算子で決定されています。最初のオペランドであるisJavaFunがtrueであるため、2番目のオペランドである文字列”yes”が返されます。これを確認するため、3行目で変数shouldILearnJavaを出力し、この時点では”yes”であるはずです。

上記のコードを実行すると、以下の出力が得られます。

Output

Should I learn Java: yes

追加の練習として、isJavaFunの前にNOT演算子を使ってみてください。

  1. boolean isJavaFun = true;
  2. String shouldILearnJava = !isJavaFun ? “yes” : “no”;
  3. System.out.println(“Should I learn java: “ + shouldILearnJava);

 

isJavaFunの値を反転させることで、それをtrueからfalseに設定します。その結果、三項演算式は最後のオペランドである「no」を返します。

以下の文を日本語で自然に言い換えます。選択肢は1つだけです。
NOT演算子などの追加の演算子を使用する場合、三項式は混乱を招くことがあります。しかし、それらは冗長なコードを省くことができるため、人気があります。

演算子の優先順位

重要な演算子を知ると、それらを使用したり、組み合わせたりすることができるようになります。ただし、それらを組み合わせる前に、演算子の優先順位のルールを知る必要があります。

オペレータの優先順位は、演算子がどの順番で評価されるかを決定します。複数の演算子を使用することが一般的ですので、オペレータの優先順位を理解することが重要です。ルールは常に直感的ではありませんが、実際にはいくつかの主要なルールだけを知っていることが十分です。

演算子の優先順位を理解することは、近代プログラミングの事実上の標準であるクリーンなコードを書くのに役立ちます。クリーンなコードを書くということは、理解しやすくメンテナンスしやすいコードを書くことを意味します。演算子に関しては、クリーンなコードのパラダイムはできるだけ少ない演算子を使用し、演算子の入れ子や組み合わせではなく、別々の文を作成することに翻訳されます。

たとえば、以下のような文は避けるべきです。なぜなら、これらはあまりにも混乱を引き起こすからです。

  1. boolean isThisCleanCode = !true || false && true;

 

運用者のドキュメントを参照しても、最終結果(isThisCleanCodeがfalse)を予測することができないかもしれません。

以下には、最も重要でよく使われる優先ルールの一部があります。最優先のルールから始めます。

  • Pre and post increment and decrement operators: They have the highest precedence and take effect before any other operators.
  • Arithmetic rules from math: All rules valid in math are also valid in Java. For example, division / has higher precedence than addition +. Parentheses override the precedence; that is, you can group operations with parentheses and they will be evaluated with priority.
  • Equality and relational operators: Since they evaluate equality or relation, they also work with the final values of their operands, and thus all other operations have to be completed.
  • Logical OR and AND operators (including short-circuit): Similar to the ternary operator, they all need the final values of their operands, hence their low precedence.
  • Ternary operator: The ternary operator needs the final value of the first operand. For this to happen, all other operations must have been completed. That’s why the ternary operator has such low precedence.
  • Assignment operators: They are evaluated last so that all other operations have been completed and the final result can be assigned to the operand on the left. As an example, think of every variable that you have assigned with the equals sign so far.

今度は、演算子の優先順位を調べるために数学の問題を使います。

  1. int x = 1 + 10 / 2;

 

上記のコードをjshellに貼り付けると、以下の出力が表示されます。

Output

x ==> 6

上記の出力によると、xの値は6になります。これは、以下の操作が優先度を下げて実行されたためです。

    1. 最初に10 ÷ 2が評価されます。その結果は5です。

 

    1. 最初の計算結果(5)に1が加えられます。これにより、結果は6となります。

 

    代入演算子が登場し、最終結果(6)が変数xに代入されます。

数式は比較的簡単ですが、常に優先順位がわかりやすくなるよう、より詳細に括弧を使用して書き直すことができます。以下のように書き換えることを考えてみてください。

  1. int x = 1 + (10 / 2);

 

上記をjshellに貼り付けると、以前と同じ結果が印刷されます。

Output

x ==> 6

最後の例では、10 / 2 の周りに括弧を使っても演算の優先順位は変わりませんでした。その代わり、括弧の目的は、内部の演算の優先順位を明確にすることだけでした。このように括弧を使うことで、コードをより清潔で理解しやすくすることができます。特に演算が複雑な場合には、これが重要です。

優先規則は興味深く、時間をかけて学ぶことは良い考えです。クリーンコードのパラダイムを念頭に置き、不必要なネストや演算子の組み合わせはコードの弱点と見なされることを考慮してください。

結論

このチュートリアルでは、Javaの主要な演算子について学びました。いくつかのテストコードスニペットを書き、演算子に関連する最も便利で興味深いシナリオの一部を見ることができました。また、クリーンコードについて学び、演算子が不必要に過度に使用されるべきではないという事実も学びました。

Javaについてもっと詳しく知りたい方は、当社の「Javaでのコーディング方法シリーズ」をご覧ください。

コメントを残す 0

Your email address will not be published. Required fields are marked *