質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.80%

Scannerが使えない(に関する問題)part3

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 327

score 79

前提・実現したいこと

現在classをどんどん追加して入力した番号に対応したclassを実行させるプログラムを作っているのですが、その入力にScannerを使用していてまず0を入力したところclassを選択するところはできたのですがclass calcuScannerが実行しようとした瞬間エラーが起きました。直し方を教えてください。

発生している問題・エラーメッセージ

Exception in thread "main" java.util.NoSuchElementException
        at java.base/java.util.Scanner.throwFor(Scanner.java:937)
        at java.base/java.util.Scanner.next(Scanner.java:1478)
        at calcu.test03(test0301.java:25)
        at test0301.main(test0301.java:13)

該当のソースコード

import java.util.Scanner;

public class test0301
{
    public static void main(String[] args)
    {
        System.out.print(">>");
        var sentaku = new Scanner(System.in);
        int cl_num = sentaku.nextInt();
        sentaku.close();
        var cl0 = new calcu();
        switch(cl_num){
            case 0:cl0.test03();break;
        }


    }
}
class calcu
{
    void test03(){
        Scanner sc = new Scanner(System.in);
        put("説明を表示しますか");
        put("Y or N");
        String setumei = sc.next();
        if(setumei.equals("Y")||setumei.equals("y")){
            put("これから出てくる指示の通りに入力してください");
            put("");
        }
        try{
            while(true){
                put("数値を入力してください");
                System.out.print(">>");
                int num1 = sc.nextInt();
                put("演算子を入力してください");
                System.out.print(">>");
                String str1 = sc.next();
                put("数値を入力してください");
                System.out.print(">>");
                int num2 = sc.nextInt();
                int answer = 0;
                int answer2 = 0;
                switch(str1){
                case "+":
                    answer = num1 + num2;
                    put("A."+answer);
                    break;
                case "-": 
                    answer = num1 - num2; 
                    put("A."+answer);
                    break;
                case "*": 
                    answer = num1 * num2; 
                    put("A."+answer);
                    break;
                case "/":
                    answer = num1 / num2;
                    answer2 = num1 % num2;
                    if(answer2 != 0){
                        put("A."+answer + "…"+answer2);
                    }else{
                        put("A."+answer);
                    }
                    break;
                case ";":
                    answer = num1 + num2;
                    put("A."+answer);
                    break;
                case ":": 
                    answer = num1 * num2; 
                    put("A."+answer);
                    break;
                }
                put("");
                put("もう一度計算しますか");
                put("Y or N");
                String nextln = sc.next();
                if(nextln.equals("Y")||nextln.equals("y")){
                    put("");
                }else{
                    put("終了します");
                    break;
                }
            }
        }
        catch(Exception e){
            put("終了します");
        }
        sc.close();
    }
    public static void put(String str)
    {
        System.out.println(str);
    }
}

補足情報(FW/ツールのバージョンなど)

java jdk-14.0.2

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

System.in は Scanner で close すると、もう使えなくなります。
new Scanner(System.in) とその close はプログラム中で一度だけにしましょう。

-        sentaku.close();
-        var cl0 = new calcu();
+        var cl0 = new calcu(sentaku);
         switch(cl_num){
             case 0:cl0.test03();break;
         }
-
-
+        sentaku.close();
     }
 }
 class calcu
 {
+    Scanner sc;
+    calcu(Scanner sc) { this.sc = sc; }
     void test03(){
-        Scanner sc = new Scanner(System.in);
         put("説明を表示しますか");
         }
-        sc.close();
     }


追記

close(); を一度使うと二度と Scanner を使えなくなるという認識で正しいでしょうか。

System.in に関してはそうです。
他のファイルや文字列に対しては、Scanner は何度でも使えます。

System.in に関しても close() しなければ何度でも使えますが、
new するたびにバッファが確保され、リソースが無駄になります。

まず、次のコードを試してみてください。

import java.util.Scanner;

class Test {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        if (!sc.hasNextLine()) {
            System.out.println("1. no line");
            return;
        }
        String line = sc.nextLine();
        System.out.println(line);
        sc.close();

        sc = new Scanner(System.in);
        if (!sc.hasNextLine()) {
            System.out.println("2. no line");
            return;
        }
        line = sc.nextLine();
        System.out.println(line);
        sc.close();
    }
}


2回目の new Scanner(System.in); はエラーになります。

では、最初の sc.close(); を実行しなければどうなるか?
キーボード入力で 2行読めます。

ところが、java Test <file.txt のように標準入力をファイルに切り替えると
2行目の読み込みができません。

なぜかというと、Scanner は内部にバッファ(多分 8KB)を用意します。

入力がキーボードだと、1回の read で、1行しかバッファに読み込まないため、
新しい Scanner でも次の行が読めます。

でも、入力がファイルだと、最初の Scanner がファイルを読み込めるだけ全部
バッファに読み込んでしまいます。
次の Scanner はもう読み込むものがありません。
ファイルのサイズが 8KB 以上だったら、続きが読めます。
でも、2行目は最初の Scanner で読み込まれているので、
ずっと後の行の途中からしか読み込めません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/10/02 23:04 編集

    close(); を一度使うと二度と Scanner を使えなくなるという認識で正しいでしょうか。

    キャンセル

  • 2020/10/06 22:05

    追伸ありがとうございます。
    とても分かりやすかったです。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.80%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る