Java贪吃蛇游戏高分更新功能崩溃问题求助
问题分析与解决:Java贪吃蛇高分更新崩溃问题
问题描述
用Java开发贪吃蛇游戏,需求是当applesEaten(本局得分)超过HighScore.txt中的现有高分时,更新该文件的记录。测试发现:
- 若本局得分未超过文件高分,游戏结束后正常显示得分与高分;
- 若本局得分超过现有高分,游戏崩溃,抛出
java.util.NoSuchElementException异常。
报错堆栈信息
Exception in thread "AWT-EventQueue-0" java.util.NoSuchElementException at java.base/java.util.Scanner.throwFor(Scanner.java:937) at java.base/java.util.Scanner.next(Scanner.java:1594) at java.base/java.util.Scanner.nextInt(Scanner.java:2258) at java.base/java.util.Scanner.nextInt(Scanner.java:2212) at GamePanel.highScoreChecker(GamePanel.java:138) at GamePanel.gameOver(GamePanel.java:203) at GamePanel.draw(GamePanel.java:84) at GamePanel.paintComponent(GamePanel.java:50) at java.desktop/javax.swing.JComponent.paint(JComponent.java:1119) at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5311) at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedImpl(RepaintManager.java:1657) at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1632) at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1570) at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1337) at java.desktop/javax.swing.JComponent._paintImmediately(JComponent.java:5259) at java.desktop/javax.swing.JComponent.paintImmediately(JComponent.java:5069) at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:879) at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:862) at java.base/java.security.AccessController.doPrivileged(AccessController.java:399) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86) at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:862) at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:835) at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:784) at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1898) at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716) at java.base/java.security.AccessController.doPrivileged(AccessController.java:399) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
核心问题代码
问题出在highScoreChecker()方法中,当更新高分后,复用了之前的fileByteStream来创建新的Scanner,而此时流已经读取完毕且未重置,导致读取失败:
public int highScoreChecker() { Scanner scnr = new Scanner(System.in); // 此处scnr未使用,可删除 FileInputStream fileByteStream = null; Scanner inFS = null; try { fileByteStream = new FileInputStream("HighScore.txt"); inFS = new Scanner(fileByteStream); prevHighScore = inFS.nextInt(); } catch (FileNotFoundException e) { e.printStackTrace(); } if (applesEaten > prevHighScore) { try { FileWriter myWriter = new FileWriter("HighScore.txt"); myWriter.write(applesEaten + ""); myWriter.close(); // 错误点:复用已读取过的fileByteStream,此时流已到末尾,无法读取新内容 inFS = new Scanner(fileByteStream); highScore = inFS.nextInt(); } catch (IOException e) { e.printStackTrace(); } } else { highScore = prevHighScore; } return highScore; }
解决方案
方案1:更新高分后直接使用当前applesEaten作为新高分
既然已经将applesEaten写入文件,新高分就是当前得分,直接赋值即可,无需重复读取文件:
public int highScoreChecker() { FileInputStream fileByteStream = null; Scanner inFS = null; prevHighScore = 0; // 默认初始高分0,防止文件不存在时变量未初始化 try { fileByteStream = new FileInputStream("HighScore.txt"); inFS = new Scanner(fileByteStream); if (inFS.hasNextInt()) { // 先判断是否有整数可读,避免文件为空时报错 prevHighScore = inFS.nextInt(); } } catch (FileNotFoundException e) { // 文件不存在时,默认高分0,后续会写入第一个得分 System.out.println("HighScore.txt不存在,将创建新文件"); } finally { // 关闭流,防止资源泄漏 if (inFS != null) { inFS.close(); } try { if (fileByteStream != null) { fileByteStream.close(); } } catch (IOException e) { e.printStackTrace(); } } if (applesEaten > prevHighScore) { try { FileWriter myWriter = new FileWriter("HighScore.txt"); myWriter.write(String.valueOf(applesEaten)); myWriter.close(); highScore = applesEaten; // 直接使用当前得分作为新高分 } catch (IOException e) { e.printStackTrace(); } } else { highScore = prevHighScore; } return highScore; }
方案2:重新打开输入流读取新高分
如果一定要从文件读取新高分,需要关闭旧流后重新创建新的FileInputStream:
public int highScoreChecker() { FileInputStream fileByteStream = null; Scanner inFS = null; prevHighScore = 0; try { fileByteStream = new FileInputStream("HighScore.txt"); inFS = new Scanner(fileByteStream); if (inFS.hasNextInt()) { prevHighScore = inFS.nextInt(); } } catch (FileNotFoundException e) { System.out.println("HighScore.txt不存在,将创建新文件"); } finally { if (inFS != null) inFS.close(); try { if (fileByteStream != null) fileByteStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (applesEaten > prevHighScore) { try { FileWriter myWriter = new FileWriter("HighScore.txt"); myWriter.write(String.valueOf(applesEaten)); myWriter.close(); // 重新打开文件读取新高分 fileByteStream = new FileInputStream("HighScore.txt"); inFS = new Scanner(fileByteStream); if (inFS.hasNextInt()) { highScore = inFS.nextInt(); } } catch (IOException e) { e.printStackTrace(); } finally { if (inFS != null) inFS.close(); try { if (fileByteStream != null) fileByteStream.close(); } catch (IOException e) { e.printStackTrace(); } } } else { highScore = prevHighScore; } return highScore; }
额外优化点
- 删除未使用的
Scanner scnr = new Scanner(System.in);,避免资源浪费; - 增加流的关闭操作(使用finally块),防止资源泄漏;
- 添加
inFS.hasNextInt()判断,避免文件为空时读取失败; - 初始化
prevHighScore为0,防止文件不存在时变量未初始化导致逻辑错误。
内容的提问来源于stack exchange,提问作者Evan Schulte
相关产品推荐
相关产品推荐

