英文:
How to validate object values in a List if value is not empty or not null using java 8 stream
问题
// Original Code:
I have an objectList
OfferToCheck offer = new OfferToCheck();
offer.setDiscountId(null);
offer.setProductName("sadf spacefjkd");
offer.setServiceCode("dfsdfv");
offer.setServiceGroup("nospace");
OfferToCheck offer1 = new OfferToCheck();
offer1.setDiscountId("");
offer1.setProductName("sadfspacefjkd");
offer1.setServiceCode("sdnof");
offer1.setServiceGroup("sdf");
request.setOffersToCheck(Arrays.asList(offer, offer1));
request.setStartTrialPeriod("y");
if (service.validateStatus(request)) {
System.out.println("true");
} else {
System.out.println("false");
}
// Original Loop:
for (OfferToCheck offer : request.getOffersToCheck()) {
if (offer.getDiscountId() != null && !offer.getProductName().isEmpty()) {
if (!offer.getDiscountId().chars().allMatch(Character::isDigit)) {
return isValid = false;
}
}
if (offer.getServiceCode() != null && !offer.getServiceCode().isEmpty()) {
if (!offer.getServiceCode().chars().allMatch(Character::isAlphabetic)) {
return isValid = false;
}
}
if (offer.getServiceGroup() != null && !offer.getServiceGroup().isEmpty()) {
if (!offer.getServiceGroup().chars().allMatch(Character::isAlphabetic)) {
return isValid = false;
}
}
if (offer.getProductName() != null && !offer.getProductName().isEmpty()) {
if (!offer.getProductName().matches("[a-zA-Z ]*")) {
return isValid = false;
}
}
}
// Stream Approach:
if (!request.getOffersToCheck().stream()
.filter(list -> list.getDiscountId() != null && !list.getDiscountId().isEmpty())
.filter(list -> list.getProductName() != null && !list.getProductName().isEmpty())
.allMatch(validateList -> (
validateList.getDiscountId().chars().allMatch(Character::isLetterOrDigit) &&
validateList.getProductName().matches("[a-zA-Z0-9 ]*") &&
validateList.getServiceCode().matches("[a-zA-Z0-9]*") &&
validateList.getServiceGroup().chars().allMatch(Character::isDigit))
)) {
return isValid = false;
}
Note: The provided code snippets appear to be a mix of original code, a for loop, and a stream approach. If there are any errors in the original code or the provided snippets, please adjust them accordingly.
英文:
I have an objectList
OfferToCheck offer = new OfferToCheck();
offer.setDiscountId(null);
offer.setProductName("sadf spacefjkd");
offer.setServiceCode("dfsdfv");
offer.setServiceGroup("nospace");
OfferToCheck offer1 = new OfferToCheck();
offer1.setDiscountId("");
offer1.setProductName("sadfspacefjkd");
offer1.setServiceCode("sdnof");
offer1.setServiceGroup("sdf");
request.setOffersToCheck(Arrays.asList(offer,offer1));
request.setStartTrialPeriod("y");
if(service.validateStatus(request)){
System.out.println("true");
}
else{
System.out.println("false");
}
i want to acheive this for loop using java 8 stream
for(OfferToCheck offer : request.getOffersToCheck()){
if(offer.getDiscountId() != null && !offer.getProductName().isEmpty()){
if(!offer.getDiscountId().chars().allMatch(Character::isDigit)){
return isValid = false;
}
}
if(offer.getServiceCode() != null && !offer.getServiceCode().isEmpty()){
if(!offer.getServiceCode().chars().allMatch(Character::isAlphabetic)){
return isValid = false;
}
}
if(offer.getServiceGroup() != null && !offer.getServiceGroup().isEmpty()){
if(!offer.getServiceGroup().chars().allMatch(Character::isAlphabetic)){
return isValid = false;
}
}
if(offer.getProductName() != null && !offer.getProductName().isEmpty()){
if(!offer.getProductName().matches("[a-zA-Z ]*")){
return isValid = false;
}
}
}
I have tried this but when value of discountId is empty or null it does not include the rest of the object into the stream.
if(!request.getOffersToCheck().stream()
.filter(list -> (list.getServiceCode() != null && !list.getServiceCode().isEmpty()))
.filter (list -> list.getDiscountId() != null && !list.getDiscountId().isEmpty())
.filter (list -> list.getProductName() != null && !list.getProductName().isEmpty())
.filter (list -> list.getProductName() != null && !list.getProductName().isEmpty())
.filter (list -> list.getServiceGroup() != null && !list.getServiceGroup().isEmpty())
.allMatch(validateList -> (validateList .getDiscountId().chars().allMatch(Character::isLetterOrDigit)
&& validateList.getProductName().matches("[a-zA-Z0-9 ]*")
&& validateList.getServiceCode().matches("[a-zA-Z0-9]*")
&& validateList.getServiceGroup().chars().allMatch(Character::isDigit))
))
{
return isValid = false;
}
also tried all the condtion in one filter
答案1
得分: 1
你可以创建一个字段映射的地图(使用 Function
作为键,Predicate
作为字段验证的值)。
然后,你只需遍历报价(Stream<OfferToCheck>
),对于每个报价遍历代表提取和验证的地图。
- 使用键提取字段值(例如,
String fieldValue = entry.getKey().apply(offer)
) - 使用值验证字段值(例如,
entry.getValue().test(fieldValue)
)
你想收集 Stream::allMatch
的所有布尔结果,并确保它们都为 true,从而返回该结果本身。
Map<Function<OfferToCheck, String>, Predicate<String>> map = new HashMap<>();
map.put(OfferToCheck::getDiscountId, s -> s.chars().allMatch(Character::isDigit));
map.put(OfferToCheck::getServiceCode, s -> s.chars().allMatch(Character::isAlphabetic));
map.put(OfferToCheck::getServiceGroup, s -> s.chars().allMatch(Character::isAlphabetic));
map.put(OfferToCheck::getProductName, s -> s.matches("[a-zA-Z ]*"));
return request.getOffersToCheck()
.stream()
.allMatch(offer -> map.entrySet()
.stream()
.filter(entry -> entry.getKey().apply(offer) != null &&
!entry.getKey().apply(offer).isEmpty())
.allMatch(entry -> entry.getValue().test(entry.getKey().apply(offer))));
此解决方案假设所有字段都以类似的方式进行验证 - 例如,使用了 String::isEmpty
。否则,您必须将此类验证放入映射中,并从内部流中删除它。根据您的需要随意修改代码。
是否采用此解决方案的最终选择完全取决于您:
优点
- 对于大量类似的字段验证非常有用,例如 SOAP。
- 可扩展:每个新字段都只需添加一个新的
map
条目。
缺点
- 阅读、维护和调试较困难(必须使用
Stream::peek
)。 - 需要适当的单元测试来覆盖这种逻辑(无论如何,我建议您这样做,这种实现方式需要强烈的测试需求)。
英文:
You can create a map of the field mappings (using Function
) as a key and a Predicate
as a value of the field validation itself.
Then all you need is to iterate through the offers (Stream<OfferToCheck>
) and for each one iterate through the map which represents both the extraction and the validation itself.
- Using it's key you extract the field value (i.e.
String fieldValue = entry.getKey().apply(offer)
) - Using it's value you validate the field value (i.e.
entry.getValue().test(fieldValue)
)
You want to collect all the boolean
results from Stream::allMatch
and get sure they are all true, thus returning that result itself.
Map<Function<OfferToCheck, String>, Predicate<String>> map = new HashMap<>();
map.put(OfferToCheck::getDiscountId, s -> s.chars().allMatch(Character::isDigit));
map.put(OfferToCheck::getServiceCode, s -> s.chars().allMatch(Character::isAlphabetic));
map.put(OfferToCheck::getServiceGroup, s -> s.chars().allMatch(Character::isAlphabetic));
map.put(OfferToCheck::getProductName, s -> s.matches("[a-zA-Z ]*"));
return request.getOffersToCheck()
.stream()
.allMatch(offer -> map.entrySet()
.stream()
.filter(entry -> entry.getKey().apply(offer) != null &&
!entry.getKey().apply(offer).isEmpty())
.allMatch(entry -> entry.getValue().test(entry.getKey().apply(offer))));
This solution assumes all the fields are validated in the similar way - ex. String::isEmpty
is used. Otherwise you have to place such validation to the map and remove it from the inner Stream. Feel free to modify the code according to your needs.
The final choice whether you are up to this solution is solely up to you:
Pros
- Useful for a large number of similar field validations, ex. SOAP.
- Scalable: the only thing you add with each new field is a new
map
entry.
Cons
- Harder to read, maintain and debug (you have to use
Stream::peek
). - Needs proper unit tests to cover such logic (I'd recommend you anyway, this implementation implies a strong need for a test).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论