是否可以将 try with resources 与输入流一起使用?
Is it possible to use try with resources along with an input stream?
在使用资源实现尝试时,我在 try 语句的 () 内通过 Scanner sc = new Scanner(System.in)
创建一个 Scanner 对象。
在 try 块中,我提示用户输入一个数值,通过 sc.nextLine()
读取它并利用 parseDouble
将其转换为一个方法。
如果最初输入的值无效,我会使用 do-while 循环重新提示用户输入值。
但是,如果用户输入了无效值,输入流将关闭,NumberFormatException
被捕获,但在 do-while 循环的第二次迭代期间,将抛出 'No line found' NoSuchElementException 并无限此后由于'stream closed'java.io.IOException。
有没有办法在利用 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);
}
正如其他人在评论中已经说过的那样,您不应该将 try-with-resource 与您自己未打开的资源一起使用,尤其是 System.in
,它不应该被关闭申请。
除此之外,您应该更喜欢事先测试条件,而不是捕获异常。此外,尽量避免代码重复,您最终会得到一个更简单的解决方案:
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();
}
此解决方案使用 hasNextDouble()
询问扫描器下一个令牌是否具有双重格式,只有在确认后,应用程序才会通过 nextDouble()
获取它。否则,它使用 next()
来获取无效令牌,该令牌服务于两者,报告并将其从未处理的输入中删除。同样,hasNext("[-+*/]")
检查输入是否与支持的四个运算符中的一个匹配。
由于编译器不理解现在可能只有四个有效输入中的一个出现,我们必须在 switch
的 default
情况下放置一个抛出语句,否则编译器会说 result
可能尚未初始化。我们可以将 result
初始化为默认值,但如果程序流程未按预期运行,最好有一个强烈的信号,而不是将默认值打印为错误结果。
Scanner
使用可配置的分隔符来决定什么构成令牌,因此此解决方案使用 useDelimiter("\R")
使用换行符作为分隔符,将每一行视为一个令牌,就像您的原始代码一样。所以 Pattern
class 语法的完整描述。
在使用资源实现尝试时,我在 try 语句的 () 内通过 Scanner sc = new Scanner(System.in)
创建一个 Scanner 对象。
在 try 块中,我提示用户输入一个数值,通过 sc.nextLine()
读取它并利用 parseDouble
将其转换为一个方法。
如果最初输入的值无效,我会使用 do-while 循环重新提示用户输入值。
但是,如果用户输入了无效值,输入流将关闭,NumberFormatException
被捕获,但在 do-while 循环的第二次迭代期间,将抛出 'No line found' NoSuchElementException 并无限此后由于'stream closed'java.io.IOException。
有没有办法在利用 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);
}
正如其他人在评论中已经说过的那样,您不应该将 try-with-resource 与您自己未打开的资源一起使用,尤其是 System.in
,它不应该被关闭申请。
除此之外,您应该更喜欢事先测试条件,而不是捕获异常。此外,尽量避免代码重复,您最终会得到一个更简单的解决方案:
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();
}
此解决方案使用 hasNextDouble()
询问扫描器下一个令牌是否具有双重格式,只有在确认后,应用程序才会通过 nextDouble()
获取它。否则,它使用 next()
来获取无效令牌,该令牌服务于两者,报告并将其从未处理的输入中删除。同样,hasNext("[-+*/]")
检查输入是否与支持的四个运算符中的一个匹配。
由于编译器不理解现在可能只有四个有效输入中的一个出现,我们必须在 switch
的 default
情况下放置一个抛出语句,否则编译器会说 result
可能尚未初始化。我们可以将 result
初始化为默认值,但如果程序流程未按预期运行,最好有一个强烈的信号,而不是将默认值打印为错误结果。
Scanner
使用可配置的分隔符来决定什么构成令牌,因此此解决方案使用 useDelimiter("\R")
使用换行符作为分隔符,将每一行视为一个令牌,就像您的原始代码一样。所以 Pattern
class 语法的完整描述。