查找 Java Enum 的最佳实践
我们有一个 REST API,客户端可以提供代表服务器上 Java 枚举中定义的值的参数。
因此我们可以提供一个描述性错误,我们将这个 lookup
方法添加到每个 Enum 中。看起来我们只是在复制代码(不好)。有更好的做法吗?
public enum MyEnum {
A, B, C, D;
public static MyEnum lookup(String id) {
try {
return MyEnum.valueOf(id);
} catch (IllegalArgumentException e) {
throw new RuntimeException("Invalid value for my enum blah blah: " + id);
}
}
}
更新:valueOf(..)
提供的默认错误消息为No enum const class abcMyEnum.BadValue
。我想从 API 中提供更具描述性的错误。
We have a REST API where clients can supply parameters representing values defined on the server in Java Enums.
So we can provide a descriptive error, we add this lookup
method to each Enum. Seems like we're just copying code (bad). Is there a better practice?
public enum MyEnum {
A, B, C, D;
public static MyEnum lookup(String id) {
try {
return MyEnum.valueOf(id);
} catch (IllegalArgumentException e) {
throw new RuntimeException("Invalid value for my enum blah blah: " + id);
}
}
}
Update: The default error message provided by valueOf(..)
would be No enum const class a.b.c.MyEnum.BadValue
. I would like to provide a more descriptive error from the API.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
也许您可以实现通用静态
lookup
方法。像这样
然后你可以
或显式调用实用程序类查找方法。
Probably you can implement generic static
lookup
method.Like so
Then you can
or call explicitly utility class lookup method.
看起来你在这里的做法很糟糕,但不是你想象的那样。
捕获
IllegalArgumentException
来重新抛出另一个带有更清晰消息的RuntimeException
可能看起来是个好主意,但事实并非如此。因为这意味着您关心异常中的消息。如果您关心异常中的消息,则意味着您的用户以某种方式看到了您的异常。这很糟糕。
如果要向用户提供明确的错误消息,则应在解析用户输入时检查枚举值的有效性,并在用户输入不正确时在响应中发送相应的错误消息。
像这样的东西:
Looks like you have a bad practice here but not where you think.
Catching an
IllegalArgumentException
to rethrow anotherRuntimeException
with a clearer message might look like a good idea but it is not. Because it means you care about messages in your exceptions.If you care about messages in your exceptions, then it means that your user is somehow seeing your exceptions. This is bad.
If you want to provide an explicit error message to your user, you should check the validity of the enum value when parsing user input and send the appropriate error message in the response if user input is incorrect.
Something like:
当涉及到 Rest/Json 等时,我们所有的枚举都是这样的。
它的优点是错误是人类可读的,并且还为您提供了可接受的值列表。我们使用自定义方法 MyEnum.fromString 而不是 MyEnum.valueOf,希望它有所帮助。
例如,如果您调用,
您将收到一个 IllegalArgumentException 并显示以下消息:
您可以将 IllegalArgumentException 更改为自定义异常。
We do all our enums like this when it comes to Rest/Json etc.
It has the advantage that the error is human readable and also gives you the accepted value list. We are using a custom method MyEnum.fromString instead of MyEnum.valueOf, hope it helps.
so for example if you call
you'll get an IllegalArgumentException with the following message:
you can change the IllegalArgumentException to a custom one.
Guava 还提供了这样的函数,如果找不到枚举,它将返回一个
Optional
。Guava also provides such function which will return an
Optional
if an enum cannot be found.Apache Commons Lang 3 包含 EnumUtils 类。如果您没有在项目中使用 Apache Commons,那么您就做错了。你正在重新发明轮子!
我们可以使用许多很酷的方法而不会引发异常。例如:
Apache Commons Lang 3 contais the class EnumUtils. If you aren't using Apache Commons in your projects, you're doing it wrong. You are reinventing the wheel!
There's a dozen of cool methods that we could use without throws an Exception. For example:
如果您希望查找不区分大小写,您可以循环遍历这些值,使其更加友好:
If you want the lookup to be case insensitive you can loop through the values making it a little more friendly:
为什么我们必须写那 5 行代码?
Why do we have to write that 5 line code ?
IllegalArgumentException 中的错误消息已经具有足够的描述性。
您的方法从特定例外中产生了一般例外,并简单地改写了相同的消息。开发人员更喜欢特定的异常类型,并且可以适当地处理这种情况,而不是尝试处理 RuntimeException。
如果目的是使消息对用户更加友好,那么对枚举值的引用无论如何都与它们无关。让 UI 代码决定应该向用户显示什么,UI 开发人员最好使用 IllegalArgumentException。
The error message in IllegalArgumentException is already descriptive enough.
Your method makes a generic exception out of a specific one with the same message simply reworded. A developer would prefer the specific exception type and can handle the case appropriately instead of trying to handle RuntimeException.
If the intent is to make the message more user friendly, then references to values of enums is irrelevant to them anyway. Let the UI code determine what should be displayed to the user, and the UI developer would be better off with the IllegalArgumentException.
更新:正如 GreenTurtle 正确评论的那样,以下内容是错误的,
我只会写
这可能比捕获运行时异常的性能要差,但可以使代码更清晰。捕获此类异常总是一个坏主意,因为它很容易误诊。
当比较值的检索本身导致 IllegalArgumentException 时会发生什么?然后,这将被视为枚举器的不匹配值。
update: As GreenTurtle correctly remarked, the following is wrong
I would just write
This is possibly less performant than catching a runtime exception, but makes for much cleaner code. Catching such exceptions is always a bad idea, since it is prone to misdiagnosis.
What happens when the retrieval of the compared value itself causes an IllegalArgumentException ? This would then be treaten like a non matching value for the enumerator.
您可以使用静态查找映射来避免异常并返回 null,然后根据需要抛出:
You can use a static lookup map to avoid the exception and return a null, then throw as you'd like: