使用Scanner读取|分隔文件时遭遇NoSuchElementException求助
解决StringTokenizer读取分隔文件时的NoSuchElementException问题
你的问题核心出在内层的while(stringTokenizer.hasMoreTokens())循环上,结合错误发生在setYear行的信息,我们来拆解问题并给出解决方案:
问题根源
每一行文本对应一个完整的Opera对象,需要恰好6个|分隔的字段,但内层循环的逻辑存在两个致命问题:
- 如果某一行字段数量不足6个(比如空行、格式错误的行),当调用到第3次
nextToken()(对应year字段)时,已经没有剩余token,直接抛出NoSuchElementException。 - 即使所有行都刚好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
相关产品推荐
相关产品推荐

