我为注册屏幕创建了一个非常简单的表单验证工具,我遇到了一些与LinkedHashMap
有关的意外行为以及从其entrySet
创建的流。
我将验证结果存储在LinkedHashMap
中,其语句顺序如下:
Map<ValidationResult.SignUpField, Boolean> fieldStatuses = new LinkedHashMap<>();
fieldStatuses.put(EMAIL, isValidEmail(emailAddress));
fieldStatuses.put(USERNAME, isValidUsername(username));
fieldStatuses.put(BIRTHDAY, isValidBirthday(birthday));
fieldStatuses.put(PASSWORD, isValidPassword(password));
fieldStatuses.put(CONFIRM_PASSWORD, password.equals(confirmedPassword));
List<ValidationEntry> invalidFields = aggregateInvalidFields(fieldStatuses);
除了&#34;确认密码&#34;之外,一个特定的迭代产生上述所有字段无效。在条目集上使用简单的for循环并省略有效结果,无效结果按以下顺序显示:
然后我尝试使用Android上可用的Stream API子集(目标版本25,最小值为19,因此缺少Collectors.toMap()
):
private static List<ValidationEntry> aggregateInvalidFields(Map<ValidationResult.SignUpField, Boolean> fields) {
List<ValidationEntry> invalidFields = new ArrayList<>();
fields.entrySet()
.stream()
.filter(entry -> !entry.getValue())
.forEachOrdered(entry -> {
ValidationResult.SignUpField field = entry.getKey();
invalidFields.add(new ValidationEntry(field, lookUpErrorCode(field)));
});
return invalidFields;
}
但该代码产生以下顺序:
这里到底发生了什么,为什么流的结果不符合LinkedHashMap
的插入顺序?请注意,如果我将forEachOrdered
换成forEach
,则仍然无法插入订单。
答案 0 :(得分:6)
此行为是Android的LinkedHashMap 7.0 / 7.1实现中的一个已知错误。
LinkedHashMap的集合视图'entrySet
,values
和keySet
的分裂器正确地报告它们是ORDERED
但实际上它们不是因为父级的分裂器实现class(HashMap)在内部使用。
此行为在Javadoc中已经documented,并且还在那里提出了解决方法。
fix已于2016-08-16提交,并将在下一个Android版本中显示。
澄清一下:Google最初在2017-01发现了这个错误,因此上面提到的“修复”是一个意外修复。如果他们之前已经知道这个问题,那么解决方案将包含在7.1
中