查找Java枚举的最佳实践

我们有一个REST API,客户端可以在其中提供表示Java Enums中服务器上定义的值的参数。

因此,我们可以提供一个描述性错误,我们将此valueOf(..)方法添加到每个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 a.b.c.MyEnum.BadValue。我想从API中提供一个更具描述性的错误。

Marcus Leon asked 2020-08-02T10:08:59Z

10个解决方案

34 votes

可能可以实现通用的静态lookup方法。

像这样

public class LookupUtil {

public static > E lookup(Class e, String id) {

try {

E result = Enum.valueOf(e, id);

} catch (IllegalArgumentException e) {

// log error or something here

throw new RuntimeException(

"Invalid value for enum " + e.getSimpleName() + ": " + id);

}

return result;

}

}

那么你就可以

public enum MyEnum {

static public MyEnum lookup(String id) {

return LookupUtil.lookup(MyEnum.class, id);

}

}

或显式调用实用程序类查找方法。

Mykola Golubyev answered 2020-08-02T10:09:21Z

13 votes

看来您在这里有不好的作法,但在想不到的地方却没有。

捕获一个IllegalArgumentException以更清晰的消息重新抛出另一个RuntimeException,这似乎是个好主意,但事实并非如此。 因为这意味着您关心异常中的消息。

如果您关心异常中的消息,则意味着您的用户以某种方式看到了异常。 这不好。

如果要向用户提供显式错误消息,则应在解析用户输入时检查枚举值的有效性,如果用户输入不正确,则在响应中发送适当的错误消息。

就像是:

// This code uses pure fantasy, you are warned!

class MyApi

{

// Return the 24-hour from a 12-hour and AM/PM

void getHour24(Request request, Response response)

{

// validate user input

int nTime12 = 1;

try

{

nTime12 = Integer.parseInt(request.getParam("hour12"));

if( nTime12 <= 0 || nTime12 > 12 )

{

throw new NumberFormatException();

}

}

catch( NumberFormatException e )

{

response.setCode(400); // Bad request

response.setContent("time12 must be an integer between 1 and 12");

return;

}

AMPM pm = null;

try

{

pm = AMPM.lookup(request.getParam("pm"));

}

catch( IllegalArgumentException e )

{

response.setCode(400); // Bad request

response.setContent("pm must be one of " + AMPM.values());

return;

}

response.setCode(200);

switch( pm )

{

case AM:

response.setContent(nTime12);

break;

case PM:

response.setContent(nTime12 + 12);

break;

}

return;

}

}

Vincent Robert answered 2020-08-02T10:09:59Z

3 votes

为什么我们必须编写那5行代码?

public class EnumTest {

public enum MyEnum {

A, B, C, D;

}

@Test

public void test() throws Exception {

MyEnum.valueOf("A"); //gives you A

//this throws ILlegalargument without having to do any lookup

MyEnum.valueOf("RADD");

}

}

Kannan Ekanath answered 2020-08-02T10:10:19Z

3 votes

如果您希望查找不区分大小写,则可以遍历所有值,使其更加友好:

public enum MyEnum {

A, B, C, D;

public static MyEnum lookup(String id) {

boolean found = false;

for(MyEnum enum: values()){

if(enum.toString().equalsIgnoreCase(id)) found = true;

}

if(!found) throw new RuntimeException("Invalid value for my enum: " +id);

}

}

Adam answered 2020-08-02T10:10:39Z

3 votes

Guava还提供了这样的功能,如果找不到枚举,它将返回Optional。

Enums.getIfPresent(MyEnum.class, id).toJavaUtil()

.orElseThrow(()-> new RuntimeException("Invalid enum blah blah blah.....")))

Ken Chan answered 2020-08-02T10:10:59Z

2 votes

IllegalArgumentException中的错误消息已经足够描述。

您的方法会在特定消息中产生一般性异常,只需将其改写为相同的消息即可。 开发人员更喜欢特定的异常类型,并且可以适当地处理这种情况,而不必尝试处理RuntimeException。

如果要使消息更加用户友好,则对枚举值的引用无论如何都与它们无关。 让UI代码确定应向用户显示的内容,并且UI开发人员最好使用IllegalArgumentException。

Robin answered 2020-08-02T10:11:28Z

2 votes

更新:正如GreenTurtle正确指出的那样,以下错误

我只会写

boolean result = Arrays.asList(FooEnum.values()).contains("Foo");

这可能比捕获运行时异常的性能要差,但是可以使代码更简洁。 捕获此类异常始终是一个坏主意,因为它容易出错。当检索比较值本身导致IllegalArgumentException时会发生什么? 然后将其视为枚举器的不匹配值。

makrom answered 2020-08-02T10:11:57Z

2 votes

对于Rest / Json等,我们会像这样进行所有枚举。它的优点是该错误是人类可读的,并且还提供了可接受的值列表。 我们使用的是自定义方法MyEnum.fromString而不是MyEnum.valueOf,希望对您有所帮助。

public enum MyEnum {

A, B, C, D;

private static final Map NAME_MAP = Stream.of(values())

.collect(Collectors.toMap(MyEnum::toString, Function.identity()));

public static MyEnum fromString(final String name) {

MyEnum myEnum = NAME_MAP.get(name);

if (null == myEnum) {

throw new IllegalArgumentException(String.format("'%s' has no corresponding value. Accepted values: %s", name, Arrays.asList(values())));

}

return myEnum;

}

}

例如,如果您致电

MyEnum value = MyEnum.fromString("X");

您将收到带有以下消息的IllegalArgumentException:

“ X”没有相应的值。 接受的值:[A,B,C,D]

您可以将IllegalArgumentException更改为自定义对象。

Radu Sebastian LAZIN answered 2020-08-02T10:12:35Z

0 votes

您可以使用静态查找映射来避免该异常并返回null,然后根据需要抛出:

public enum Mammal {

COW,

MOUSE,

OPOSSUM;

private static Map lookup =

Arrays.stream(values())

.collect(Collectors.toMap(Enum::name, Function.identity()));

public static Mammal getByName(String name) {

return lookup.get(name);

}

}

mskfisher answered 2020-08-02T10:12:55Z

0 votes

Apache Commons Lang 3包含EnumUtils类。 如果您没有在项目中使用Apache Commons,那么您做错了。 您正在重新发明轮子!

我们可以使用很多很酷的方法而不会引发异常。 例如:

获取该类的枚举,如果找不到,则返回null。

此方法与Enum.valueOf的不同之处在于它不会抛出 无效的枚举名称,并且不区分大小写 名称的匹配。

EnumUtils.getEnumIgnoreCase(SeasonEnum.class, season);

Willian Crozeta answered 2020-08-02T10:13:28Z

java查询枚举_查找Java枚举的最佳实践相关推荐

  1. java查询序列_基于JAVA的苹果序列号查询api调用代码实例

    代码描述:基于JAVA的苹果序列号查询api调用代码实例 关联数据:苹果序列号 接口地址:http://www.juhe.cn/docs/api/id/37 1.[代码][Java]代码 import ...

  2. java 中的枚举_说说Java中的枚举(一)

    在实际编程中,往往存在着这样的"数据集",它们的数值在程序中是稳定的,而且"数据集"中的元素是有限的.例如星期一到星期日七个数据元素组成了一周的"数据 ...

  3. java enum int 转换为枚举_关于java:从枚举序号转换为枚举类型

    我有一个枚举类型ReportTypeEnum,它在所有类的方法之间传递,但是我需要在URL上传递它,所以我使用序数方法来获取int值.在我把它放到我的另一个JSP页面之后,我需要将它转换回一个Repo ...

  4. java什么是枚举_【JAVA】浅谈java枚举类

    一.什么情况下使用枚举类? 有的时候一个类的对象是有限且固定的,这种情况下我们使用枚举类就比较方便? 二.为什么不用静态常量来替代枚举类呢? public static final int SEASO ...

  5. java正则表达式 匹配()_学习Java正则表达式(匹配、替换、查找)

    import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; public c ...

  6. c++ main函数调用 类中的枚举_为啥用枚举,枚举有哪些用法?

    Java基础:枚举的用法与原理 在学习过程中,我们也只是在定义常量的时候,会意识到枚举的存在,而定义常量其实可以在类中实现,这时就会感觉枚举有点鸡肋.但在实际项目开发的过程中,枚举因相当迷人的特性而受 ...

  7. java核心教程_核心Java教程

    java核心教程 Welcome to Core Java Tutorial. I have written a lot on Core Java and Java EE frameworks. Th ...

  8. java初始化数据报_初始化java原因

    虚拟机的类加载机制 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类 即虚拟机的类加载机制. 在Java中,类型的加载.链接 ...

  9. java 流程控制_《Java基础知识》Java流程控制

    流程控制分类: 一.顺序结构 如果没有流程控制(即没有分支结构和循环结构),Java方法里面的语句是一个顺序执行流,从上到下依次执行每条语句. 二.分支结构 1.if语句 if语句使用布尔表达式或者布 ...

最新文章

  1. 使用liner、feather、multiband对已经拼接的数据进行融合(下)
  2. 如何做EL表达式能调用的函数-小例子(转)
  3. UVA11078开放式学分制(前面-后面的最大值)
  4. 修改默认runlevel
  5. Android GridView的使用方法
  6. VMware Device/Credential Guard 不兼容
  7. PageCollectionView[Bug],使用Filter的时候,删除集合中的元素,会导致ArgumentOutOfRangeException...
  8. 【最全资料下载】Kubernetes and Cloud Native Meetup (北京站)
  9. mysql存储java对象_Mysql存储java对象 | 学步园
  10. [Contest20180116]随机游走
  11. SOME/IP不等同于SOA,CommonAPI-RPC通信和vsomeip基于消息通信
  12. deepin 惠普打印驱动安装
  13. 【数理统计】02. 抽样分布与次序统计量
  14. lpx寒假作业案例14
  15. 关于求职及面试的一些小技巧
  16. Esxi通过U盘启动
  17. No Matter What
  18. 三菱PLC编程与案例精讲之ST语言
  19. GPT-2 论文翻译
  20. 利用BibTeX批量导入参考文献

热门文章

  1. span文字强制换行
  2. 跨境电商“三分天下”格局已定,洋码头再融资也难当“领头羊”?
  3. win10占用内存过高的解决办法
  4. python openpyxl详解_python openpyxl使用方法详解
  5. 购买单反相机的注意事项(转载)
  6. 国内外各类信息安全和网络对抗竞赛介绍
  7. 获取textview行数
  8. kernel(三)NAND FLASH
  9. Ignored attempt to cancel a touchmove event with cancelable=false
  10. python实现滑动验证码_使用python实现滑动验证码