Непрерывная средняя программа

Я создаю программу, которая усредняет четыре числа - три из файла и один из пользовательского ввода. Достаточно просто. Но поймать, профессор собирается сознательно пытаться нарушить программу.

Я бы советовал в любом случае, но помните, что основное внимание уделяется надежности.

import java.util.*;
import java.io.*;

public class average {
    public static void main (String[] args) throws IOException{
        double[] nums = new double[4];
        nums = inputHandler();
        System.out.println("Average " + findAverage(nums));

        System.out.println("End Program.");
    }

    public static double findAverage(double[] nums){
        double average = 0.0;
        final double N = 4.0;

        for(int i = 0; i < N; i++){
            average += nums[i] / N;
        }

        return average;
    }

    public static double[] inputHandler() throws IOException{
        Scanner input = new Scanner(System.in);
        double[] nums = new double[4];
        double[] fileNums = new double[3];

        // get first three numbers from file
        System.out.print("Enter the name of the file which contains the first three numbers: ");
        fileNums = fileInput(input.nextLine());
        System.out.println();

        // copy numbers from fileNums[] to nums[]
        for(int i = 0; i < 3; i++){
            nums[i] = fileNums[i];
        }

        //get last number from user input
        System.out.print("Enter the fourth number: ");
        nums[3] = userInput(input.nextLine());
        System.out.println();

        input.close();

        return nums;
    }

    public static double[] fileInput(String fileName) throws IOException{
        double[] nums = new double[3];

        System.out.println();

        File file = new File(fileName);

        if(!file.isFile()){
            System.err.println("ERROR: File does not exist.");
            System.exit(-1);
        }

        System.out.println(fileName + ":");

        Scanner input = new Scanner(file);
        String cur = "";

        for(int i = 0; i < 3; i++){

            if(!input.hasNext()){
                System.err.println("ERROR: File does not contain enough numbers.");
                System.exit(-1);
            }

            cur = input.next();

            System.out.println("Number " + (i + 1) + ": " + cur);

            if(cur.matches("-?\\d+(\\.\\d+)?")){ //regex ensures numeric input
                if(Double.parseDouble(cur) < 1.7e308){
                    nums[i] = Double.parseDouble(cur);
                }
                else{
                    System.err.println("ERROR: Number too large");
                    System.exit(-1);
                }
            }
            else{
                System.err.println("ERROR: Non numeric input. Please check your file and try again.");
                System.exit(-1);
            }
        }

        input.close();

        return nums;
    }

    public static double userInput(String userInput){
        double num = 0;

        if(userInput.matches("-?\\d+(\\.\\d+)?")){ //regex ensures input is numeric
            num = Double.parseDouble(userInput);
        }
        else{
            System.err.println("ERROR: Non numeric input. Please check your file and try again.");
            System.exit(-1);
        }

        return num;
    }
}
29 голосов | спросил PsylentKnight 17 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 17 Sep 2015 03:10:48 +0300 2015, 03:10:48

6 ответов


22

Сначала используйте try /catch блоки вокруг частей, которые могут генерировать исключения. Например, что происходит, когда IOException вызывается файлом, возможно потому, что данные повреждены и файл существует, но не может быть открыт?

Во-вторых, я не знаю, что представляет собой сбой, но ошибка закрытия приложения - это ошибка в моей книге:

if(!file.isFile()){
    System.err.println("ERROR: File does not exist.");
    System.exit(-1);
}

В-третьих, @SirPython прав - используйте встроенный метод для чтения вашего номера. Существуют встроенные функции для чтения как double s, так и int s, в зависимости от вашей программы.

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

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

ответил Hosch250 17 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 17 Sep 2015 03:33:46 +0300 2015, 03:33:46
13

Программа не может быть полностью нерушимой.

for(int i = 0; i < N; i++){
    average += nums[i] / N;
}

for(int i = 0; i < N; i++){
    total += nums[i];
}
average = total / N;

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

  1. Используемый вами метод: разделите каждое число на размер списка, а затем добавьте его в текущую сумму. Это невосприимчиво к ошибкам переполнения, но более уязвимо к ошибкам округления, чем метод # 2, особенно с исключительно небольшими числами (если профессор вводит четыре копии Double.MIN_VALUE, код вернет 0, когда он должен возвращать Double.MIN_VALUE).
  2. Добавьте все числа и разделите общее количество на размер списка. Это устойчиво к ошибкам округления, но уязвимо к ошибкам переполнения (если профессор вводит четыре копии Double.MAX_VALUE), он переполняется, когда он должен возвращать Double.MAX_VALUE). , Это также быстрее, чем метод # 1, но в большинстве ситуаций разница в скорости не имеет значения.

Правильный выбор зависит от того, важны ли ошибки переполнения или ошибки округления.

ответил Mark 17 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 17 Sep 2015 11:32:41 +0300 2015, 11:32:41
11
public static double userInput(String userInput){
    // ...
    if(userInput.matches("-?\\d+(\\.\\d+)?")){
        // ...
    } else {
        System.err.println("ERROR: Non numeric input.Please check your file and try again.");
        System.exit(-1);
    }
    // ...
}

Мне было предложено ввести номер! Возможно, я ошибался, но почему он просит меня проверить мой файл?

Это проблема с копированием и вводом кода ... Если у вас есть метод, который принимает double из экземпляра Scanner и настраиваемого сообщения об ошибке, вы сможете обойти эту проблему. Например:

/**
 * Gets the number of double values from the scanner.
 *
 * @param scanner      the {@link Scanner} instance to take from
 * @param times        the number of values required
 * @param errorMessage the error message to use if not enough values
 * @return a double array of the required size
 * @throws {@link IllegalArgumentException} if not enough values
 */
private static double[] getInputs(Scanner scanner, int times, String errorMessage) {
    double[] results = new double[times];
    int i = 0;
    for (; i < times && scanner.hasNextDouble(); i++) {
        results[i] = scanner.nextDouble();
    }
    if (i != times) {
        throw new IllegalArgumentException(errorMessage);
    }
    return results;
}

Кроме того, чтобы ответить @ Hosch250 , надежность программы это его способность восстанавливаться после ошибок ... то, что вы сделали здесь, это только обработка их сообщениями об ошибках, но вы не пытались восстановить . Возможно, это тоже стоит задуматься, например, вы ожидаете, что будете предлагать четвертое число, пока не будет принято действительное значение double?

ответил h.j.k. 17 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 17 Sep 2015 04:49:55 +0300 2015, 04:49:55
10

Бесполезный код

В первой строке кода я уже видел проблему:

    double[] nums = new double[4];
    nums = inputHandler();

Почему вы выделяете массив для nums, а затем сразу переназначаете его на что-то еще? Первая строка полностью бесполезна. Это должно быть:

    double[] nums = inputHandler();

Вы сделали ту же ошибку в inputHandler() с помощью fileNums.

Средняя функция

Есть несколько вещей, которые мне не нравятся в этой функции:

public static double findAverage(double[] nums){
    double average = 0.0;
    final double N = 4.0;

    for(int i = 0; i < N; i++){
        average += nums[i] / N;
    }

    return average;
}
  1. Вы используете double, N, как лимит цикла.
  2. Разделяйте один раз за цикл, а не только один раз.

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

public static double findAverage(double[] nums){
    double sum = 0.0;
    final int numElements = nums.length;

    for(int i = 0; i < numElements; i++) {
        sum += nums[i];
    }

    return sum / numElements;
}
ответил JS1 17 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 17 Sep 2015 07:49:46 +0300 2015, 07:49:46
10

Вы выполняете way слишком много работы для проверки ввода; Scanner уже имеет метод чтения удвоений: java.util.Scanner.nextDouble .

Вместо того, чтобы делать все это безумное регулярное выражение, вы должны просто использовать это вдоль стороны java.util.Scanner.hasNextDouble для получения ввода.

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


В Java, это плохая практика, просто сказать, например, что метод собирается бросить IOException, фактически не делая никакой обработки. Фактически, если вы используете IDE, ваша среда IDE, скорее всего, вызовет раздражение.

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

Просто вставьте метод try/catch в метод и попросите метод обработать исключение, а не использовать этот метод.


final double N = 4.0;

Если это постоянное значение, лучше применить это свойство к свойству класса и объявить его следующим образом:

public static final double N = 4.0;

У вас есть этот номер 3, отображающийся во многих местах вашего кода. Кажется, что он неловко сидит там; он должен быть в константе , аналогичный выше.

ответил SirPython 17 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 17 Sep 2015 03:24:13 +0300 2015, 03:24:13
3

Если пользователь подключает поток символов, который не содержит новую строку для stdin, сканер, вероятно, просто продолжит чтение. (Я тестировал файл размером 9 МБ и читал все это.)

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

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

ответил Anonymous Coward 18 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 18 Sep 2015 03:17:23 +0300 2015, 03:17:23

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132