使用JDK 11.0.3
。我有以下代码片段:
Set<String> allNumbersSet = customerInfoService.getCustomerPhoneNumbers(bankCustomerId);
additionalInformation
.map(info -> info.get(BANK_PE_CUSTOMER_ID_KEY))
.filter(StringUtils::isNotEmpty)
.ifPresent(id -> allNumbersSet.addAll(customerInfoService.getCustomerPhoneNumbers(id))); // fails here
那里的电话号码只有Collectors.toSet()
@Override
public Set<String> getCustomerPhoneNumbers(String customerId) {
return backOfficeInfoClient.getCustByHashNo(customerId).getPropertyLOVs()
.flatMap(property -> property.getValues().values().stream())
.collect(Collectors.toSet());
}
但是,它未能做到:
java.lang.UnsupportedOperationException
at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:71)
at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.addAll(ImmutableCollections.java:76)
at service.impl.UserManagementServiceImpl.lambda$validateNewLogin$3(UserManagementServiceImpl.java:69)
如果我更新如下:
var allNumbersSet = new HashSet<>(customerInfoService.getCustomerPhoneNumbers(bankCustomerId));
现在很好用。
上面的代码用法有什么问题?你能解释一下为什么会出现这种情况吗?
此方法调用被调用Hazelcast缓存-前后包围。正如在评论中提到的,这可能是造成这种行为的一个原因:
缓存的值使用不可变集合表示,这是有意义的,因为这允许共享而不需要防御性副本。
解决方案:
找到了如何重写此逻辑并在不合并两个集合的情况下完成该操作的方法:
var numbersSet = customerInfoService.getCustomerPhoneNumbers(id);
if (!numbersSet.contains(newLogin)) {
var peNumbersSet = additionalInformation
.map(info -> info.get(BANK_PE_CUSTOMER_ID_KEY))
.filter(StringUtils::isNotEmpty)
.map(customerInfoService::getCustomerPhoneNumbers)
.orElseGet(Collections::emptySet);
if (!peNumbersSet.contains(newLogin)) {
throw new ProcessException(ServerError.WRONG_LOGIN_PROVIDED.errorDTO());
}
}
再考虑一下这个逻辑:
var additionalInformation = Optional.ofNullable(user.getAdditionalInformation());
var phoneNumbers = new HashSet<String>();
additionalInformation
.map(i -> i.get(BANK_CUSTOMER_ID_KEY))
.filter(StringUtils::isNotEmpty)
.map(customerInfoService::getCustomerPhoneNumbers)
.ifPresent(phoneNumbers::addAll);
additionalInformation
.map(i -> i.get(BANK_PE_CUSTOMER_ID_KEY))
.filter(StringUtils::isNotEmpty)
.map(customerInfoService::getCustomerPhoneNumbers)
.ifPresent(phoneNumbers::addAll);
if (!phoneNumbers.contains(newLogin)) {
throw new MetryusProcessException(AuthServerError.WRONG_LOGIN_PROVIDED.errorDTO());
}
然而,了解Collectors.toSet()
在不同条件下的确切工作方式是非常有用的。
发布于 2022-09-13 11:31:52
根据Javadoc of Collectors.toSet()
返回的集合的类型、可更改性、可序列化性或线程安全性没有保证。
因此,如果您需要一个可变集,您应该自己创建一个集合,以确保它是可变的。
您可以使用所拥有的复制构造函数(new HashSet<>(...)
-不要忘记<>
)来实现这一点,也可以使用:
Collectors.toCollection(HashSet::new)
作为收集器,如链接的Javadoc所述。
但是,请注意,更多的streams方法是将两个流连接在一起:
Set<String> someNumbersSet = customerInfoService.getCustomerPhoneNumbers(bankCustomerId);
Set<String> allNumbersSet =
Stream.concat(
someNumbersSet.stream(),
additionalInformation
.map(info -> info.get(BANK_PE_CUSTOMER_ID_KEY))
.filter(StringUtils::isNotEmpty)
.map(customerInfoService::getCustomerPhoneNumbers)
.stream()
.flatMap(Collection::stream))
.collect(Collectors.toSet());
https://stackoverflow.com/questions/73701845
复制相似问题