简体   繁体   English

LinkedHashMap entrySet的顺序未保存在流中(Android)

[英]LinkedHashMap entrySet's order not being preserved in a stream (Android)

I'm creating a very simple form validation utility for a sign up screen, and I'm running into some unexpected behavior concerning LinkedHashMap and a stream created from its entrySet . 我正在为注册屏幕创建一个非常简单的表单验证实用程序,我遇到了一些关于LinkedHashMap和从其entrySet创建的流的意外行为。

I'm storing validation results in a LinkedHashMap , with the following ordering of statements: 我将验证结果存储在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);

One particular iteration yields all of the above fields invalid except for "confirm password". 除了“确认密码”之外,一个特定的迭代产生上述所有字段无效。 Using a simple for loop over the entry set and omitting valid results, the invalid results appear in the following order: 在条目集上使用简单的for循环并省略有效结果,无效结果按以下顺序显示:

  • Email 电子邮件
  • Username 用户名
  • Birthday 生日
  • Password 密码

I then attempted to make use of the subset of Stream API's available on Android (targeting version 25 with a min of 19, hence the lack of Collectors.toMap() ): 然后我尝试使用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;
}

But that code yields the following order: 但该代码产生以下顺序:

  • Birthday 生日
  • Password 密码
  • Username 用户名
  • Email 电子邮件

What exactly is happening here, why is the result of the stream not honoring the insertion order of the LinkedHashMap ? 这里究竟发生了什么,为什么流的结果不符合LinkedHashMap的插入顺序? Note that if I swap out forEachOrdered with forEach , it's still not insertion ordered. 请注意,如果我用forEach换出forEachOrdered ,它仍然没有按顺序插入。

This behavior is a known bug in Android's 7.0 / 7.1 implementation of LinkedHashMap. 此行为是Android的LinkedHashMap 7.0 / 7.1实现中的已知错误。

The LinkedHashMap's collection views' spliterators for entrySet , values and keySet correctly report that they are ORDERED but actually they aren't because the spliterator implementation of the parent class (HashMap) is used internally. LinkedHashMap的集合视图的entrySetvalueskeySet的分裂器正确地报告它们是ORDERED但实际上它们不是因为父类(HashMap)的spliterator实现是在内部使用的。

This behavior has already been documented in the Javadoc and workarounds are also proposed there. 这种行为已经记录在Javadoc中,并且在那里也提出了变通方法。

The fix has been commited on 2016-08-16 and will appear in the next Android release. 修复程序已于2016-08-16提交,并将在下一个Android版本中出现。

For clarification: Google became aware of this bug at first in 2017-01, so the "fix" mentioned above was an accidental fix. 澄清一下:谷歌最初在2017-01发现了这个错误,所以上面提到的“修复”是一个偶然的修复。 If they had known about this problem earlier, the resolution would have been included in 7.1 如果他们之前已经知道这个问题,那么该决议将包含在7.1中

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM