无法使用提取到字符串的映射键
Extracted Map key to String could not be used
在一个应用程序上我有公交车,每辆公交车都与几个车站相关联,并且在一天中的每个车站都有几个到达时间。
Map<String, Station> stationMap = new HashMap<>();
Map<String, String[]> busTimesForSingleStation = new HashMap<>(); // key is station's name and value would be an array of times in string.
List<Station> stationsOfBus = new ArrayList<>();
Map<List<Station>, String[]> allArriveTimes = new HashMap<>();
for (int i = 10; i <= 400; i += 10) {
busTimesForSingleStation = generateTimeForStation(i);
String key;
for (Map.Entry<String, String[]> e : busTimesForSingleStation.entrySet()){
key = e.getKey();
}
allArriveTimes.put(stationsOfBus.add(stationMap.get(key)),
busTimesForSingleStation.get(Integer.toString(i)));
}
第一个 for
循环旨在将多个站点(每个站点有多个站点)添加到公共汽车。然而,使用内部 for
循环是因为我不知道任何其他方法来获取 busTimesForSingleStation
的密钥。 (尽管每次 busTimesForSingleStation
地图中只有一个条目。)
我的具体问题是倒数第二行使用的 key
变量显然不起作用,我从 IDE:
得到这个错误
Variable 'key' might not have been initialized
问题是,编译器不知道第二个 for 循环是否会 运行 至少一次(因为它不可能知道 busTimesForSingleStation是否为空)。
要解决这个问题,只需将 String key;
更改为 String key = "";
这样编译器就知道,不会有空引用,即使 busTimesForSingleStation 是空.
我同意 SimMac 对问题的描述,但不同意他建议的修复方法。
简单地说 String key = "";
的问题是您随后 使用 这个值。也许这没问题 - stationMap.get(key)
return 是一个安全的 "not found" 值 - 但更有可能不是。说它 returns null
:现在你正在将 null
添加到 stationsOfBus
,这可能会在运行时失败(最好的情况 - 但它可能会从这段代码中失败很长一段时间),或者默默地继续通过你的程序传播废话(最坏的情况)。
修复编译器捕获的实际问题(映射可能为空)比破解一个只隐藏该问题的修复要好得多。
如果 busTimesForSingleStation
不能为空,则断言:
if (!busTimesForSingleStation.isEmpty()) {
String key = ""; // Now you know it will be overwritten.
for (String maybeKey : busTimesForSingleStation.keySet()) {
key = maybeKey;
}
} else {
throw new AssertionError("Should never happen!");
}
或者,如果它可能为空,则明确处理:
if (!busTimesForSingleStation.isEmpty()) {
String key = ""; // Now you know it will be overwritten.
for (String maybeKey : busTimesForSingleStation.keySet()) {
key = maybeKey;
}
} else {
// Some logic to handle it correctly.
}
这个问题的更深层原因是您选择的 return 类型 generateTimesForStation
没有准确编码您的意图:
- 您的问题是您希望 returned 地图包含一对 key/value
- 您的 return 类型表示该方法的调用者应该 returned 零,一对或多对 key/value
显然,"one k/v pair" 可以用包含 "zero or more k/v pairs" 的数据结构表示 - 但选择这样表示意味着调用代码必须能够处理 "zero" 和 "or more" 例。
例如,如果 returned 数据结构 did 包含 2 个或更多 k/v 对,并且您想选择 "last" 键,您将不得不担心这些对的迭代顺序。如果类型系统可以保证它永远不会发生,那么处理这种情况的要求就完全取消了。
如果你想return正好一对k/v,有两个选项需要高亮:
代码中最简单的更改是使用 Map.Entry<String, String[]>
而不是 Map<String, String[]>
。 Map.Entry
只是您在循环中迭代的结构的元素之一。
Map.Entry<String, String[]> entry = generateTimesForStation(i);
String key = entry.getKey();
// Do whatever with the key.
编写一个自定义类型来表示 k/v 对,以及 return 和它的实例。 Map.Entry
(以及 Map
)的缺点之一是 "key" 和 "value" 没有附加语义。如果您有名为 getStationName
和 getTimes
(或其他名称)的访问器,可能更容易一目了然地阅读代码。一个精心挑选的 class 名字也比 Map.Entry<String, String[]>
.
的普通汤漂亮很多
BusTime entry = generateTimesForStation(i);
String key = entry.getStationName();
// Do whatever with the key - or maybe just refer to
// `entry.getStationName()` directly.
无论你选择哪一个,你现在都避免了未初始化的变量和循环,因为没有任何东西可以循环了。
如果你想 return 零对或一对 k/v ,上面的两个选项都是有效的,但你应该将结果包装在类似 Optional
的类型中,以便强烈表明不存在这样的 k/v 对的可能性。你 可以 return null
来表明这一点,但我不鼓励这样做 - 请参阅 Louis Wasserman's answer 为什么 Optional
比 null
(他说的是 Guava Optional
,但 Java 8 Optional
的论点是相同的)。
Optional<Map.Entry<String, String[]>> entry = generateTimesForStation(i);
if (entry.isPresent()) {
String key = entry.get().getKey();
// Do whatever with the key.
} else {
// Handle the "not found" case.
}
使用更具体的 return 类型的方法也可能有助于您实现 generateTimesForStation
:一个(或者可能是零个或一个)值必须是 returned 可以帮助您捕获导致 return 值不符合这些约束的控制流路径。
在一个应用程序上我有公交车,每辆公交车都与几个车站相关联,并且在一天中的每个车站都有几个到达时间。
Map<String, Station> stationMap = new HashMap<>();
Map<String, String[]> busTimesForSingleStation = new HashMap<>(); // key is station's name and value would be an array of times in string.
List<Station> stationsOfBus = new ArrayList<>();
Map<List<Station>, String[]> allArriveTimes = new HashMap<>();
for (int i = 10; i <= 400; i += 10) {
busTimesForSingleStation = generateTimeForStation(i);
String key;
for (Map.Entry<String, String[]> e : busTimesForSingleStation.entrySet()){
key = e.getKey();
}
allArriveTimes.put(stationsOfBus.add(stationMap.get(key)),
busTimesForSingleStation.get(Integer.toString(i)));
}
第一个 for
循环旨在将多个站点(每个站点有多个站点)添加到公共汽车。然而,使用内部 for
循环是因为我不知道任何其他方法来获取 busTimesForSingleStation
的密钥。 (尽管每次 busTimesForSingleStation
地图中只有一个条目。)
我的具体问题是倒数第二行使用的 key
变量显然不起作用,我从 IDE:
Variable 'key' might not have been initialized
问题是,编译器不知道第二个 for 循环是否会 运行 至少一次(因为它不可能知道 busTimesForSingleStation是否为空)。
要解决这个问题,只需将 String key;
更改为 String key = "";
这样编译器就知道,不会有空引用,即使 busTimesForSingleStation 是空.
我同意 SimMac 对问题的描述,但不同意他建议的修复方法。
简单地说 String key = "";
的问题是您随后 使用 这个值。也许这没问题 - stationMap.get(key)
return 是一个安全的 "not found" 值 - 但更有可能不是。说它 returns null
:现在你正在将 null
添加到 stationsOfBus
,这可能会在运行时失败(最好的情况 - 但它可能会从这段代码中失败很长一段时间),或者默默地继续通过你的程序传播废话(最坏的情况)。
修复编译器捕获的实际问题(映射可能为空)比破解一个只隐藏该问题的修复要好得多。
如果 busTimesForSingleStation
不能为空,则断言:
if (!busTimesForSingleStation.isEmpty()) {
String key = ""; // Now you know it will be overwritten.
for (String maybeKey : busTimesForSingleStation.keySet()) {
key = maybeKey;
}
} else {
throw new AssertionError("Should never happen!");
}
或者,如果它可能为空,则明确处理:
if (!busTimesForSingleStation.isEmpty()) {
String key = ""; // Now you know it will be overwritten.
for (String maybeKey : busTimesForSingleStation.keySet()) {
key = maybeKey;
}
} else {
// Some logic to handle it correctly.
}
这个问题的更深层原因是您选择的 return 类型 generateTimesForStation
没有准确编码您的意图:
- 您的问题是您希望 returned 地图包含一对 key/value
- 您的 return 类型表示该方法的调用者应该 returned 零,一对或多对 key/value
显然,"one k/v pair" 可以用包含 "zero or more k/v pairs" 的数据结构表示 - 但选择这样表示意味着调用代码必须能够处理 "zero" 和 "or more" 例。
例如,如果 returned 数据结构 did 包含 2 个或更多 k/v 对,并且您想选择 "last" 键,您将不得不担心这些对的迭代顺序。如果类型系统可以保证它永远不会发生,那么处理这种情况的要求就完全取消了。
如果你想return正好一对k/v,有两个选项需要高亮:
代码中最简单的更改是使用
Map.Entry<String, String[]>
而不是Map<String, String[]>
。Map.Entry
只是您在循环中迭代的结构的元素之一。Map.Entry<String, String[]> entry = generateTimesForStation(i); String key = entry.getKey(); // Do whatever with the key.
编写一个自定义类型来表示 k/v 对,以及 return 和它的实例。
的普通汤漂亮很多Map.Entry
(以及Map
)的缺点之一是 "key" 和 "value" 没有附加语义。如果您有名为getStationName
和getTimes
(或其他名称)的访问器,可能更容易一目了然地阅读代码。一个精心挑选的 class 名字也比Map.Entry<String, String[]>
.BusTime entry = generateTimesForStation(i); String key = entry.getStationName(); // Do whatever with the key - or maybe just refer to // `entry.getStationName()` directly.
无论你选择哪一个,你现在都避免了未初始化的变量和循环,因为没有任何东西可以循环了。
如果你想 return 零对或一对 k/v ,上面的两个选项都是有效的,但你应该将结果包装在类似 Optional
的类型中,以便强烈表明不存在这样的 k/v 对的可能性。你 可以 return null
来表明这一点,但我不鼓励这样做 - 请参阅 Louis Wasserman's answer 为什么 Optional
比 null
(他说的是 Guava Optional
,但 Java 8 Optional
的论点是相同的)。
Optional<Map.Entry<String, String[]>> entry = generateTimesForStation(i);
if (entry.isPresent()) {
String key = entry.get().getKey();
// Do whatever with the key.
} else {
// Handle the "not found" case.
}
使用更具体的 return 类型的方法也可能有助于您实现 generateTimesForStation
:一个(或者可能是零个或一个)值必须是 returned 可以帮助您捕获导致 return 值不符合这些约束的控制流路径。