Is it possible to use try with resources along with an input stream?

て烟熏妆下的殇ゞ 提交于 2021-02-08 11:47:19

问题


When implementing try with resources I am creating a Scanner object via Scanner sc = new Scanner(System.in) within () of the try statement. In the try block, I am prompting the user to enter a numeric value, reading it via sc.nextLine() and utilizing parseDouble to convert it to a method. I utilize a do-while loop to re-prompt the user to enter a value if an invalid value was entered initially.

However, if the user enters an invalid value, the input stream closes, NumberFormatException is caught but during the second iteration of the do-while loop, a 'No line found' NoSuchElementException is thrown and infinitely thereafter due to the 'stream closed' java.io.IOException. Is there a way to circumvent this while utilizing try with resources?

public static void main(String[] args) {

  int x = 1;

  do {
      try (Scanner sc = new Scanner(System.in)) {
          System.out.print("Enter a numeric value: ");
          String input1 = sc.nextLine();
          Double d1;
          d1 = Double.parseDouble(input1);
          System.out.print("Enter a numeric value: ");
          String input2 = sc.nextLine();
          Double d2;
          d2 = Double.parseDouble(input2); 
          System.out.print("Choose an operation (+ - * /): ");
          String input3 = sc.nextLine();
          //sc.close();

          switch (input3) {
              case "+":
                  Double result = d1 + d2;
                  System.out.println("The answer is " + result);
                  break;
              case "-":
                  Double result1 = d1 - d2;
                  System.out.println("The answer is " + result1);
                  break;
              case "*":
                  Double result2 = d1 * d2;
                  System.out.println("The answer is " + result2);
                  break; 
              case "/":
                  Double result3 = d1 / d2;
                  System.out.println("The answer is " + result3);
                  break;
              default:
                  System.out.println("Unrecognized Operation!");
                  break;
          }
          x++;        
      } 
      catch (NumberFormatException e){ 
          System.out.println("Number formatting exception "+e.getMessage());
          System.out.println("Enter a proper value");    
      }
      catch (Exception e1){
          System.out.println("Arbitrary error encountered"+e1.getMessage());
      }
  }
  while(x==1);

}

回答1:


As already said by others in the comments, you shouldn’t use try-with-resource with a resource you didn’t open yourself, especially not with System.in, which should never be closed by an application.

Besides that, you should prefer testing conditions beforehand, instead of catching exceptions. Further, try to avoid code duplication and you’ll end up at a much simpler solution:

public static void main(String[] args) {
    Scanner sc = new Scanner(System.in).useDelimiter("\\R");
    System.out.print("Enter first numeric value: ");
    double d1 = getDouble(sc);
    System.out.print("Enter second numeric value: ");
    double d2 = getDouble(sc);
    System.out.print("Choose an operation (+ - * /): ");
    while(!sc.hasNext("[-+*/]")) {
      System.out.println(sc.next()+" is not a valid operation");
    }
    String operation = sc.next();

    double result;
    switch (operation) {
        case "+": result = d1 + d2; break;
        case "-": result = d1 - d2; break;
        case "*": result = d1 * d2; break; 
        case "/": result = d1 / d2; break;
        default:
            throw new AssertionError("should not happen due to pretest");
    }
    System.out.println(d1+operation+d2);
    System.out.println("The answer is " + result);
}    
private static double getDouble(Scanner sc) {
    while(!sc.hasNextDouble()) {
        System.out.println(sc.next()+" is not a number");
    }
    return sc.nextDouble();
}

This solution uses hasNextDouble() to ask the scanner whether the next token has a double format and only if that’s acknowledged, the application will fetch it via nextDouble(). Otherwise, it uses next() to fetch the invalid token, which serves both, reporting and removing it from the unprocessed input. Likewise, hasNext("[-+*/]") checks whether the input matches one the the supported four operators.

Since the compiler doesn’t understand that now only one of the four valid inputs may occur, we have to put a throwing statement to the default case of the switch, as otherwise the compiler will say that result may not have been initialized. We could initialize result to a default value instead, but it’s better to have a strong signal if the program flow doesn’t work as expected, instead of printing a default value as wrong result.

The Scanner uses configurable delimiters to decide what constitutes a token, so this solution uses useDelimiter("\\R") to use line breaks as delimiter, to consider each line a token, like your original code. So the Pattern class for a full description of the syntax.



来源:https://stackoverflow.com/questions/57969142/is-it-possible-to-use-try-with-resources-along-with-an-input-stream

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!