naz*_*art 1 java exception set unsupportedoperation java-11
使用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
Run Code Online (Sandbox Code Playgroud)
获取电话号码的地方就是Collectors.toSet():
@Override
public Set<String> getCustomerPhoneNumbers(String customerId) {
return backOfficeInfoClient.getCustByHashNo(customerId).getPropertyLOVs()
.flatMap(property -> property.getValues().values().stream())
.collect(Collectors.toSet());
}
Run Code Online (Sandbox Code Playgroud)
但是,它失败了:
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)
Run Code Online (Sandbox Code Playgroud)
如果我像下面这样更新:
var allNumbersSet = new HashSet<>(customerInfoService.getCustomerPhoneNumbers(bankCustomerId));
Run Code Online (Sandbox Code Playgroud)
现在效果很好。
上面的代码使用有什么问题吗?您能解释一下为什么会出现这种情况吗?
此方法调用由调用 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());
}
}
Run Code Online (Sandbox Code Playgroud)
稍微重新思考一下这个逻辑:
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());
}
Run Code Online (Sandbox Code Playgroud)
然而,了解Collectors.toSet()在不同条件下到底如何工作确实非常有用。
对于返回的 Set 的类型、可变性、可序列化性或线程安全性没有任何保证。
因此,如果您需要一个可变集,您应该自己创建一个,以确保它是可变的。
您可以使用您拥有的复制构造函数(new HashSet<>(...)- 不要忘记<>)来做到这一点,或者您可以使用:
Collectors.toCollection(HashSet::new)
作为收集器,如链接的 Javadoc 中所述。
但是,请注意,一种更 Stream-y 的方法是连接两个流:
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());
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1228 次 |
| 最近记录: |