Java 8避免了大量的if / else语句

时间:2017-03-20 18:05:57

标签: java validation lambda predicate

我有一些看起来像这样的东西:

 public boolean isValidObject(SomeObject obj){
    if(obj.getField() == null){
      LOG.error("error code 1");
      return false;
    }
    if(obj.getField().getSize() > 500){
      LOG.error("error code 2");
      return false;
    }
    ......
    if(someCondition()){
     log something
     return false;
    }

    return true;
}

使用lambdas在java 8中编写这个最干净的方法是什么?

6 个答案:

答案 0 :(得分:11)

为此使用多态。为每个逻辑验证器创建一个类,并将它们链接到列表中。这里有你需要的很好的答案: https://stackoverflow.com/a/23501390/1119473

public interface Validator<SomeObject>{
    public Result validate(SomeObject object);
}

实现:

public class SomeFieldSizeValidator implements Validator<SomeObject> {

@Override
public Result validate(SomeObject obj) {
    // or you can return boolean true/false here if it's enough
    return obj.getField().getSize() > 500 ? Result.OK : Result.FAILED;
    }
}

调用验证链:

List<Validator> validators = ... create ArrayList of needed Validators
for (Validator v : validators) {
if (!v.validate(object)) { 
  ... throw exception, you know validator and object here
}

答案 1 :(得分:3)

我可能会返回错误,但这仍然会使用一些if <#p>。

public String isValidObject(SomeObject obj){
    if (obj.getField() == null) return "error code 1";
    if (obj.getField().getSize() > 500) return "error code 2";
    ......
    if (someCondition()) return "something";
    return OK;
}

通过这种方式,您可以对此方法进行单元测试,以查看它是否返回了您对不同无效对象所期望的错误。

  

我想摆脱50条if / else语句。

如果您有50个条件并且它们都有不同的结果,则需要进行50次检查。你可以改变这样的结构。

static final Map<Predicate<SomeObject>, String> checks = new LinkedHashMap<>();
static {
    checks.put((Predicate<SomeObject>) o -> o.getField() == null, "error code 1");
    checks.put((Predicate<SomeObject>) o -> o.getField().getSize() > 500, "error code 2");
}

public String isValidObject(SomeObject obj) {
    for (Predicate<SomeObject> test : checks.keySet())
        if (test.test(object))
            return checks.get(test);
    return OK;
}

然而,就个人而言,这并不是更清楚,并且更难以调试,例如断点。

答案 2 :(得分:3)

我建议使用不同方法的解决方案:考虑使用Validator对象。含义:不是将所有检查放在同一个方法中,而是将每个检查放在自己的类中!

定义一些提供验证方法的Validator接口。验证失败时,该方法应抛出一些ValidationException(该异常可能包含错误代码+消息)。

然后你创建了许多小类,每个小类都实现了该接口。

最后一步:创建一个列表,在其中放置每个impl类的一个对象。现在,您的代码归结为迭代该列表,并将每个impl应用于另一个。

这解耦了您的验证步骤,添加新/其他检查变得非常容易。

答案 3 :(得分:3)

使用java.util.function.Predicate接口:

Predicate<SomeObject> p1 = (SomeObject so ) -> so.getField()!=null;
Predicate<SomeObject> p2 = (SomeObject so ) -> so.getField().getSize() > 500;

...

 SomeObject someObject = new SomeObject();
 Predicate<SomeObject> fullPredicate = p1.and(p2).and( ...


 boolean result = fullPredicate.test(someObject);

除了这将给你50个Predicate一行定义,它们会更紧凑。

答案 4 :(得分:2)

我不确定lambdas如何在这里有用。

如果你使用了很多'if else'来处理很多业务规则,那么一个选择就是尝试一些rule engines。一个简单而最好的选择是EasyRules

Easy rules非常方便且易于实施。这将使您的业务逻辑代码看起来非常干净。

答案 5 :(得分:1)

如果您特别希望使用lambda,它们与enum

很好地匹配
public enum SomeValidators {
    E1 (1, o -> o.getField() == null),
    E2 (2, o -> o.getField().getSize() > 500)
    ;

    final int code;
    final Predicate<SomeObject> predicate;

    SomeValidators(int code, int predicate) {
        this.code = code;
        this.predicate = predicate;
    }
}

然后您可以使用它来复制if-else if流程,如下所示:

boolean isValidObject(SomeObject o) {
    Optional<SomeValidators> firstError = 
        Arrays.stream(SomeValidators.values())
        .filter(v -> v.predicate.apply(o))
        .findFirst();

    firstError.ifPresent(e -> LOG.error("error code " + e.code));
    return firstError.isPresent();
}