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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

1回答

1197閲覧

NoSuchElementExceptionの解決法

Anna

総合スコア4

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2022/11/26 09:16

編集2022/11/26 13:53

前提

Eclipseで問題なし、paizaで実行時エラーとなります。
文字列を数字に分割する処理を含むコードで、nextIntメソッドを使っています。

実現したいこと

  • Javaの実行時エラー解決法を教えてください!

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

Exception in thread "main" java.util.NoSuchElementException at java.base/java.util.Scanner.throwFor(Scanner.java:941) at java.base/java.util.Scanner.next(Scanner.java:1598) at java.base/java.util.Scanner.nextInt(Scanner.java:2263) at java.base/java.util.Scanner.nextInt(Scanner.java:2217) at Main.main(Main.java:18)

該当のソースコード

<処理の概要>
以下N,C,r[i],c[i]は整数とします。
入力値"N C"を一つの文字列で受け取ります。#間は半角スペース
#ループ(最大N回)
入力値”r[i] c[i]”を受け取ります。
Cはc[i]ずつ減っていき、0以下になったらループを抜けます。
#ループ終わり
r[i]に1〜10が全て現れていたら、”Yes”
そうでなければ現れた数字の数を表示します。

Java

1import java.util.Scanner; 2 3public class Main { 4 public static void main(String[] args) { 5 6 Scanner sc1 = new Scanner(System.in); 7 int N = sc1.nextInt(); 8 int C = sc1.nextInt(); 9 10 int[] r = new int[N]; 11 int[] c = new int[N]; 12 int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 13 14 Scanner sc2 = new Scanner(System.in); 15 16 for (int i = 0; i < N; i++) { 17 18 r[i] = sc2.nextInt(); 19 c[i] = sc2.nextInt(); 20 21 if (C - c[i] <= 0) { 22 break; 23 } 24 C -= c[i]; 25 26 for (int j = 0; j < array.length; j++) { 27 if (r[i] == array[j]) { 28 array[j] = 0; 29 break; 30 } 31 } 32 } 33 34 int cnt = 0; 35 for (int i = 0; i < array.length; i++) { 36 if (array[i] == 0) { 37 cnt++; 38 } 39 } 40 41 if (cnt == array.length) { 42 System.out.println("Yes"); 43 } else { 44 System.out.println(cnt); 45 } 46 } 47}

試したこと

Eclipseに貼り付けて、同じテストケースを入力したところ、エラーは起きず、正しい動作をしました。。。
Eclipse では、警告が出ていません。try文によってScannerインスタンス生成を行なっています。

テストケース
12 9000
11 100
1 120
2 200
3 200
4 500
5 800
6 10
7 123
8 900
9 3000
10 2
12 7000
結果
paiza: 実行時エラー(NoSuchElementException)
Eclipse: Yes

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

Eclipse: java SE-17 2022-09 (4.25.0)
paiza.io: openjdk version "18.0.2.1" 2022-08-18

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Anna

2022/11/26 10:27

ご指摘ありがとうございま。修正しました
dodox86

2022/11/26 10:36

> Eclipseに貼り付けて、同じテストケースを入力したところ、エラーは起きず、正しい動作をしました 具体的なテストケースを本質問中に追記すると、より閲覧者、回答者さんらでの再現がしやすくなり、回答を得易くなります。 また、お使いのJavaのバージョンがEclipseとpaiza.ioで合っているか、あるいは互換性のある動きをしているか確認しましょう。 [paiza.IO 利用ガイド - 各言語のバージョン] https://paiza.io/help
Anna

2022/11/26 10:57

互換性があるかは、未熟者なので判定できませんが。。。 Eclipse 2022-09 (4.25.0) paiza openjdk version "18.0.2.1" 2022-08-18 >テストケース 12 9000 11 100 1 120 2 200 3 200 4 500 5 800 6 10 7 123 8 900 9 3000 10 2 12 7000 >結果 paiza 実行エラー Eclipse Yes
dodox86

2022/11/26 11:08

むしろ Eclipseで実行された時の方が異端(?)かもしれませんね。Java SE 8 でWindows コマンドプロンプト上で試したらpaiza.IOと同じエラーです。 >>>ここから C:\Java\work>javac Main.java C:\Java\work>copy con t.txt 12 9000 11 100 1 120 2 200 3 200 4 500 5 800 6 10 7 123 8 900 9 3000 10 2 12 7000 ^Z 1 個のファイルをコピーしました。 C:\Java\work>java Main < t.txt Exception in thread "main" java.util.NoSuchElementException at java.util.Scanner.throwFor(Scanner.java:862) at java.util.Scanner.next(Scanner.java:1485) at java.util.Scanner.nextInt(Scanner.java:2117) at java.util.Scanner.nextInt(Scanner.java:2076) at Main.main(Main.java:17) C:\Java\work>java -version java version "1.8.0_291" Java(TM) SE Runtime Environment (build 1.8.0_291-b10) <<<ここまで ※質問者さんのコードの問題は調べていません。
jimbe

2022/11/26 11:37 編集

少なくとも、System.in からの Scanner を複数作っているのでダメでしょう。 Eclipse のコンソールはあくまでエミュレートです。完全ではありません。 Paiza がどうやっているのかは知りません。 また、例外とは関係ありませんが、 > 入力値"N C"を一つの文字列で受け取ります。 nextInt で 2 回で受け取るのは 違うと思いますが。 > C-=c[i]; > if(C-c[i]<=0){ > break; > } 引いた後に、また引いた値で break 判定してますけど?
Anna

2022/11/26 11:51

>dodox86さん Eclipse では電球マークが出ていて、推測実行(?)していたみたいです。。。 try (Scanner sc1 = new Scanner(System.in)) {main内記述部分} try (Scanner sc2 = new Scanner(System.in)) { r[i] = sc2.nextInt(); c[i] = sc2.nextInt(); } とすると、2回目の入力"11 100"で、同じエラーが出ました。
dodox86

2022/11/26 12:15

@質問者 Annaさん jimbeさんが有益なコメントをされているので検討しましょう。
Anna

2022/11/26 13:23

>jimbeさん ご指摘ありがとうございます。 Scannerインスタンス sc2の生成をループの外に出したらEclipseではうまくいきました。 paizaでは同じエラーです。 nextIntで、入力を空白で区切って取得する方法を調べたまま使いました。 参考にした:https://qiita.com/mzmz__02/items/64d853f12d31a70d86c1       https://eng-entrance.com/java-scanner-delimiter break判定部分はコピーミスでした。テストケースの試行時はミスなしです。
jimbe

2022/11/26 16:11 編集

> Scannerインスタンス sc2の生成をループの外に出したらEclipseではうまくいきました。 sc2 自体が要らない(あってはならない)のです。 sc2 を作っている行を消し、 sc2 を使っている所を sc1 にしてください。 Scanner は最初の nextInt (等読み込む必要があるメソッド)で、返すのに必要なデータ以上に System.in から読み込んでいる可能性があります ( キャッシングとかバッファリングとかいうヤツです ) 。本件では全データを読み込み済みなのではないでしょうか。 2 つ目の Scanner である sc2 はそれを知らずに同様に nextInt で System.in からデータを取り出そうとし、 すでに EOF になっていて 当該例外を発しているものと思います。 1 つの入力元 ( 本件では System.in) から複数の取得オブジェクト (Scanner 等 ) を作成すると、このようなことが起きる可能性がありますので、原則 1 つの入力元からは 1 つしか取得オブジェクトを作成せず、複数個所で取得処理をするのであればその 1 つを使い回すようにしてください。
jimbe

2022/11/26 16:21 編集

>nextIntで、入力を空白で区切って取得する方法を調べたまま使いました。 要件でなく表現の問題だけであれば良いのですが。 先に書きました通り、 N, C の 2 つを 2 回の nextInt で取り込むことを「"N C"を一つの文字列で受け取ります」と表現するのは、紛らわしいと思います。 (参考にされた qiita の記事の "キャストする方法" なら、 nextLine で『一つの文字列で』受け取っています。蛇足ながら "キャストする方法" のコードの処理はキャストではありませんので、もしあの記事の処理を使って「キャストで受け取ります」と説明していたら、キャストが何なのか分かる人から「は?」と思われるでしょう。)
Anna

2022/11/27 07:38

>jimbeさん sc1のみ使ったら上手くいきました!テストケースも複数試して、問題はないようです。 丁寧な対応ありがとうございました。 System.inは一回きりなんですねー?知りませんでした。。System.inと書くと、入力を受け付けるものだと思っていましたが、nextIntメソッドが入力を受け付けているということなんでしょうか?
BeatStar

2022/11/27 07:45

> System.inと書くと、入力を受け付けるものだと思っていました まったく違いますね。Scannerクラスは「ファイル」「コンソール」どちらからも読み取れるようにしてあるクラスなので「どこから読み込むか」を指定する必要があります。そこでコンソールから読み込めという指定をSystem.inとして指定しているだけです。(内部ではSystem.inのメソッドなんかを使って処理しているものと思われるが) 読み込みはScannerが持つnextIntメソッドで取得していますね。
BeatStar

2022/11/27 07:47

後、解決したのなら「自己解決」みたいなものがあるはずなのでそこに「どのように解決したか」を書いておきましょう。似たような問題に直面した次の世代の人に対してのアドバイスにもなりますので。
jimbe

2022/11/27 07:59

> System.inは一回きりなんですね ちょっと言い過ぎています。『原則 1 つの入力元からは 1 つしか取得オブジェクトを作成せず、複数個所で取得処理をするのであればその 1 つを使い回す』です。 System.in は入力元(キーボードとかファイルとか)からのデータが並んでいるもの (InputStream) です。 https://docs.oracle.com/javase/jp/8/docs/api/java/lang/System.html#in System.in が入力を受け付けるのではありません。入力を受け付けるのは OS の何かで、そのデータは OS の "何処か" に保存されます。 java は System.in の InputStream を その "何処か" に繋げるので、 System.in から入力が取り出せるのです。 例えるなら、水道管が貯水槽に繋がっていて水が溜まるようになっているので、蛇口を貯水槽に繋げば自由に水を得られるということです。 Scanner はそこからデータを取り込みますが、例えば nextInt を呼ばれたら System.in から 100 バイト取り込んで、先頭の何バイトかで nextInt の戻り値を作って、残りは次回の nextInt 等が呼ばれた時に System.in からわざわざ取り込まなくて良い用に自分の内部で保存しておく…といった動作をします。 当然、 System.in 側は 100 バイト取り込まれたら次に取り込めるのは 101 バイト目としますし、もしデータが 100 バイトしか無かったとしたら次からは ”もうありません”(EOF) と言うことになります。 そこで 2 つ目の Scanner が nextInt で System.in から取り込もうとしたら EOF と言われ、"もうデータ無いってよ!" (NoSuchElementException) と言ってくるのです。 https://docs.oracle.com/javase/jp/8/docs/api/java/util/Scanner.html#nextInt--
Anna

2022/11/27 08:15

>BeatStarさん 返信ありがとうございます。 なるほど、コンストラクタの引数で機能が変わるんですか。 APIはクラスの動作を理解しないで勝手な使い方をしてはダメですね。。。
Anna

2022/11/27 08:22

>jimbeさん うーん、内部の細かな動作は、まだ私にはハードルが高いですね。。。 少しずつ理解していければと思います。 ひとまず解決とします、みなさんありがとう。
dodox86

2022/11/27 08:35

随分と込み入った話になってましたね。ひとまず解決とは、結局paiza.IOで問題無く動いたのでしょうか。
jimbe

2022/11/27 09:07

System.in の Scanner を入力の度に作っているコードは teratail でもよく出てきますので、恐らくその辺のことを教わっていない(教えていない)のでしょう。 java も OS も大量のプログラムの塊で、入力から数値を 1 つ得るまでにどれだけのプログラムが作られ動作しているのかは、食卓の料理 1 つが口に入れるまでにどれだけの労力と時間・資材が使われているのかと同じくらいの規模感を感じられると思います。
Anna

2022/11/27 09:07

>dodoxさん paiza.IOでも問題なしです。
guest

回答1

0

自己解決

前提
・このエラーの主な原因としては、Scannerインスタンス(System.in)を複数作っていること。
解決への変更点
・Scannerインスタンスは一つ生成し、それを使い回すようにした。

投稿2022/11/27 08:30

Anna

総合スコア4

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問