Подтвердить что ты не робот

Почему этот цикл плохой практики?

Следующий цикл не является хорошей практикой. Это связано с тем, что String является основным условием цикла for, а не переменной int, то есть цикл for бесконечен? Кроме того, это связано с тем, что нет экземпляра для ввода "конца", чтобы остановить цикл?

Scanner in = new Scanner(System.in);
int i = 0;
for (String s = in.next(); !s.equals("end"); i++) 
{
    System.out.println("The value of i is: " + i + " and you entered " + s);
}

Как я могу переписать его, чтобы он соответствовал принятому стилю?

(Это вопрос в предыдущей экзаменационной статье.)

4b9b3361

Ответ 1

Ну, ваша строка s никогда не меняется, что может привести к бесконечному циклу. Вероятно, вы хотели:

for (String s = in.next(); !s.equals("end"); s = in.next(), i++) {
    ...
}

Некоторые (включая меня) могут сказать, что i++ не должен находиться в секции приращения этого цикла, поскольку он не имеет прямого отношения к условию:

for (String s = in.next(); !s.equals("end"); s = in.next()) {
    ...
    i++;
}

Это связано с тем, что строка является основным условием цикла for, а не переменной int, то есть цикл for бесконечен?

Исходный цикл был действительно бесконечным (по крайней мере, после ввода начального ввода и предполагая, что "end" не был первым входом). Однако это не по той причине, о которой вы заявляете. For-loops чаще всего записываются с использованием интегральных контрольных переменных цикла, но это не всегда так. Например, общая идиома для итерации через связанный список:

for (Node node = list.head; node != null; node = node.next) {
    ...
}

Проблема с вашим циклом заключается в том, что строка s никогда не изменяется, поэтому она никогда не будет равна "end", если только первый вход.

Ответ 2

Я бы предложил разделить условие цикла и вызов на Scannner.next():

while (in.hasNext()) {
    String s = in.next();
    if (s.equals("end")) {
      break;
    }
    System.out.println("The value of i is: " + i + " and you entered " + s);
    i++;
}

Я думаю, что это намного легче понять, чем пытаться сжать все в выражение for.

Ответ 3

С этим кодом существует несколько проблем:

  • s никогда не изменяется после первоначального присваивания, поэтому это бесконечный цикл.
  • Вызов .next() может вызвать NoSuchElementException или IllegalStateException. Вместо того, чтобы ловить эти исключения, я считаю более вежливым проверить .hasNext() заранее, так как исчерпание входных данных является предсказуемой, а не исключительной ситуацией. Тем не менее, альтернативный стиль ask-for-forgive также может быть приемлемым.
  • Заголовок for-loop не формирует связную историю - он инициализирует s и тестирует s, но обновляет i.
  • По-моему, System.out.format() будет несколько предпочтительнее System.out.println() с конкатенацией.

Я бы написал его как:

Scanner in = new Scanner(System.in);
int i = 0;
String s;
while (in.hasNext() && !"end".equals(s = in.next())) {
    System.out.format("The value of i is: %d and you entered %s\n", i++, s);
}

Также может быть приятным пользовательским интерфейсом, чтобы сообщить пользователю, что end является волшебным словом для завершения цикла (при условии, что он был изменен, чтобы работать как возможно предназначенный).

Ответ 4

Общей практикой для циклов for является то, что переменная счетчика повторяется в каждом члене:

for(int i=...; i<... ; i++)

В приведенном выше примере код смешивает переменные. Это сбивает с толку читателя и, вероятно, приводит к ошибке, что цикл заканчивается только при вводе end в качестве первого значения.

Ответ 5

Это не очень хорошая идея, потому что строка s никогда не может быть равна "end". Вероятно, вам захочется проверить, есть ли в сканере другая строка. Кроме того, вы только инициализируете строку до in.next(), но вам нужно установить s в следующую строку после каждой итерации цикла.

while(in.hasNext()) {
  String s = in.next();
  if (s.equals("end")) {
    break;
  }
  // ..
}

Ответ 6

Этот цикл - плохая идея, потому что вы принимаете установку s один раз с пользовательского ввода, а не на каждой итерации. Таким образом, он заставит вас запускать бесконечное время, если s заполнено значением, отличным от "end".

Возможно, вам захотелось чего-то большего:

for (String s; (s = in.nextLine()).equals("end"); i++) 
{
    System.out.println("The value of i is: " + i + " and you entered " + s);
}

Ответ 7

Этот подход слишком плох.

Данный код: -

Scanner in = new Scanner(System.in);
int i = 0;
for (String s = in.next(); !s.equals("end"); i++) 
{
    System.out.println("The value of i is: " + i + " and you entered " + s);
}

Первая часть цикла for выполняется только один раз в жизни.

String s = in.next() //Execute only once in life

Вторая часть цикла for никогда не будет истинна, потому что входная консоль никогда не позволит ввести второй вход.

!s.equals("end")//2nd part

Эта программа никогда не позволит вводить второй вход с консоли, потому что in.next() будет выполняться только один раз. И токен выхода для этого цикла - "конец", который невозможно ввести после первого ввода.

Этот тип циклов должен быть реализован циклом while.

Scanner in = new Scanner(System.in);
while(in.hasNext()){
String yourdata=in.next();
if(yourdata.equals("end")){
//Stop the loop 
}
//Do you code here
}

Ответ 8

Это плохая практика, потому что она завершается только в том случае, если следующий полученный токен "завершен". Это не рассматривает ситуацию. например конец входного потока.

Итак, когда поток заканчивается и нигде не появляется "конец", вы получаете s=null и NullPointerException в s.equals("end").

Вы можете исправить это, например. изменив условие на in.hasNext() && !"end".equals(s).

Также s никогда не изменяется после его инициализации.

Ответ 9

Если вопрос "зачем его переписывать", то ответ в основном, как указывали другие, указывает на то, что он в настоящее время является бесконечным циклом, а также что он не очень читабельен, поскольку он стоит. Лично я бы переписал его как цикл while, о котором несколько других уже указывали, как это сделать, поскольку это делает ваши намерения более понятными, чем цикл for с счетчиком, который подсчитывает до бесконечности. Кто-то, кто не знаком с тем, как должен работать код, может легко путать бесконечное приращение, чтобы быть надзором программиста, который его написал.

Ответ 10

Строка s никогда не изменяется. Цикл никогда не заканчивается. Что об этом:

    Scanner in = new Scanner(System.in);
    String s = "";
    for (int i = 0 ; !s.equals("end"); i++) {
        s = in.next();
        System.out.println("The value of i is: " + i + " and you entered "
                + s);
    }

Ответ 11

Другие упоминали, что цикл не заканчивается, потому что вы не меняете значение s, поэтому цикл никогда не заканчивается. Возможно, это и есть то, чего хотел ваш профессор, и это может быть не так. Плохой код - это плохая практика, как правило, но есть и другие причины, по которым это плохая практика.

Что мне показалось мне плохой практикой, и то, что мог предположить профессор, - это использование цикла for здесь. Как сказал мне мой профессор: "Для циклов, когда вы знаете, когда вы хотите, чтобы код заканчивался, а петли - когда вы не знаете, когда вы хотите, чтобы код закончился". Поэтому, если у вас есть итеративный i, такой как этот код:

for(i = 0; i<100; i++)
{
    ...
}

В этом коде вы знаете, что хотите итерации я от 0 до 100. Цикл while - это то, что вы хотели бы использовать в ситуации, обсуждаемой вашим профессором.

int counter;
while(*(str+counter))
    counter++;

Вы понятия не имеете, когда цикл закончится, потому что вы не знаете, сколько времени занимает str, но вы знаете, что когда-нибудь он достигнет нулевого указателя, и цикл завершится. Обычно это лучшая практика.

Итак, для кода, опубликованного вашим профессором, вы можете выглядеть так:

Scanner in = new Scanner(System.in);
int i = 0;
while(!s.equals("end"))
{
    i++;
    String s = in.next();
    System.out.println("The value of i is: " + i + " and you entered " + s);
}

Ответ 12

Я думаю, что это плохая практика, потому что нет необходимости в цикле for. В этом случае я считаю это бесполезным. Это может быть только так:

Scanner in = new Scanner(System.in);
String s = in.next();
if (!s.equals("end"))
{
    System.out.println("You have enetered" + s);
}

Смотрите, нет необходимости в цикле. У петли, которую вы делали, было сложнее, чем должно было быть. Я всегда думал, что все должно быть таким простым, насколько они могут быть, если они не требуют сложностей. Циклы for должны использоваться только тогда, когда у вас есть несколько действий, которые вы хотите выполнить. В приведенном выше случае происходит только одно: оператор println, поэтому нет необходимости в цикле. Это ненужно...

Кроме того, цикл никогда не заканчивается. Так что это тоже, но это просто неисправный код. Это не то, почему это плохая практика. Это плохая практика из-за ненужного использования цикла for. Это также ошибочно, потому что код неправильный. Итак, с этим кодом происходит две разные вещи.

Ответ 13

Это не в хорошей практике из-за двух вещей:

  • для циклов предназначены для итерации по набору данных
  • цикл for состоит из начального состояния итератора, условия цикла и функции итерации, которые связаны

Оператор for просто смешивает две разные данные (поток и счетчик). Даже если это действительно работает, это не очень хорошая практика.

Ответ 14

Я бы просто оставил комментарий, но у меня пока нет репутации. То, что я не видел, объясняет, почему ваша стоимость не меняется.

В типичном цикле для:

for(a=1; a<=10; a+=1) {body}

начальная фраза "a = 1", ТОЛЬКО выполняется один раз в качестве инициализации.

третья фраза "a + = 1" выполняется один раз в конце каждого цикла, пока...

вторая фраза, 'a >= 10', оценивает значение false.

поэтому цикл для будет представлен в "psuedo-code" примерно так:

    a=1         // first phrase
:LoopLabel
    {body}
    a+=1        // third phrase
    if (a<=10)  // second phrase (boolean evaluation)
        then goto LoopLabel

Аналогично, ваш пример в подобном псевдокоде может выглядеть так:

    Scanner in = new Scanner(System.in);
    int i = 0;
    String s = in.next()
:LoopLabel
    {
        System.out.println("The value of i is: " + i + " and you entered " + s);
    }
    ++i
    if (!s.equals("end"))
        goto LoopLabel

Итак, причина, по которой ваша программа была бесконечным циклом, заключалась в том, что значение 's' было установлено только при входе в ваш цикл и никогда не изменялось при каждом выполнении цикла, как это было бы наиболее вероятно.

Ответ 15

for (int i = 0; in.hasNext(); i++) {
    String s = in.next();
    if (s.equals("end")) {
        break;
    }
    ...

Бесконечный цикл или цикл no (когда s изначально "завершен" ).

Ответ 16

Несколько ответов, приведенных выше, являются правильными, чтобы сказать, что написанное вами представляет собой бесконечный цикл. Но я хотел уточнить, почему это бесконечный цикл. Цикл для, который вы используете, отличается от другой формы, о которой вы можете подумать:

String[] stringArray = { "1", "2", "3" };
for (String s : stringArray) {
   System.out.println(s);
}

В этом случае переменная s инициализируется следующим значением из вашей коллекции или массива на каждой итерации. Но эта форма цикла для работает с коллекциями и массивами и не может использоваться с итераторами, такими как класс Сканер.

Форма цикла для, который вы используете, отличается тем, что предложение инициализации (где у вас есть String s = in.next()) вызывается ТОЛЬКО первый раз через цикл. s устанавливается в первый раз, а затем не изменяется.

Вы можете переписать следующим образом:

int i = 0;
for (String s = in.next(); !s.equals("end"); s = in.next()) {
    System.out.println("The value of i is: " + i++ + " and you entered " + s);
}

Но еще одна плохая вещь в том, что нет нулевой или конечной проверки. Возможно, если вы вряд ли закончите строки, прежде чем найдете тот, который будет равен "концу". Если это произошло, тестовое предложение для (среднее) даст вам NullPointerException, когда оно попытается вызвать equals() метод. Это определенно плохая практика. Я, вероятно, переписал бы вот так:

int i = 0;
while (in.hasNext()) {
    String s = in.next();
    if (s.equals("end")) {
        break;
    }
    System.out.println("The value of i is: " + i++ + " and you entered " + s);
}

Если вам действительно нужен цикл для, а не , а, то лучше сделать это:

int i = 0;
for (Scanner in = new Scanner(System.in); in.hasNext();) {
    String s = in.next();
    if (s.equals("end")) {
        break;
    }
    System.out.println("The value of i is: " + i++ + " and you entered " + s);
}

Последний вариант, который сохраняет тест против строки в тестовом предложении, будет выглядеть следующим образом:

int i = 0;
String s = "";
for (Scanner in = new Scanner(System.in);
     in.hasNext() && !s.equals("end"); 
     s = in.next()) {
    System.out.println("The value of i is: " + i++ + " and you entered " + s);
}

Вы также можете добавить нулевую проверку до s.equals("end") для полной безопасности.

Ответ 17

Это не очень хорошая практика, потому что вы сравниваете String s с String, но вы не сравниваете значение, вы сравниваете позицию памяти значения s.