如何在Java中返回标志和可选消息?

如何在Java中返回标志和可选消息?,java,readability,Java,Readability,我想用Java编写一个方法,验证某些条件是否适用于某些数据,并确认数据有效,否则会生成相应的错误消息 问题是我们不能从一个方法返回多个内容,所以我想知道最好的解决方案是什么(在可读性和可维护性方面) 第一个解决方案。很简单,但我们无法知道到底是什么导致检查失败: boolean verifyLimits1(Set<Integer> values, int maxValue) { for (Integer value : values) { if (value

我想用Java编写一个方法,验证某些条件是否适用于某些数据,并确认数据有效,否则会生成相应的错误消息

问题是我们不能从一个方法返回多个内容,所以我想知道最好的解决方案是什么(在可读性和可维护性方面)

第一个解决方案。很简单,但我们无法知道到底是什么导致检查失败:

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
}
boolean verifyLimits1(设置值,int-maxValue){
for(整数值:值){
如果(值>最大值){
返回false;//超出限制
}
}
返回true;//所有值都正常
}
第二个解决方案。我们有这个消息,但我们正在以一种我们不应该使用的方式使用异常(此外,它可能应该是一个特定于域的已检查异常,在我看来开销太大了):

void verifyLimits2(设置值,int maxValue){
for(整数值:值){
如果(值>最大值){
抛出新的IllegalArgumentException(“值“+value+”超过最大值”);
}
}
}
第三个解决方案。我们有一条详细的消息,但合同并不明确:我们让客户机检查字符串是否为空(他需要读取javadoc)

String verifyLimits3(设置值,int-maxValue){
StringBuilder=新的StringBuilder();
for(整数值:值){
如果(值>最大值){
builder.append(“值“+value+”超过最大值/n”);
}
}
返回builder.toString();
}
您会推荐哪种解决方案?还是有更好的(希望如此!)


(注意:我编了一个小例子,我的实际用例涉及异构数据的复杂条件,所以不要把重点放在这个具体的例子上,建议
Collections.max(values)>maxValue?“超出范围。”:“一切正常。”
:-)

解决方案很简单:创建一个自定义的
验证结果
类。它可以有一个
布尔状态
标志和一个
字符串消息
字段,以及您可能需要添加的其他内容。不是返回
字符串
布尔值
,而是返回
验证结果

此外,根据上下文的不同,抛出异常实际上可能是正确的做法。不过,这必须根据具体情况逐案考虑


替代解决方案:最后一个错误查询 您可以使用的另一个选项是让验证返回一个
布尔值
,并有一个单独的方法,例如
字符串whatwentworlasttime()
,用户可以在返回
false
时查询该方法。您必须非常小心任何可能会覆盖“最后一次”验证错误的并发性问题等


这是例如所采取的方法,它不会抛出任何
IOException
(构造函数除外)。要查询是否出现“错误”,您可以查询其方法,该方法返回最后一个
IOException
,如果没有,则返回
null

创建您自己的自定义未检查异常,该异常扩展自RuntimeException

您可以使用简单的键值,通过使用HashMap,当然还有预定义的键。
返回HashMap以进行进一步处理。

如果需要多个值,则应返回一个简单的类实例。以下是我们在某些情况下使用的示例:

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;
    }
}
这对类型使用了一个简单的枚举:

public enum ValidationType {
    OK, HINT, ERROR;
}
验证器方法可能如下所示:

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

就是这样。

IllegalArgumentException
是一种方法,如果它真的意味着:你向方法(契约)的调用者提出一些要求,但它们被忽略了。在这种情况下,IAE是合适的


如果这不能反映您的用例,我将使用其他解决方案之一。

在这种情况下,返回“false”的方法看起来像是业务逻辑结果,而不是真正的异常。所以verifyLimits无论如何都应该返回一个结果,而不是在“false”时抛出异常

 class VerifyLimitsResult{
       //Ignore get, set methods
        Integer maxValue;
        Integer value;

        public VerifyLimitsResult(Integer maxValue, Integer value) {
           this.maxValue = maxValue;
           this.value = value;
        }

        public boolean isOK(){
           return value==null;
        }

        public String getValidationInfo(){
           if(isOK()){
              return "Fine";
           }else{
              return "The value " + value + " exceeds the maximum value/n"
           }
        }
 }
....
VerifyLimitsResult verifyLimits4(Set<Integer> values, int maxValue) {

         for (Integer value : values) {
             if (value > maxValue) {
                   return new VerifyLimitsResult(maxValue, value);  
            }
        }
         return new VerifyLimitsResult(maxValue, null);  
}
类验证限制结果{
//忽略get、set方法
整数最大值;
整数值;
公共VerifyLimitsResult(整型maxValue,整型值){
this.maxValue=maxValue;
这个值=值;
}
公共布尔isOK(){
返回值==null;
}
公共字符串getValidationInfo(){
if(isOK()){
退回“罚款”;
}否则{
返回“值”+值+“超过最大值/n”
}
}
}
....
VerifyLimitsResult verifyLimits4(设置值,int maxValue){
for(整数值:值){
如果(值>最大值){
返回新的VerifyLimitsResult(maxValue,value);
}
}
返回新的VerifyLimitsResult(maxValue,null);
}

我将投票支持第二种解决方案(使用IllegalArgumentException或定义特定的解决方案)


一般来说,好的做法是确保可以安全地忽略方法的任何返回值(因为总有一天会有人忘记检查它),并且,在忽略返回值不安全的情况下,最好抛出/捕获异常。

另一种方法-使用状态对象:

 public class Status {
   public final static Status OK = new Status("OK");
   private String message;
   public Status(String message) { this.message = message; }
   public String getMessage() { return message; }
 }
若要验证,请返回
状态。确定
输入是否有效,或创建新的状态消息

 public Status validate(Integer input, int maxValue){
   if (input > maxValue) {
     return new Status(
         String.format("%s value out of limits (maxValue=%s)", input, maxValue);
   }

   return Status.OK;
 }
使用验证器很简单,如下所示:

 Status status = validate(i, 512);
 if (status != Status.OK) {
   // handle the error
 }

我认为最好的解决方案是创建您自己的异常,该异常保存您想要的尽可能多的错误描述信息。它不应该是
RuntimeException
子类;您希望调用方必须处理验证失败,因为太多的程序员无法进行错误处理。通过将失败设置为选中的异常,您可以强制他们(您?)至少放入一些内容,代码审查可以
 public Status validate(Integer input, int maxValue){
   if (input > maxValue) {
     return new Status(
         String.format("%s value out of limits (maxValue=%s)", input, maxValue);
   }

   return Status.OK;
 }
 Status status = validate(i, 512);
 if (status != Status.OK) {
   // handle the error
 }
// A simple listener to be implemented by the calling method.
public interface OutOfLimitListener {
    // Called whenever a limit is violated.
    public void outOfLimit(int value, int maxValue);

    // ... Add additional results as parameters
    // ... Add additional states as methods
}
private boolean verifyLimits(Set<Integer> values, int maxValue, OutOfLimitListener listener) {
    boolean result = true; // Assume all values are OK
    for (Integer value : values) {
        if (value > maxValue) {
            listener.outOfLimit(value, maxValue);
            result = false; // At least one was out of limits
        }
    }
    return result;
}
@Test
public final void test() throws IOException, InterruptedException {
    // Make up a test set of random numbers
    Set<Integer> testSet = new HashSet<Integer>();
    for(int i=0; i<10; i++) testSet.add((int) (Math.random() * 100));

    // Implement the interface once with appropriate reaction to an out-of-limit condition      
    OutOfLimitListener listener = new OutOfLimitListener() {
        @Override
        public void outOfLimit(int value, int maxValue) {
            System.out.printf("The value %d exceeds the maximum value %d\n", value, maxValue);
        }
    };

    // Call verification
    verifyLimits(testSet, 50, listener);
}