16

以下に示すように、複数のIntegerオブジェクトを作成してそれらを に配置するクラスがあります。LinkedList

public class Shares<E> implements Queue<E> {
    protected LinkedList<E> L;

    public Shares() {
        L = new LinkedList<E>();
    }

    public boolean add(E price) {
        System.out.println("How many of these shares would you like?");
        Scanner scanInt;
        scanInt = new Scanner(System.in);
        Integer noShares = scanInt.nextInt();
        for (int i = 0; i < noShares; i++) {
            L.addLast(price);
        }
        scanInt.close();

        return true;
    }
}

コンソールからの入力「追加」をスキャンし、見つかった場合は、add以下に示すようにメソッドを呼び出すアプリケーションがあります。

public class Application {
    private static Scanner scan;

    public static <E> void main(String[] args) {
        Queue<Integer> S = new Shares<Integer>();
        scan = new Scanner(System.in);
        System.out.println("Please type add");
        String sentence = scan.nextLine();
        while (sentence.equals("quit") == false) {
            if (sentence.equals("add")) {

                System.out
                    .println("What price would you like to buy your shares at?");

                S.add((Integer) scan.nextInt());

            } else
                System.exit(0);

            sentence = scan.nextLine();
        }
    }
}

アプリケーションでは、ユーザーが何度でも「追加」を入力できるようにする必要がありますが、addメソッドが呼び出された後に「行が見つかりません」というエラーが表示されます。

これはScanner、メソッド内の が閉じられておらず、必要に応じて再度開かれたためだと推測しています。これはプログラムの問題ですか? もしそうなら、どうすれば修正できますか?

これらの株式を売却する売却方法を追加する予定であるため、このプログラムは終了していません。そのため、while ループを使用しています。

4

3 に答える 3

17

任意のストリームに複数のラッパーを用意することは、自分自身を混乱させる優れた方法です。自分が何をしているのか本当にわからない限り、ストリームを一度だけラップすることをお勧めします。

これを行う最も簡単な方法は、別のシングルトンをラップするため、この場合シングルトンを使用することです (最良の方法は、スキャナーを引数として渡すことです)。

public class Application { 
    // use this Scanner in all you other code, don't create another one.
    static final Scanner scan = new Scanner(System.in);

    public static <E> void main(String[] args) {

これは、メソッドのスキャナーが閉じられていないためだと思います

ストリームを閉じると、基になるストリームが閉じられ、再び使用できなくなります。System.in を再度使用しないようにする場合にのみ、System.in を閉じてください。

どうすれば修正できますか?

最善の解決策は、すべての Scanner を 1 つの場所、1 つのメソッド、または 1 つのクラスで使用することです。main() でユーザーとのやり取りをすべて行い、値をデータ構造に渡します。自分自身を初期化するオブジェクトを持つことは、悪い習慣です。これをやり始めると、開発の残りの期間、悩まされることになります;)


ところで、説明なしにプログラムを終了しないでください。エラーメッセージすらSystem.exit(0);出ないのも悪夢です。System.exit() への 260 回の呼び出しがあり、エラー メッセージが表示されないことが多いプロジェクトに取り組んだことがあります。明確な理由もなく停止したサーバーを診断するのがどれほど楽しいか想像できるでしょう。

于 2013-11-04T11:19:23.307 に答える
11

最初の間違いは、このコード行です

scanInt.close();

scanInt オブジェクトだけでなく、System.in も閉じます。これは、add の最初の呼び出しの後、スキャン オブジェクトは既に持っている入力のみを消費し、NoSuchElementException: Remove this lineを受け取ることを意味します。

さて、最後の行をこれに置き換えると

sentence = scan.nextLine();
System.out.println("sentence: \"" + sentence + "\"");

終了する前に取得した最後の入力が空の文字列であることがわかります。したがって、次のループでelseステートメントを入力すると、プログラムの実行が停止します。以下を追加することで、この問題を解決できます。

scan.nextLine(); // consume the first always empty String...
System.out.println("Please type add");
sentence = scan.nextLine(); // and then get the actual value

ただし、複数のラッパーを使用するべきではないという Peter の意見に同意します。Shares クラス コントラクターで Scanner オブジェクトを引数として渡すことを検討してください。

于 2013-11-04T11:45:04.507 に答える