Как я могу удалить while (true) из моего цикла в Java? - PullRequest
3 голосов
/ 04 октября 2009

Я слышал, что использование while (true) - плохая практика программирования.

Итак, я написал следующий код для получения некоторых чисел от пользователя (со значениями по умолчанию). Однако, если пользователь введет -1, он выйдет из программы.

Как это должно быть написано тогда без времени (правда)? Я могу придумать условие отключения цикла while, которое сразу же перехватит, не продолжая до следующей итерации?

Вот как у меня сейчас:

 public static void main(String[] args)
    {
        System.out.println("QuickSelect!");

        while (true)
        {
            System.out.println("Enter \"-1\" to quit.");

            int arraySize = 10;
            System.out.print("Enter the size of the array (10): ");
            String line = input.nextLine();
            if (line.matches("\\d+"))
            {
                arraySize = Integer.valueOf(line);
            }

            if (arraySize == -1) break;

            int k = 1;
            System.out.print("Enter the kth smallest element you desire (1): ");
            line = input.nextLine();
            if (line.matches("\\d+"))
            {
                k = Integer.valueOf(k);
            }

            if (k == -1) break;

            List<Integer> randomData = generateRandomData(arraySize, 1, 100);

            quickSelect(randomData, k);
        }
    }

Ответы [ 8 ]

10 голосов
/ 04 октября 2009

while (true) в порядке. Держи это.

Если бы у вас было более естественное условие завершения, я бы сказал, что оно будет использоваться, но в этом случае, как показывают другие ответы, избавление от while (true) усложняет понимание кода.

3 голосов
/ 04 октября 2009

Существует школа мысли с одним входом и одним выходом (SESE), которая предлагает не использовать break, continue или злоупотреблять исключениями, чтобы сделать то же самое для некоторой ценности злоупотребления). Я считаю, что идея здесь не в том, что вы должны использовать некоторую вспомогательную переменную-флаг, а в том, чтобы четко указать постусловие цикла. Это делает возможным рассуждать о цикле. Очевидно, используйте разумную форму рассуждений, поэтому она непопулярна среди немытых масс (таких как я).

public static void main(String[] args) {
    ...
    do {
        ...
        if (arraySize == -1)  {
            ...
            if (k != -1) {
                ...
            }
        }
    } while (arraySze == -1 || k == -1);
    ...
}

Реальный код будет более сложным, и вы естественным образом (!) Разделите входную, выходную и основную "бизнес" логику, что упростило бы понимание происходящего.

2 голосов
/ 04 октября 2009
    bool exit = false;
while (!exit) {
    ...
    ...
    if (k == -1) {
        exit = true;            
    }
    else {         
        List <Integer> ....;
        quickselect(.......);
    }
}

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

1 голос
/ 04 октября 2009

Хотя такой цикл технически не является ошибочным, некоторые люди утверждают, что он не так удобен для чтения, как показано ниже:

bool complete = false;

while (!complete)
{

    if (arraySize == -1)
    {
        complete = true;
        break;
    }
}

Кроме того, иногда хорошей идеей является наличие счетчика цикла безопасности, который проверяет, чтобы убедиться, что цикл не прошел, скажем, 100 миллионов итераций или какое-то число, намного большее, чем вы ожидаете для тела цикла. Это безопасный способ убедиться, что ошибки не приводят к зависанию вашей программы. Вместо этого вы можете дать пользователю дружественное сообщение «Извините, но вы обнаружили ошибку ... Программа теперь завершит работу…», где для «завершения» установлено значение «истина», и вы завершаете программу или выполняете дополнительную обработку ошибок. Я видел это в рабочем коде, и может быть, а может и не быть тем, что вы бы использовали.

0 голосов
/ 22 февраля 2012

while (true) {} очень полезно в некоторых сценариях. Вы заслуживаете того, чтобы спрыгнуть с 1000-этажного здания, если вы говорите, что его неправильно использовать ....

0 голосов
/ 04 октября 2009

Проблема в том, что вы делаете очень много в этом цикле, а не разделяете функциональность на простые методы.

Если вы хотите придерживаться процедурного подхода, вы можете переместить чтение размера массива и k в отдельные методы и использовать тот факт, что результатом присваивания является присвоенное значение:

    for (int arraySize; ( arraySize = readArraySize ( input ) ) != -1;) {
        final int k = readKthSmallestElement ( input );

        List<Integer> randomData = generateRandomData(arraySize, 1, 100);

        quickSelect(randomData, k);
    }

Однако это все-таки немного уродливо и плохо инкапсулировано. Поэтому вместо двух != -1 тестов для отдельных переменных инкапсулируйте arraySize, k и randomData в объекте и создайте метод, который считывает данные из ввода и возвращает либо объект QuickSelect или null, если пользователь выходит:

    for ( QuickSelect select; ( select = readQuickSelect ( input ) ) != null; ) {
        select.generateRandomData();
        select.quickSelect();
    }        

Возможно, вы даже захотите перейти к следующему этапу создания последовательности объектов QuickSelect из входных данных, каждый из которых инкапсулирует данные за одну итерацию:

    for ( QuickSelect select : new QuickSelectReader ( input ) ) {
        select.generateRandomData();
        select.quickSelect();
    }        

где QuickSelectReader реализует Iterable, а итератор имеет логику для создания объекта QuickSelect, который инкапсулирует arraySize, k, список и операцию быстрого выбора. Но в итоге получается гораздо больше кода, чем процедурных вариантов.

Я бы сделал это, только если бы хотел использовать его где-то еще; это не стоит усилий, чтобы сделать main () красивым.

Также обратите внимание, что "-1" не соответствует регулярному выражению "\\d+", поэтому у вас действительно есть бесконечный цикл.

0 голосов
/ 04 октября 2009

while (true) здесь совершенно нормально, поскольку условие действительно "пока пользователь не хочет выходить"!

В качестве альтернативы вы можете запросить оба входа в одной строке, чтобы упростить логику, и использовать «q» для выхода: это позволяет вам изменить цикл на «while (! Line.equals (« q »))» ».

0 голосов
/ 04 октября 2009

Если вам действительно не нравится while(true), вы всегда можете выбрать for(;;). Я предпочитаю последнее, потому что оно кажется менее избыточным.

...