提问人:ChronicallyOverEngineered 提问时间:8/18/2023 更新时间:8/19/2023 访问量:91
Java-- do-while 循环跳转到下一次迭代而不检查退出条件?
Java-- do-while loop jumping to next iteration without checking exit condition?
问:
我已经使用 BufferedReader 为从文本文件中读取的方法编写了 do-while 代码。如果你想要上下文,我正在做臭名昭著的基于文本的冒险游戏,这种方法是从文本文件中提取我的游戏“物品”,以便它们可以在我的 HashMap 中制作成对象。
无论如何,我的一些描述有多行,所以我想确保它能捕捉到每一行。
下面是完整的代码块:
while ((currentLine = readerObject.readLine()) != null) {
if (currentLine.startsWith("name: ")) {
name = currentLine.substring(6);
} else if (currentLine.startsWith("location: ")) {
location = currentLine.substring(10);
} else if (!currentLine.startsWith("DONE")) {
do {
if (currentLine.startsWith("description: ")) {
description = currentLine.substring(13);
currentLine = readerObject.readLine();
} else {
description = description.concat(currentLine);
currentLine = readerObject.readLine();
}
} while (!currentLine.startsWith("DONE"));
itemsAll.put(name, new Items(name, location, description));
}
}
这是我代码中存在问题的特定部分:
do {
if (currentLine.startsWith("description: ")) {
description = currentLine.substring(13);
currentLine = readerObject.readLine();
} else {
description = description.concat(currentLine);
currentLine = readerObject.readLine();
}
} while (!currentLine.startsWith("DONE"));
如果以“description:”开头的行紧随其后的是“DONE”行,那么我的目的是在第一次迭代结束时评估退出条件时退出循环。相反,它循环回另一个迭代,所以当它到达退出条件时,它认为currentLine为null,并给了我这个:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.startsWith(String)" because "<local2>" is nullat TextInput.inputItems(TextInput.java:64)
我很困惑为什么一旦 currentLine 更新到 DONE,do-while 循环就不会退出?我已经在纸上手动完成了它(确定每个步骤的每个值和输出是什么),并在打印语句中添加了测试问题所在,但我只是不明白为什么。
我已经想出了一个更简化的解决方案,但我觉得我错过了一些关于为什么原始代码不起作用的基本知识......谁能解释一下?
对不起,如果原因很明显......我今天编码了太多小时,所以我的大脑可能很糊。
答:
我看到两件事可能出错了:
尽管内部末端,但最顶层的循环仍在执行中。所以,这就是为什么你的程序没有退出。
do/while
while
您需要以与最顶层循环相同的方式在内部执行 null 检查。具体而言,在执行以下操作后:
do/while
while
currentLine = readerObject.readLine();
评论
currentLine
null
do/while
do/while
itemsAll.put(name, new Items(name, location, description));
while
currentLine = readerObject.readLine() != null
null
currentLine
null
while
我觉得我错过了一些关于为什么原版的基本知识 代码不起作用
你缺少的是你不需要另一个做。while
循环
您需要做的就是:
- 逐行读取文件
- 如果找到带有“DONE”的行,请保存(使用代替 ,它更直观,并强制用户不要将“DONE”与其他行混淆)
Item
contains
startsWith()
- 将任何其他行保存到变量中。
样本:
while ((currentLine = readerObject.readLine()) != null) {
if (currentLine.contains("DONE")) {
itemsAll.put(name, new Items(name, location, description));
}
else if (currentLine.startsWith("name: ")) {
name = currentLine.substring(6);
}
else if (currentLine.startsWith("location: ")) {
location = currentLine.substring(10);
}
else if (currentLine.startsWith("description: ")) {
description = currentLine.substring(13);
} else {
description = description.concat(currentLine);
}
}
这是您的模型:Record
@Getter
@Builder
public final class Record {
private final String name;
private final String location;
private final String description;
}
这是主要方法的样子:
Path file = Path.of("foo.txt");
List<Record> records = readRecords(file);
这是从文件中读取记录的方法,其中任何参数都可以有多行:
public static List<Record> readRecords(Path file) throws IOException {
try (Stream<String> stream = Files.lines(file, StandardCharsets.UTF_8)) {
List<Record> records = new ArrayList<>();
Queue<String> recordLines = new LinkedList<>();
stream.forEach(line -> {
if ("DONE".equalsIgnoreCase(line)) {
if (!recordLines.isEmpty()) records.add(createRecord(recordLines));
} else recordLines.add(line);
});
if (!recordLines.isEmpty()) records.add(createRecord(recordLines));
return records.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
}
private static Record createRecord(Queue<String> recordLines) {
Map<String, String> map = new HashMap<>();
while (!recordLines.isEmpty()) {
Map.Entry<String, String> entry = readMultiLine(recordLines);
if (!entry.getValue().isBlank()) map.put(entry.getKey(), entry.getValue());
}
return createRecords(map);
}
private static Map.Entry<String, String> readMultiLine(Queue<String> recordLines) {
String marker = null;
StringBuilder buf = new StringBuilder();
while (!recordLines.isEmpty()) {
String recordLine = recordLines.element();
int pos = recordLine.indexOf(':');
if (pos > 0) {
if (marker != null) break;
marker = recordLine.substring(0, pos);
}
buf.append(System.lineSeparator()).append(recordLine.substring(pos + 1));
recordLines.remove();
}
return Map.entry(marker, buf.toString().trim());
}
private static Record createRecords(Map<String, String> map) {
return Record.builder()
.name(map.get("name"))
.location(map.get("location"))
.description(map.get("description"))
.build();
}
上一个:继续声明
评论
else if
"description"
! "DONE"
if
"DONE"