查找 Java 枚举的最佳实践

2022-08-31 20:14:06

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

因此,我们可以提供一个描述性错误,我们将此方法添加到每个枚举中。似乎我们只是在复制代码(不好)。有没有更好的做法?lookup

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);
        }
    }
}

更新:提供的默认错误消息为 。我想从API中提供更具描述性的错误。valueOf(..)No enum const class a.b.c.MyEnum.BadValue


答案 1

也许你可以实现泛型静态方法。lookup

这样

public class LookupUtil {
   public static <E extends Enum<E>> E lookup(Class<E> 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);
   }
}

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


答案 2

看起来你在这里有一个不好的做法,但不是你想象的地方。

抓住一个用更清晰的信息重新抛出另一个可能看起来是一个好主意,但事实并非如此。因为这意味着您关心异常中的消息。IllegalArgumentExceptionRuntimeException

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

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

像这样:

// 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;
    }
}