在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.validatorhibernate.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流方式将内联filtermap()操作中的帮助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 { Function sourceFunction; 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); } }