-3

My code below is supposed to be prompting the user for numbers. That part works, but after the user inputs the numbers, nothing happens. Why does the code just stop after the user inputs numbers?

public static void main(String[] args) {
    ArrayList<Double> inputs = getNumbers();
    int numberOfItemsToDrop = getLowestNumber();
    // ...
}


public static ArrayList<Double> getNumbers() {
    ArrayList<Double> inputs = new ArrayList <Double> ();

    Scanner in = new Scanner(System.in);
    System.out.println("Please enter five to ten numbers all on one line separated with spaces.");
    double vals = in.nextDouble();

    while (in.hasNextDouble()) {
        inputs.add(in.nextDouble());
    }

    return inputs;
}


public static int getLowestNumber() {
    int numberOfItemsToDrop = 0;

    System.out.println("How many of the lowest values should be dropped?");
    Scanner in = new Scanner(System.in);
    numberOfItemsToDrop = in.nextInt();

    return numberOfItemsToDrop;
}
Kevin J. Chase
  • 3,856
  • 4
  • 21
  • 43
slynnx
  • 13
  • 2
  • 2
    How are you finishing the input of doubles? The while will keep looping until you enter something that is not (part of) a double, e.g. some letter. – user85421 Jul 25 '17 at 22:59
  • A mostly unrelated problem: You never use `vals`, meaning the first `double` will vanish forever. – Kevin J. Chase Jul 26 '17 at 01:39

1 Answers1

0

You have two problems: an extra Scanner, and indistinguishable inputs.

In the order they appear in your code...

1. Dueling Scanners

As a general rule, you want only one Scanner per input stream. If the first Scanner "reads ahead" to fill its input buffer, those bytes will vanish forever when the Scanner gets garbage-collected. This typically leads to a NoSuchElementException when the next Scanner tries to read inputs that no longer exist.

Note that this is not the same as trying to read from a closed input stream (see "java.util.NoSuchElementException - Scanner reading user input") --- losing inputs can happen even when the input stream is still open.

A much better strategy is to create just one Scanner, and then pass it to each method that needs to read from it:

public static void main(final String[] args) {
    final Scanner in = new Scanner(System.in);  // The one and only.
    ArrayList<Double> inputs = getNumbers(in);
    int numberToDrop = getLowestNumber(in);
    // ...
}

2. Indistinguishable Inputs

Also, you need a way to determine the end of the floating-point data and the start of the integer. You can't do that with hasNextDouble, because an integer input like 3 is also a perfectly good double. Fortunately, you have already told the user that you will only read to the end of the line, and nextLine does exactly that.

I created a throw-away Scanner to read double values from the String returned by nextLine. (The new Scanner parser does not conflict with Scanner in, because they read from different sources.)

public static ArrayList<Double> getNumbers(final Scanner in) {
    System.out.println(
      "Please enter five to ten numbers all on one line " +
      "separated with spaces."
    );
    final String s = in.nextLine();
    final Scanner parser = new Scanner(s);
    ArrayList<Double> inputs = new ArrayList<>();
    while (parser.hasNextDouble()) {
        inputs.add(parser.nextDouble());
    }
    parser.close();
    return inputs;
}

I checked the input with hasNextInt and returned 0 if it wasn't a valid integer:

public static int getLowestNumber(final Scanner in) {
    System.out.println(
      "How many of the lowest values should be dropped?"
    );
    if (in.hasNextInt()) {
        return in.nextInt();
    }
    return 0;
}

I think both of the scanning methods should throw exceptions if they encounter bogus inputs, rather than trying to make do like this... The only thing worse than bogus data is a plausible result based on that bogus data.

Kevin J. Chase
  • 3,856
  • 4
  • 21
  • 43