You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 22:45:03