Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 avoiding lots of if/else statements

I have something that looks like this:

 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;
}

What is the cleanest way of writing this in java 8 with lambdas?

like image 200
Mihai Avatar asked Mar 20 '17 18:03

Mihai


3 Answers

Use polymorphism for this. Create a class for every logical validator and chain them in the list. Here is nice answer with something you need: https://stackoverflow.com/a/23501390/1119473

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

implementation:

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;
    }
}

Calling validation chain:

List<Validator> validators = ... create ArrayList of needed Validators
for (Validator v : validators) {
if (!v.validate(object)) { 
  ... throw exception, you know validator and object here
}
like image 118
Gondy Avatar answered Nov 11 '22 21:11

Gondy


I might return the error but this would still use a few if's

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;
}

This way you could unit test this method to see if it return the error you expect for different invalid objects.

I want to get rid of 50 if/else statements.

If you have 50 conditions and they all value different results you will need to do 50 checks. You could change the structure like this.

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;
}

However, personally this is not clearer and would be harder to debug e.g. breakpoint.

like image 21
Peter Lawrey Avatar answered Nov 11 '22 21:11

Peter Lawrey


Use java.util.function.Predicate interface:

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);

Except this will give you 50 Predicate one-line definitions, they'll just be a bit more compact.

like image 24
dev8080 Avatar answered Nov 11 '22 22:11

dev8080