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."
:-).)
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With