как поймать NoSuchElementException? - PullRequest
4 голосов
/ 15 апреля 2011

Мое задание для класса - написать программу, в которой пользователь вводит набор числовых значений. Если пользователь вводит значение, которое не является числом, предполагается, что программа предоставит пользователю 2 секунды для правильного ввода числа, и после этих двух случаев прекратите запрашивать ввод и напечатайте сумму всех введенных значений до сих пор. .

Мой код работает не совсем правильно. Когда вводится первое не-число, программа выполняет код в блоке catch один раз, печатает строку «gimme input» в начале блока try, но затем сразу выполняет код в блоке catch снова, не дожидаясь, пока пользователь введет другой номер.

Просматривая мой учебник на предмет подсказок, я заметил следующую строку: «NoSuchElementException не перехватывается ни одним из предложений catch. Исключение остается выброшенным до тех пор, пока оно не будет перехвачено другим блоком try или основным методом заканчивается. "

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

а) Как мне обойти это для целей данного задания?

b) Что именно означает, что исключение не перехватывается предложением catch? Разве не для этого существуют предложения catch? Мне действительно нужно решение моего задания, но я также хочу понять , почему так оно и есть, если возможно.

Спасибо за любую помощь!

import java.util.InputMismatchException;
import java.util.NoSuchElementException;
import java.util.ArrayList;
import java.util.Scanner;

public class NotANumber {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.println("This program computes the sum of any number of real numbers. When you are done entering values, enter something other than a real number twice in a row.\n");

        ArrayList<Double> numbers = new ArrayList<Double>();

        int count = 0;
        while (count < 2) {
            try {
                System.out.println("Please enter a floating point number: ");
                double newNumber = in.nextDouble();
                numbers.add(newNumber);
                count = 0;
            }
            catch (NoSuchElementException exception) {
                System.out.println("The value entered was not correctly specified. All values must be integers or floating point values.");
                count++;
            }
        }

        if (!numbers.isEmpty()) {
            double sum = 0;
            for (Double each : numbers) {
                sum = sum + each;
            }
            System.out.println("The sum is " + sum);
        }
        else {
            System.out.println("There is no sum as no correctly specified values were entered.");
        }

    }
}

Ответы [ 4 ]

4 голосов
/ 15 апреля 2011

Пока что забудьте о перехвате исключения (это не то, что вы хотите сделать!).Что вы хотите сделать, это добавить вызовы типа: s.hasDouble () перед вызовом s.nextDouble ().

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

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

Для исключений компилятор говорит вам, что вы должны с ними справиться, вы делаете что-то вроде:

try
{
    foo();
}
catch(final IOException ex)
{
    // do something smarter here!
    ex.printStackTrace();
}

В этомкод, foo () объявляется примерно так:

public void foo() 
    throws IOException 
{
   // ... code ...
}

IOException является проверенным исключением (RuntimeException, также называемое непроверенными исключениями, не должно быть перехвачено, проверенные исключения должны быть перехвачены ... хорошо, вы можете сделать другоечто-то непонятное, но пока не беспокойтесь об этом)s.nextXXX().

1 голос
/ 15 апреля 2011

@ TofuBear заявляет:

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

Я думаю, что это слишком упрощение.

Это правда, что исключения, которые объявлены как проверенные исключения, ДОЛЖНЫ быть либопойман или объявлен как выброшенный в сигнатуре метода.

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

Однако в некоторых обстоятельствах явно необходимо их отловить.Например:

  try {
      System.out.println("Enter a lucky number!");
      String input = // get string from user
      int number = Integer.parseInt(input);
      ...
  } catch (NumberFormatException ex) {
      System.err.println("Bad luck!  You entered an invalid number");
  }

Если вы не поймали NumberFormatException ... что является исключением unchecked ... тогда вы не сможете распечататьсообщение и попросите пользователя повторить попытку.

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

  • Некоторые из стандартных могут указывать на неверный ввод от пользователя или клиента (например, NumberFormatException, IllegalArgumentException, ArithmeticException и т. Д.), Или они могут указывает на то, что конкретное приложение может восстановить или, по крайней мере, пытается диагностировать.

  • Я сталкивался со сторонними библиотеками, в которых разработчик испытывает отвращение к проверенным исключениям и объявляет все исключения библиотек непроверенными.(Плохой дизайн ИМО, но это случается ...)

Так что общее утверждение, что вы не должны ловить непроверенные исключения, является явно неправильным советом.


Однако вторая часть совета @ TofuBear действительна.(Вообще) лучше сделать тест, чтобы предотвратить возникновение ожидаемого исключения, чем выполнить действие и поймать исключение.(Код, как правило, проще и эффективнее ... хотя есть примеры счетчиков.)

В этом случае, если вы позвоните и протестируете hasNextDouble() до nextDouble(), вы можете избежать ошибки, которую выпытаемся справиться с помощью try / catch.

1 голос
/ 15 апреля 2011

Вы ошибаетесь: Scanner.nextDouble выдает NoSuchElementException, если ввод исчерпан, что вряд ли произойдет со стандартным вводом (вместо этого он заблокируется). Неверное значение приведет к InputMismatchException.

Однако я предполагаю, что nextDouble не удаляет ошибочное значение из потока при сбое. Вам нужно будет «очистить» входные данные в вашем улове, прежде чем возобновить чтение.

0 голосов
/ 18 марта 2014

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

for (ListIterator<Double> iter = numbers.listIterator(); iter.hasNext(); ) {
    if(iter.hasNext()) { // this return false in case of NoSuchElementException 
        // do your stuff here
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...