在Java-8中重构多个If语句
我需要在课堂上validation必填字段
例如, 9
字段不能为null
。
我需要检查它们是否都为null但我现在使用多个if语句,如下所示:
StringBuilder mandatoryExcessFields = new StringBuilder(MANDATORY_EXCESS_FIELDS.length); if(Objects.isNull(excess.getAsOfDate())){ mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[0]); } if(StringUtils.isEmpty(excess.getStatus())) { mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[1]); } if(Objects.isNull(excess.getLimit())) { mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[2]); } if(!Objects.isNull(excess.getLimit()) && Objects.isNull(excess.getLimit().getId())) { mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[3]); } if(!Objects.isNull(excess.getLimit()) && Objects.isNull(excess.getLimit().getAsOfDate())) { mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[4]); } if(Objects.isNull(excess.getExposure())) { mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[5]); } if(!Objects.isNull(excess.getExposure()) && Objects.isNull(excess.getExposure().getCoordinates())) { mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[6]); } if(!Objects.isNull(excess.getExposure()) && Objects.isNull(excess.getExposure().getValue())) { mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[7]); } if(StringUtils.isEmpty(excess.getLimitValue())) { mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[8]); }
我们是否有更好的方法来减少这个样板代码或任何设计模式或Java-8的任何新function,我可以利用它?
可以用Optional
对象及其方法替换所有Object.isNull
。 让我们举个例子:
if (!Objects.isNull(excess.getLimit()) && Objects.isNull(excess.getLimit().getId())) { mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[3]); }
将简化为(并在1行上挤压仍然可读):
Optional.ofNullable(excess.getLimit()) // check the Limit .map(limit -> limit.getId()) // if not null, getId .ifPresent(i -> builder.append(MANDATORY_EXCESS_FIELDS[3])); // Append if present
对于String.isEmpty(s)
检查,您必须以这种方式创建Optional
:
Optional.ofNullable(excess.getStatus()).filter(s -> !StringUtils.isEmpty(s))
一种简短的方法是将这些Optional
对象传递到映射中,并使用索引迭代它们并执行操作。 int count
是一些检查:
Map> map = new HashMap<>(); map.put(...); map.put(1, Optional.ofNullable(excess.getStatus()).filter(s -> !StringUtils.isEmpty(s))); map.put(...); map.put(3, Optional.ofNullable(excess.getLimit()).map(limit -> limit.getId())); map.put(...); for (int index=0; index mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[index])); }
并且for-cycle也可以简化:
IntStream.range(0, count).forEach(index -> map.get(index) .ifPresent(any -> mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[index])));
基本上,这里有两种方式:
- 正如评论所建议的那样,例如,Project Lombok提供的NonNull
- Java beanvalidation
我强烈建议查看beanvalidation:
定义以bean作为信息的类。 然后使用各种注释来标记相应的字段。 然后使用一些现有的框架为您进行validation。 您甚至可以在那里定义自己的注释,运行您自己的代码。
您可以在excess
POJO类的每个字段(或您想要的任何字段)上使用带有@NotNull
注释的javax.validator
和hibernate.validator
。 这种组合也提供了广泛的模式检查。
通过这种方式,您不必明确地执行所有if检查。 您不仅可以获得空检查,还可以获得模式匹配检查,这些检查可能会分散在您的代码中。
基本上,初始化和赋值不应将任何字段设置为null。
如果这是不合逻辑的(字段在逻辑上是可选的),则该字段可能应该是Optional<...>
,并使用Optional.ofNullable(...)
分配。 这可以确保在使用时安全地处理该字段,但当然会导致编辑工作。
现在看到代码,似乎没有简单的重构。
代码可以重构; 在某处缺少function映射。
Predicate[] parts = { exc -> Objects.isNull(exc.getAsOfDate()), exc -> StringUtils.isEmpty(exc.getStatus()), ... }; for (int i = 0; i < parts.length; ++i) { if (parts[i].test(excess)) { mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[i]); } }
或者这样。
由于易于重构,您可以引入两个辅助方法:
private String createErrorMsgIfObjectNull(Object o, String errorMessage) { return Objects.isNull(o) ? errorMessage : ""; } private String createErrorMsgIfStringEmpty(String s, String errorMessage) { return StringUtils.isEmpty(s) ? errorMessage : ""; }
并以这种方式使用它们:
StringBuilder mandatoryExcessFields = new StringBuilder(MANDATORY_EXCESS_FIELDS.length); mandatoryExcessFields.append(createErrorMsgIfObjectNull(excess.getAsOfDate(), MANDATORY_EXCESS_FIELDS[0])) .append(createErrorMsgIfStringEmpty(excess.getStatus(), MANDATORY_EXCESS_FIELDS[1])) .append(createErrorMsgIfObjectNull(excess.getLimit(), MANDATORY_EXCESS_FIELDS[2])) // ...
通过检查要测试的对象的类型,您仍然可以进一步。 您将拥有一个将根据参数类型应用处理的辅助方法:
private String createErrorMsgIfNullOrEmptyString(Object o, String errorMessage) { if (o instanceof String) { return StringUtils.isEmpty((String)o) ? errorMessage : ""; } return Objects.isNull(o) ? errorMessage : ""; }
Java 8流方式将内联filter
和map()
操作中的帮助filter
,并将收集String
结果:
List> objectAndErrorMessageList = new ArrayList<>(); int i = 0; objectAndErrorMessageList.add(new SimpleImmutableEntry<>(excess.getAsOfDate(), MANDATORY_EXCESS_FIELDS[i++])); objectAndErrorMessageList.add(new SimpleImmutableEntry<>(excess.getStatus(), MANDATORY_EXCESS_FIELDS[i++])); // and so for String globalErrorMsg = objectAndErrorMessageList.stream() .filter(e -> { Object objectToValid = e.getKey(); if (objectToValid == null) { return true; } if (objectToValid instanceof String && StringUtils.isEmpty(objectToValid)) { return true; } return false; }) .map(SimpleImmutableEntry::getValue) .collect(Collectors.joining(""));
其他解决方案是这样的:与@Nikolas答案相同。
Map> map = new HashMap<>(); Predicate checkStatus = excess -> excess.getStatus().isEmpty(); Predicate checkLimit = excess -> Objects.isNull(excess.getLimit()); Predicate checkLimitId = excess -> Objects.isNull(excess.getLimit().getId()); Predicate checkLimitAndId = checkLimit.and(checkLimitId); // other predicates map.put(1,checkStatus); map.put(2,checkLimit); map.put(3,checkLimitAndId); // put other predicates ... for (Map.Entry> m : map.entrySet()) { if (m.getValue().test(excess)) { mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[m.getKey()]); } }
有点复杂,但我有一个很好的解决方案,因为它是通用的,可以用于任何对象:
Excess excess = new Excess(new Limit()); Checker checker = new Checker<>( identity(), List.of( new CheckerValue<>("excess date is null", Excess::getAsOfDate), new CheckerValue<>("limit is null", Excess::getLimit) ), List.of(new Checker<>(Excess::getLimit, List.of(new CheckerValue<>("limit id is null", Limit::getId)))) ); System.out.println(checker.validate(excess));
此代码将打印:
excess date is null limit id is null
第一类Checker
包含:
- sourceFunction – 用于获取对象
- values – 用于检查从sourceFunction获取的对象中的每个字段
-
孩子 –
Checker
列表class Checker
{ FunctionsourceFunction; List> values; List > children = emptyList(); /*All args constructor; 2 args constructor*/ public String validate(S object) { T value = sourceFunction.apply(object); if(value != null) { String valueString = values.stream().map(v -> v.validate(value)).filter(Optional::isPresent).map(Optional::get).collect(joining("\n")); valueString += "\n\t"; valueString += children.stream().map(c -> c.validate(value)).collect(Collectors.joining("\n")); return valueString; } return ""; } }
和CheckerValue
类:
class CheckerValue { String validationString; Function fun; /*all args constructor*/ public Optional validate(T object) { return fun.apply(object) != null ? Optional.empty() : Optional.of(validationString); } }