Javaアプリケーション – おみくじ②コード解説(標準入力・出力、エスケープシーケンス、四捨五入、乱数生成、キャスト)

Javaで作るおみくじアプリのサムネ画像です。 プログラミング

みなさんこんにちは、一星零哉です。

前回の記事でおみくじアプリの要件とコードを展開しました。

今回からはこのプログラムのコードについて解説をしていきます!

このアプリケーションのGitHubリポジトリ

標準入力と標準出力

まずは標準入力と標準出力の意味をおさえましょう。

標準入力ユーザがプログラムにデータを渡すこと
標準出力プログラムがユーザに処理結果を表示すること

標準入力

標準入力とは「ユーザがプログラムにデータを渡すこと」です。

キーボードでコンソールに文字を入力するのが代表例です。

このプログラムでは以下の部分が標準入力に該当します。

Scanner scanner = new Scanner(System.in);
String inputChar = scanner.nextLine();

コードの処理の流れは以下のとおりです。

  1. コンソールに入力された値はSystemクラスのinフィールドに保存されます。
  2. この値を引数にScannerクラスをインスタンス化します。
  3. Scannerクラスは入力されたデータを解析してくれるテキストスキャナーです。
  4. 最後、ScannerクラスのnextLineメソッドでコンソールに入力された値をString型の変数inputCharに代入しています。

たった2行のコードで、コンソールから入力した値をプログラムの中で自由に使うことができます。

標準出力

あなたがJavaの基礎構文を書いたことがあるなら、標準出力という単語は知らなくてもモノ自体は知っているはずです。

System.out.println("Hello, world!");

こいつですね。Java初学者が一番最初に出会うであろうアレです。

printlnメソッドは引数として渡された値をコンソールに出力してくれます。

エスケープシーケンス

エスケープシーケンスとは、特殊文字をただの文字として表示するための記法です。

System.out.println("引く場合は\"y\"を入力してください。");

例えば”(セミコロン)です。”の後ろに\がついているのがお分かりかと思います。

では、このプログラムを実行したときに、\は出力されるでしょうか?

答えはNoです。

Javaのプログラムにおいて””で囲われている値は文字列として認識されます。

上記の例で、エスケープシーケンスを使用しなかったらどうなるでしょうか?

System.out.println("引く場合は"y"を入力してください。");

コンパイラは”引く場合は”と”を入力してください。”の2つの引数を渡されたと理解します。

printlnメソッドは複数の引数を渡されることを許容しませんから、無理やり実行するとコンパイルエラーで落ちます。

Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
	The preview feature String Template is only available with source level 22 and above
	型の不一致: String から StringTemplate.Processor<R,E> には変換できません
	トークン "y" に構文エラーがあります。正しくは . です

	at omikuji/SampleOmikuji.SampleOmikuji.main(SampleOmikuji.java:10)

EclipseをはじめとしたIDEを利用していれば、該当行に警告も表示されていると思います。

今回の場合、私たちはコンパイラに”を「文字列を表す記号」としてではなく「純粋な文字列」として認識してもらいたかったはずです。

このような場合に、記号の後ろに\をつけることで「これは文字列なんだ」と認識させることができます。

乱数生成

乱数生成とは、ランダムに数値を生成することを指します。

おみくじのように、何らの法則性もない値を決める際に適しています。

Javaでは、Mathクラスのrandomメソッドを使用します。

int ftn = (int) Math.round(Math.random() * 10);

上記コードでは複数の処理を1行で行っているのですが、乱数生成は”Math.random()”の部分です。

これだけで乱数を生成して値を返してくれます。生成される値の範囲は0.0以上1.0未満で、データ型はdoubule型です。

ちなみに、上記コードでは下記の処理を行っています。

  1. Math.random()で乱数を生成する(0.0 <= Math.random() > 1.0)
  2. 生成した値を10倍する
  3. Math.round()で小数第1位で四捨五入する
  4. double型の値をint型にキャストして、int型の変数ftnに代入する

四捨五入

すでに登場していますが、JavaではMathクラスのroundメソッドを用いることで引数を四捨五入した値を取得することができます。

引数にdouble型の値を渡した場合、戻り値はlong型になります。

キャスト

データ型の変換を「キャスト」と言います。

値を変数に代入する場合、代入する値と変数が一致していなければなりません。

int型の変数にはint型のデータしか代入することができません。

無理やりデータ型の異なる値を代入しようとすると、以下のメッセージと共にコンパイルエラーになります。

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	型の不一致: double から int には変換できません

	at omikuji/SampleOmikuji.SampleOmikuji.main(SampleOmikuji.java:8)

今回のように、long型のデータはint型に変換することでint型の変数に代入できるようになります。

キャストをする上で、注意しなければならない点があります。それが「ダウンキャスト」です。

ダウンキャストとは、大きな値を扱えるデータ型をそれよりも小さなデータ型にキャストすることを指します。

例えばlong型とint型のキャストを考えてみます。

long型のデータが扱うデータの大きさは2の64乗(-9223372036854775808~9223372036854775807)、int型のデータが扱うデータの大きさは2の32乗(-2147483648~2147483647)です。

int型をlong型に変換するのは問題ないことはイメージつくでしょうか?

int型は最大の値をとったとしてもlong型のデータの大きさに収まりますからね。このようなキャストを「アップキャスト」と言い、この場合は暗黙的なキャストも許容されます。

int numInt = 1;
long numLong = 1;

numLong = numInt;
// この代入は問題ない

では、逆はどうでしょうか?

long型は-2147483648よりも小さい値や、2147483647よりも大きい値をとる可能性があります。

int型に2147483648を代入しようとすると、扱えるデータの上限を超えてしまいます。

このように、暗黙的なキャストが許容されるとデータ型の不整合が生じる可能性があるため、ダウンキャストの場合は必ず明示的にキャストしてやる必要があります。

具体的な方法は、代入したい値の先頭に(int)と付けてやります。

int numInt = 1;
long numLong = 1;

numInt = (int)numLong;
// ダウンキャストする場合は、必ず明示的に記述する

まとめ

今回の記事のまとめです!

  • 標準入力、標準出力
    • コンソールでのデータの入力と出力(表示)
  • エスケープシーケンス
    • 特殊文字を文字列として認識させる
  • 乱数生成
    • Math.random
  • 四捨五入
    • Math.round()で引数として渡した値を四捨五入
  • キャスト
    • データ型の変換

参考

Systemクラス Scannerクラス エスケープシーケンス Mathクラス

コメント