有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

在异常中提供附加信息的java可持续方法?

我正在寻找一种向最终用户提供多条异常信息的方法。例如,扩展异常的显而易见的解决方案就是以文本形式结束代码

throw new MyException("Bad data", "The data you entered is incorrect", "http://www.example.com/moreinfo/baddata");

这很快就变得不可行了

然后我研究了一种目录方法,但这种方法过于集中,每次抛出异常时都需要从一个文件跳到另一个文件。我现在考虑使用静态ErrorInfoMap类的混合方法,该类包含从键到更详细信息的映射。然后,每个类都有一个静态部分,其中包含自己的错误映射,因此使用引发上述异常的类作为示例,我将其更改为:

throw new MyException("Bad data");

在班级的最底层会有这样的东西:

static {
  ErrorInfoMap.put("Bad data", new ErrorInfo("The data you entered is incorrect", "http://www.example.com/moreinfo/baddata"));
  // Information for other exceptions thrown by this class goes here
}

它允许异常处理程序在需要时获取附加信息。这是解决这个问题的好方法,还是有更好的方法来处理这个问题


共 (3) 个答案

  1. # 1 楼答案

    您可以始终将“MyException”作为超类,并将特定类型的错误作为其子类型。对于错误消息,您可以在子类型上使用静态常量来存储不同类型的错误

    例如

    Exception    
        -> MyException
          -> BadDataException
          -> InvalidUserException
    

    等等

    会是这样的:

    throw new BadDataException(BadDataException.DATA_TOO_LONG);
    
  2. # 2 楼答案

    替代混合方法的另一种方法是将错误映射放在异常本身中。当用Bad data初始化MyException时,在您显示的ErrorInfo中添加,但也为MyException提供一系列构造函数,允许您覆盖或补充Bad data含义的默认定义

  3. # 3 楼答案

    我不知道你所说的“目录方法”到底是什么意思(你能提供一个参考或更详细的描述吗?)但是从您提供的信息来看,我不清楚静态ErrorInfoMap如何避免“过于集中,每次抛出异常时都需要从一个文件跳到另一个文件”的问题

    对我来说,有几种选择,具体取决于您需要完成的任务:

    1. 创建一个根类ExceptionTemplate,它扩展Exception,并执行您希望所有异常执行的任何可重复行为。格式化的toString()方法就是一个很好的例子。根据您的具体目标,您可能希望让您的异常实现构建器模式,如下所示:

      throw new BadDataException("Supplied data is not valid")
            .expected("a positive integer")
            .referenceUrl("http://www.example.com/moreinfo/baddata");
      
    2. 避免使用枚举或子类可以使用的stringly-typed解决方案。如果您不需要在运行时定义新的异常类型(如果您这样做了,则表明您的设计存在更深层次的错误),并且有一个包含构造异常所需的所有信息的枚举:

      public class EnumException extends Exception {
          private EnumException() {} // prevent objects from being instantiated elsewhere
      
          public enum Type {
              BAD_DATA("Bad Data","Supplied data is not valid", "http://www.example.com/moreinfo/baddata"),
              MISSING_DATA("Missing Data","Required data not found", "http://www.example.com/moreinfo/missingdata");
      
              Type(String title, String genericMessage, String url) {
                  // Store input
              }
      
              public EnumException exception() {
                  // construct your exception
                  return new EnumException();
              }
          }
      }
      

      可以通过以下方式调用:

      // note no `new` - the exception is returned by the enum
      throw EnumException.Type.BAD_DATA.exception().expected("a positive integer");
      

      这样做的好处是确保编译时类型的安全性,同时还可以灵活地在一个位置定义不同类型的异常

    3. 创建大量异常。我仍然不能完全确定您对创建一系列异常有什么异议。您正在寻找“提供附加信息”的方法,但声称“扩展异常的显而易见的解决方案最终是通过文本分发代码”。不应该是这样。Exception的每个子类都应包含所有必要的信息,但只能在构建时提供的信息除外。因此,应该有最小的“文本分布在整个代码中”,因为任何锅炉板/可重用字符串都应该在Exception类中,而不是在其他任何地方

      public class DocumentedException extends Exception
      {
          private String title;
          private String genericMessage;
          private String detailedMessage;
          private String url;
      
          // Generally avoid this long constructor, and define subclasses that only need detailedMessage
          public DocumentedException(String t, String g, String d, String u) {
              super(g + " - " + d); // sets the getMessage() return value to something sane
              title = t;
              genericMessage = g;
              detailedMessage = d;
              url = u;
          }
      
          public String toString() {
              return title.toUpperCase()+"\n"+
                  genericMessage+"\n"+
                  detailedMessage+"\n"+
                  "More info on this error: "+url+"\n";
          }
      
          public static class BadData extends DocumentedException {
              public BadData(String details) {
                  super("Bad Data", "Supplied data is not valid", details, "http://www.example.com/moreinfo/baddata");
              }
          }
      
          public static class MissingData extends DocumentedException {
              public MissingData(String details) {
                  super("Missing Data", "Required data not found", details, "http://www.example.com/moreinfo/missingdata");
              }
          }
      }
      

      然后,您只需通过以下方式调用:

      throw new DocumentedException.BadData("Username cannot contain whitespace");
      

      当然,如果您希望定期对用户名错误发出警告,您可以创建一个附加类:

      public static class BadUsername extends BadData {
          public BadUsername() {
              super("Usernames can only contain letters, numbers, and underscores");
          }
      }
      

      同样,我们的目标是显式定义一个异常层次结构,以处理您预期需要处理的所有情况,从而避免在整个应用程序中重复定义相同的字符串。我个人喜欢上面使用的将异常分组到内部类模式,它可以让您非常明确地处理错误,而不必创建数百个需要经常查看的愚蠢的存根java文件。我想说的是,每个主要包都应该有一个关联的异常保持类,该类定义了该包的所有必要异常