5

Всем привет. Я совсем новичок и все утро ломаю голову над таким вопросом. К примру, простая программа, которая записывает вопросы и ответы в массив:

import java.util.Scanner;

class proba {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        System.out.println("Input the number of cards:");
        int skolko = scan.nextInt();
        String[] vopros = new String[skolko];
        String[] otvet = new String[skolko];
        int i = 0;
        for (; i < skolko; i++) {
            System.out.println("The card #" + (i + 1) + ":");
            vopros[i] = scan.nextLine();
            System.out.println("The definition of the card #" + (i + 1) + ":");
            otvet[i] = scan.nextLine();
        }
    }
}

Если переменную int skolko записывать в программу (int skolko = 3;) то программа работает адекватно и запрашивает по очереди вопрос / ответ ровно 3 раза.

The card #1:
<<
The definition of the card #1:
<<

Если переменную skolko вводить через int skolko = scan.nextInt();, то программа сперва просит ввести цифру, а потом сразу выводит

The card #1:
The definition of the card #1:
<

то есть ввода значения, после The card #1: не происходит и для card #1 присваивается пустое значение ("").

Почему так?

Ilya
  • 51
  • 1
  • 4

1 Answers1

10

Причина проблемы:

Сначала нужно понять как работает scanner.nextLine(). Он дочитывает строку (по факту, он движется по массиву байт из InputStream консоли, т.е. из System.in) до её конца (до \n, либо \r\n, в зависимости от среды), после чего останавливается на первом же символе после символа(ов) конца строки, а все что он прочитал (за исключением символа(ов) конца строки он возвращает в качестве результата вызова).

Перед for вы вызываете scanner.nextInt(), который считывает число из InputStream консоли и останавливает свой указатель на первым же символе после окончания числа, в вашем случае, т.к. после ввода числа вы нажали enter у вас там находится символ(ы) перевода строки.

На первой итерации for у вас вызывается scanner.nextLine(), который согласно вышеописанному механизму читает все символы до конца строки и останавливается, но в вашем случае он уже стоял на символе конца строки, поэтому он просто сдвинул свой указатель на первый же символ после символа(ов) конца строки и остановился, а в результате своего вызова вернул пустую строку ("").

Решение проблемы:

Самый простой для вас способ: написать scanner.nextLine(); сразу же после вызова scanner.nextInt(); для перевода scanner на следующую строку (указатель в считываемом InputStream смещается на первый символ после символа(ов) конца текущей строки), где ввод символа контра строки еще не был осуществлен (т.к. её ввод, вообще, еще не был осуществлен).

Пример альтернативного варианта использования nextInt:

На основании вопросов из комментариев приведу пример, поясняющий как еще можно работать с методом nextInt:

public class Example {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("Введите три числа в одну строку, разделенные пробельными символами:");
        System.out.println(scanner.nextInt());
        System.out.println(scanner.nextInt());
        System.out.println(scanner.nextInt());
    }
}

Как видите, не обязательно выполнять nextLine после каждого nextInt, вы можете за раз из одной строки прочитать несколько чисел, разделенных пробельными символами.

Рекомендации:

В рамках Java для наименования классов согласно naming conventions принято использовать стиль UpperCamelCase (например, Proba), а не lowerCamelCase, как у вас (proba).

  • Большое спасибо. Получается, что scan.nextLine(); и scan.nextInt(); работают по разному? Int всегда требует, чтобы после него очистили строку маркером scan.nextLine();, а scan.nextLine();, при считывании строки этого не требует т.к. дочитывает строку до конца? – Ilya Apr 10 '20 at 14:40
  • @Ilya, на самом деле, они работают очень схоже, просто у них разные алгоритмы остановки чтения байтов из InputStream: nextLine читает все символы до конца строки, а nextInt пропускает все пробельные символы начиная с текущей позиции до первого символа числа, затем читает до тех пор пока идут числовые символы (останавливается, когда встречает пробельный символ или символ перевод строки, иначе падает с исключением). – StateItPrimitive Apr 10 '20 at 14:50
  • @Ilya, отвечая на вопрос касательно nextLine после каждого nextInt: посмотрите, пожалуйста, в конец ответа, я его дополнил информацией касательно альтернативного use-case nextInt. – StateItPrimitive Apr 10 '20 at 14:54
  • Спасибо еще раз. Всё понял и разобрался. – Ilya Apr 10 '20 at 15:26
  • @Ilya, если мой (или любой другой ответ) ответ помог вам решить проблему, то лучше пометить его, как "решение", иначе другим участникам stack overflow данный вопрос будет отображать как "нерешенный" и они будут зря отвлекаться на него. – StateItPrimitive Apr 11 '20 at 20:13