Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return a flag plus an optional message in Java?

I want to write a method in Java that verifies that some conditions hold on some data, and acknowledges that the data is valid or produces an appropriate error message otherwise.

The problem is that we cannot return more than one thing from a method, so I'm wondering what the best solution is (in terms of readability and maintainability).

First solution. Easy, but we cannot know what exactly made the check fail:

boolean verifyLimits1(Set<Integer> values, int maxValue) {
    for (Integer value : values) {
        if (value > maxValue) {
            return false; // Out of limits
        }
    }
    return true; // All values are OK
}

Second solution. We have the message, but we are using exceptions in a way that we shouldn't (besides, it should probably be a domain-specific checked exception, too much overhead IMO):

void verifyLimits2(Set<Integer> values, int maxValue) {
    for (Integer value : values) {
        if (value > maxValue) {
            throw new IllegalArgumentException("The value " + value + " exceeds the maximum value");
        }
    }
}

Third solution. We have a detailed message, but the contract is not clean: we make the client check whether the String is empty (for which he needs to read the javadoc).

String verifyLimits3(Set<Integer> values, int maxValue) {
    StringBuilder builder = new StringBuilder();
    for (Integer value : values) {
        if (value > maxValue) {
            builder.append("The value " + value + " exceeds the maximum value/n");
        }
    }
    return builder.toString();
}

Which solution would you recommend? Or is there a better one (hopefully!)?

(Note: I made up this little example, my real use case concerns complex conditions on heterogeneous data, so don't focus on this concrete example and propose Collections.max(values) > maxValue ? "Out of range." : "All fine." :-).)

like image 367
espinchi Avatar asked Nov 28 '22 11:11

espinchi


2 Answers

The solution is simple: create a custom VerificationResult class. It can have a boolean status flag and a String message field, among other things you may want to add. Instead of returning either a String or a boolean, return a VerificationResult.

Also, depending on context, throwing an exception may actually end up being the right thing to do. This has to be considered on a case-by-case basis based on concrete scenarios, though.


Alternative solution: a last error query

Another option you can use is to have the verification return a boolean, and have a separate method e.g. String whatWentWrongLastTime() that a user can query in case false is returned. You'd have to be very careful with any concurrency issues etc. that may overwrite the "last" verification error.

This is the approach taken by e.g. java.util.Scanner, which does NOT throw any IOException (except for the constructors). To query if something "went wrong", you can query its ioException() method, which returns the last IOException, or null if there wasn't any.

like image 44
polygenelubricants Avatar answered Dec 05 '22 15:12

polygenelubricants


If you need more than a single value you should return a simple class instance instead. Here is an example of what we use in some cases:

public class Validation {
    private String          text    = null;
    private ValidationType  type    = ValidationType.OK;

    public Validation(String text, ValidationType type) {
        super();
        this.text = text;
        this.type = type;
    }
    public String getText() {
        return text;
    }
    public ValidationType getType() {
        return type;
    }
}

This uses a simple Enumeration for the type:

public enum ValidationType {
    OK, HINT, ERROR;
}

A validator method could look like this:

public Validation validateSomething() {
    if (condition) {
        return new Validation("msg.key", ValidationType.ERROR);
    }
    return new Validation(null, ValidationType.OK);
}

That's it.

like image 116
Daniel Bleisteiner Avatar answered Dec 05 '22 17:12

Daniel Bleisteiner