项目场景:
编写氪金游戏,充值抽卡系统的代码,将Scanner类中的创建,和关闭Scanner对象,同时写进了for循环内,导致主线程异常。
问题描述
半成品的充值抽卡代码:
import java.util.Scanner; public class ChouKa { private static int yuanShi=0; public static void main(String[] args) { for(int j=0;j<10;j++) { Scanner sc=new Scanner(System.in); //导致BUG的代码 System.out.println("您是否要充值?(true or false)"); boolean chongZhi=sc.nextBoolean(); if(chongZhi==true){ System.out.println("请输入您的充值金额(元)"); int money=sc.nextInt(); int yuanShiC=money*10; System.out.println("邮箱提醒:到账原石"+yuanShiC); yuanShi+=yuanShiC; } System.out.println("原石:"+yuanShi); sc.close(); //导致BUG的代码 } } }
报错如下:
编写过程期间,循环充值抽卡代码。第一次输入充值金额,正常运行代码;到第二次运行时,用户不能输入数据,无法运行代码,报错显示,主线程异常。
原因分析:
在循环中创建和关闭Scanner对象,可能会导致主线程异常
第一,Scanner是一个阻塞式IO操作,Scanner对象在读取用户输入时,会导致主线程阻塞,程序停止继续执行,流正在等待来自用户的输入,例如从键盘读取输入。在这种情况下,流将阻塞
第二,用户输入完毕内容,关闭Scanner对象,它也关闭了底层输入源,例如文件或流。如果在循环的下一次迭代中创建了一个新的Scanner对象,但是输入源已经关闭,那么在对新的Scanner对象调用next()时可能会导致抛出异常
往深了讲,原因是源码中的nextBoolean()方法只读取布尔值,而不使用留在输入缓冲区中的换行字符(\n)。当程序执行到循环的下一个迭代并创建一个新的Scanner对象时,nextInt()方法将读取前一个迭代中留在输入缓冲区中的换行符,而不是等待来自用户的新输入。这将导致程序跳过用户输入的下一个提示,直接进入下一个迭代,从而用户无法输入,代码无法继续运行,主线程发生异常。
弊端:在循环中反复创建和关闭Scanner对象,相比在循环过程之外进行此操作,计算机操作更复杂,运行内存和时间占用的更多,同时系统反应的会更慢
因此,在循环中应该避免创建和关闭Scanner对象。最佳实践是在循环外创建Scanner对象,然后在循环中重复使用该对象,以避免阻塞主线程