キーボードから入力された値も、Web の画面のフォームに入力された値も、プログラムにはまず文字列として届きます。120 と入力しても、届くのは数値の 120 ではなく "120" という文字列です。この回は、その文字列を数値に変換する形を扱います。
引き続き VS Code とローカルの Java 環境を使います。この回のコードはキーボードからの入力を待つので、実行ボタンを押しても入力できない場合は、ターミナルで javac Main.java → java Main の手順で実行してください。ターミナルで日本語が化けるときは、前の回の注記と同じく chcp 65001 を先に実行します。
入力を受け取る
Scanner は、キーボードからの入力を受け取る道具です。Main.java を次の内容にします。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("個数を入力してください: ");
String input = scanner.nextLine();
System.out.println("入力された値: " + input);
}
}
1行目の import と、new Scanner(...) の形は ArrayList の回と同じです。new Scanner(System.in) の System.in はキーボードからの入力を指します。これまで使ってきた System.out(画面への出力)と対になる書き方です。
System.out.print は println と違って改行しないので、入力欄が同じ行に続きます。
実行すると入力待ちで止まります。3 と入力して Enter を押してください。
個数を入力してください: 3
入力された値: 3
画面には 3 と出ていますが、input の型は String です。数値ではありません。
そのままでは計算できない
1個120円として合計を出したくなります。String input = ... の下に、この行を足してみてください。
int total = input * 120;
これはコンパイルが通りません。String と int を * で掛けることはできず、javac は「型が合わない」という趣旨のエラーを出して止まります。表示される文面は環境の言語設定によって変わりますが、指されている行は同じです。
前回の NullPointerException は実行してみるまで分かりませんでしたが、こちらは実行の前に止まります。型が合わない間違いは、コンパイラが見つけてくれます。
Integer.parseInt で数値にする
変換を1行はさみ、表示する内容も合計に変えます。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("個数を入力してください: ");
String input = scanner.nextLine();
int count = Integer.parseInt(input);
int total = count * 120;
System.out.println("合計: " + total + "円");
}
}
個数を入力してください: 3
合計: 360円
Integer.parseInt(input) は、文字列を int に変換して返します。parse は「解釈する」という意味です。count の型が int になったので、* 120 の計算が通ります。
Scanner には nextInt() という「整数として読む」メソッドもあります。ただし数値でない文字が入力されたときに失敗する点は同じです。この回では、届いた文字列をいったん受け取ってから変換する形で進めます。
数値にできない文字を入れると落ちる
もう一度実行して、今度は abc と入力してください。
個数を入力してください: abc
Exception in thread "main" java.lang.NumberFormatException: For input string: "abc"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:565)
at java.base/java.lang.Integer.parseInt(Integer.java:662)
at Main.main(Main.java:10)
NumberFormatException は「数値の形式ではない」という意味です。For input string: "abc" に、変換しようとした値がそのまま出ています。
前回と違うのは、at で始まる行が4つあることです。この一覧をスタックトレースと呼びます。
上の3つは java.base で始まっていて、Java 側のファイルです。自分で直せる場所ではありません。探すのは、自分が書いたファイル名が出ている行です。ここでは一番下の at Main.main(Main.java:10) で、10行目の Integer.parseInt が該当します。
このコードは Temurin 25 で確認しています。
java.baseで始まる行の番号(Integer.java:565など)は Java のバージョンによって変わります。見るのはMain.javaの行番号のほうです。
失敗しやすい入力
数字に見えても変換できない値があります。
| 入力 | Integer.parseInt の結果 |
|---|---|
"120" | 120 |
" 3 "(前後に空白) | 失敗する |
"1.5" | 失敗する |
"abc" | 失敗する |
""(何も入力せずに Enter) | 失敗する |
空白は trim() で落とせます。コピーして貼り付けた値には空白が混ざりやすいので、入力を受け取る場面ではよく使います。先ほどのコードの10行目を、次のように書き換えます。
int count = Integer.parseInt(input.trim());
ただし何も入力せずに Enter を押した場合は、trim() を通しても失敗します。 空白だけを入力した場合も、trim() の結果が空になるので同じです。値が入っているかどうかは、変換とは別に確かめる必要があります。
小数を受け取りたい場合は Double.parseDouble を使います。Integer.parseInt("1.5") は失敗しますが、Double.parseDouble("1.5") は 1.5 になります。整数として読むメソッドに小数を渡しても、切り捨てにはならず失敗します。
逆に、数値を文字列にする
計算結果を文字列として扱いたいときは String.valueOf を使います。
public class Main {
public static void main(String[] args) {
int total = 360;
String text = String.valueOf(total);
System.out.println(text.length());
}
}
3
text は "360" という3文字の文字列なので、length() は 3 を返します。total のままでは length() を呼べません。
なお System.out.println("合計: " + total) のように + でつなぐ場合は、変換を書かなくても文字列として扱われます。変換を明示するのは、結果を String の変数に入れたいときや、文字数を数えるような文字列としての操作をしたいときです。
変換の早見表
| やりたいこと | 書き方 |
|---|---|
| 文字列 → 整数 | Integer.parseInt(s) |
| 文字列 → 小数 | Double.parseDouble(s) |
| 数値 → 文字列 | String.valueOf(n) |
| 数値を文字列に混ぜて表示する | "合計: " + n |
この先どこで出てくるか
画面のフォームに入力された値は、文字列です。 Part 4 で JavaScript から入力欄を読むときも、取り出せるのは文字列で、この回と同じ話になります。
そこから先は少し違います。Web アプリがサーバーへデータを送るときは JSON という形式を使いますが、JSON は数値も書ける形式です。{"count": 3} の 3 は文字列ではなく数値として書かれています。Spring Boot では、届いた JSON を宣言した Java の型へ変換する仕組みが用意されているので、Integer.parseInt を自分で書く場面はほとんどありません。
それでも、変換が失敗しうるという性質は残ります。 数量の欄に文字が入力されれば、変換はどこかで失敗します。違うのは出てくる場所です。この回のように画面へスタックトレースが出るのではなく、ブラウザにはエラーの応答が返り、詳しい内容はサーバー側のログに出ます。探す場所が変わるだけで、読むものは同じだと思っておいてください。
次の回へ
次はクラスとオブジェクトです。ここまでは値を1つずつ変数に入れてきましたが、関連するデータをひとまとめにして名前を付ける方法に入ります。Spring Boot でデータを扱うときの土台になります。