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

使用Scanner读取|分隔文件时遭遇NoSuchElementException求助

解决StringTokenizer读取分隔文件时的NoSuchElementException问题

你的问题核心出在内层的while(stringTokenizer.hasMoreTokens())循环上,结合错误发生在setYear行的信息,我们来拆解问题并给出解决方案:

问题根源

每一行文本对应一个完整的Opera对象,需要恰好6个|分隔的字段,但内层循环的逻辑存在两个致命问题:

  1. 如果某一行字段数量不足6个(比如空行、格式错误的行),当调用到第3次nextToken()(对应year字段)时,已经没有剩余token,直接抛出NoSuchElementException。
  2. 即使所有行都刚好6个字段,这个内层循环也是完全多余的——每一行只需要创建一个Opera对象,不需要重复循环读取token。

解决方案

方案1:移除内层循环,增加字段校验

直接去掉内层while循环,先用countTokens()检查当前行的字段数量是否符合要求,再依次赋值:

void readFromFile(String fileName) {
    operas.clear();
    Scanner input = new Scanner(new File(fileName));
    while(input.hasNextLine()) {
        String line = input.nextLine().trim();
        // 跳过空行,避免无意义处理
        if (line.isEmpty()) {
            continue;
        }
        Opera opera = new Opera();
        StringTokenizer stringTokenizer = new StringTokenizer(line, "|");
        
        // 确保当前行有恰好6个字段
        if (stringTokenizer.countTokens() == 6) {
            opera.setTitle(stringTokenizer.nextToken());
            opera.setComposer(stringTokenizer.nextToken());
            // 额外捕获数字格式异常,避免年份不是有效整数导致崩溃
            try {
                opera.setYear(Integer.parseInt(stringTokenizer.nextToken()));
            } catch (NumberFormatException e) {
                System.err.println("无效的年份格式,跳过该行: " + line);
                continue;
            }
            opera.setCity(stringTokenizer.nextToken());
            opera.setSynopsis(stringTokenizer.nextToken());
            opera.setLink(stringTokenizer.nextToken());
            operas.add(opera);
        } else {
            System.err.println("格式错误的行(预期6个字段,实际" + stringTokenizer.countTokens() + "个): " + line);
        }
    }
    input.close();
}

方案2:改用String.split()(更直观易维护)

String.split()可以直接将行分割为字符串数组,通过索引访问字段,格式校验更清晰:

void readFromFile(String fileName) {
    operas.clear();
    Scanner input = new Scanner(new File(fileName));
    while(input.hasNextLine()) {
        String line = input.nextLine().trim();
        if (line.isEmpty()) {
            continue;
        }
        // \\|是转义后的分隔符,-1参数确保保留末尾空字段(如果存在)
        String[] parts = line.split("\\|", -1);
        Opera opera = new Opera();
        
        if (parts.length == 6) {
            opera.setTitle(parts[0]);
            opera.setComposer(parts[1]);
            try {
                opera.setYear(Integer.parseInt(parts[2]));
            } catch (NumberFormatException e) {
                System.err.println("无效的年份,跳过该行: " + line);
                continue;
            }
            opera.setCity(parts[3]);
            opera.setSynopsis(parts[4]);
            opera.setLink(parts[5]);
            operas.add(opera);
        } else {
            System.err.println("格式错误的行(预期6个字段,实际" + parts.length + "个): " + line);
        }
    }
    input.close();
}

额外优化提示

  • 处理异常场景:加入了NumberFormatException捕获,避免年份不是有效整数时程序崩溃。
  • 跳过空行:通过trim()和isEmpty()过滤空行,减少无效处理。
  • 复杂场景扩展:如果你的字段中可能包含|字符(比如剧情简介里出现),StringTokenizer和split都会失效,此时建议使用成熟的CSV解析库处理带转义的分隔符。

内容的提问来源于stack exchange,提问作者Jeremiah Griffith

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:49:44