如何在 Java 中返回一个标志和一条可选消息?
我想用 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
}
第二种解决方案。我们有消息,但我们以不应该的方式使用异常(此外,它可能应该是特定于域的检查异常,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");
}
}
}
第三种解决方案。我们有一个详细的消息,但契约并不干净:我们让客户端检查 String 是否为空(为此他需要阅读 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();
}
您会推荐哪种解决方案?或者有更好的吗(希望如此!)?
(注意:我编了这个小例子,我的实际用例涉及异构数据的复杂条件,因此不要关注这个具体示例并提出Collections.max(values) > maxValue ?“超出范围。 " : "一切都好。"
:-).)
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."
:-).)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
如果您需要多个值,您应该返回一个简单的类实例。下面是我们在某些情况下使用的示例:
这对类型使用了简单的枚举:
验证器方法可能如下所示:
就是这样。
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:
This uses a simple Enumeration for the type:
A validator method could look like this:
That's it.
解决方案很简单:创建一个自定义
VerificationResult
类。它可以有一个布尔状态标志和一个字符串消息字段,以及您可能想要添加的其他内容。返回VerificationResult
,而不是返回String
或boolean
。此外,根据上下文,抛出异常实际上可能是正确的做法。不过,这必须根据具体情况进行具体情况考虑。
替代解决方案:最后一个错误查询
您可以使用的另一个选项是让验证返回一个
boolean
,并有一个单独的方法,例如用户可以查询的String whatWentWrongLastTime()
如果返回false
。您必须非常小心任何可能覆盖“最后”验证错误的并发问题等。这是例如
java. util.Scanner
,它不会抛出任何IOException
(构造函数除外)。要查询是否出现“错误”,您可以查询其ioException()
方法,返回最后一个IOException
,如果没有则返回null
任何。The solution is simple: create a custom
VerificationResult
class. It can have aboolean status
flag and aString message
field, among other things you may want to add. Instead of returning either aString
or aboolean
, return aVerificationResult
.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 casefalse
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 anyIOException
(except for the constructors). To query if something "went wrong", you can query itsioException()
method, which returns the lastIOException
, ornull
if there wasn't any.IllegalArgumentException
是正确的方法,如果它确实意味着:您向方法的调用者(契约)提出一些要求,但它们被忽略。在这种情况下,IAE 是合适的。如果这不能反映您的用例,我会使用其他解决方案之一。
IllegalArgumentException
is the way to go if it really means that: You make some demands to the caller of the method (the contract) but they are ignored. In this case an IAE is appropriate.If that doesn't reflect your use case, I'd use one of the solutions of the others.
另一种方法 - 使用 Status 对象:
要验证,如果输入有效,则返回
Status.OK
或创建新的状态消息。使用验证器很简单:
Another approach - use a Status object:
To Verify, either return
Status.OK
if the input is valid or create a new Status message.Using the verifier is simple as that:
我认为最好的解决方案是创建您自己的异常,其中包含您想要的尽可能多的错误描述信息。它不应该是 RuntimeException 子类;您希望调用者必须处理验证失败的情况,因为太多程序员未能进行错误处理。通过将失败设置为已检查的异常,您可以强迫他们(您?)至少放入一些内容,并且如果他们对此愚蠢的话,代码审查可以相对轻松地发现。我知道这很官僚,但从长远来看它提高了代码质量。
完成此操作后,请考虑是否需要在成功验证时返回一个值。仅当该值包含“哦,我现在到了这里”(这从程序流程中显而易见)以外的信息时才返回该值。如果您确实需要返回结果,并且它需要是一个复杂的结果,请务必使用自定义类实例来保存它!不这样做就等于拒绝使用该语言为您提供的设施。
I think the best solution is to create your own exception that holds as much error description information as you want. It should not be a
RuntimeException
subclass; you want callers to have to deal with a failure to validate, because too many programmers fail to put in error handling. By making failure a checked exception, you force them (you?) to put at least something in, and code review can relatively easily pick up if they're being stupid about it. I know it's bureaucratic, but it improves code quality in the long run.Once you've done that, consider whether you need to return a value on successful validation or not. Only return a value if that value contains information other than “oh, I've got here now” (which is obvious from the program flow). If you do need to return a result, and it needs to be a complex result, by all means use a custom class instance to hold it! To not do that is just refusing to use the facilities that the language gives you.
在这种情况下,返回“false”的方法看起来像是业务逻辑结果,而不是真正的异常。因此 verifyLimits 无论如何都应该返回结果,而不是在“false”时抛出异常。
In this case, the method returning 'false' looks like a business logic result rather than a real Exception. So verifyLimits should return a result anyway rather than throwing an Exception when 'false'.
如果您检查合理数量的项目并关心您创建的用于返回结果的对象的数量,则可以使用带有
接口
的替代方案。首先,您创建一个在违反限制时调用的
接口
:您可以添加参数和/或方法。例如,违规值的实际位置可以是一个参数。作为另一个示例,添加一个在每次测试结束时调用的方法,其中包含检查次数和违规次数的参数。
该接口的实现作为参数传递给您的检查方法。每当违反其中一个限制时,它都会调用侦听器:
最后,您只需通过实现接口即可使用此方法:
Android 和其他 GUI 接口大量使用此模式。对我来说,当结果包含多个值时,它得到了首选方法。
If you check a reasonable amount of items and be concerned about the number of objects you create to return the result, there's an alternative with
interface
.First you create an
interface
to be called whenever the limit is violated:You can add parameters and/or methods. For example the actual position of the violating value could be a parameter. As antother example add a method that is called at the end of each test with parameters for the number of checks and the number of violates.
An implementation of this interface is passed as argument to your checking method. It calls the listener every time one of the limits is violated:
And finally you use this method just by implementening the interface:
Android and other GUI Interfaces use this pattern heavily. For me, it got the prefered method when the result contains more then one value.
创建您自己的从 RuntimeException 扩展的自定义未检查异常。
Create your own custom unchecked exception that extends from RuntimeException.
您可以使用简单的键值对,通过使用 HashMap,当然还有预定义的键。
返回 HashMap 以进行进一步处理。
You can use simple Key-Value, by using HashMap, of course with predefined keys.
Return the HashMap for further processing.
我会投票支持第二种解决方案(使用 IllegalArgumentException 或定义特定的解决方案)。
一般来说,好的做法是确保可以安全地忽略方法的任何返回值(因为有一天有人会忘记检查它),并且在忽略返回值不安全的情况下,最好抛出/捕获异常。
I would vote for the second solution (either using IllegalArgumentException or defining a specific one).
Generally good practice is ensuring that any return value from a method can safely be ignored (because some day somebody will forget to check it anyway) and, in cases when ignoring a return value is unsafe, it's always better to throw/catch an exception.
您可以将标志作为布尔值返回,并记录未验证的测试结果,无论如何您都想记录它们......
假设您将检查数百万个值。
You could return the flag as a boolean and log the results of tests that don't verify, you'll want to log them anyhow...
presuming you'll be checking millions of values.