0

我正在寻找一种方法来向最终用户提供多条异常信息。扩展 Exception 的明显解决方案以文本分布式吞吐量代码结束,例如

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
}

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

4

3 回答 3

0

您的混合方法的替代方法是将错误映射放在异常本身中。何时使用add in 进行MyException初始化,但还提供了一系列构造函数,允许您覆盖或补充默认定义的含义。Bad dataErrorInfoMyExceptionBad data

于 2013-01-06T00:14:27.010 回答
0

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

例如

Exception    
    -> MyException
      -> BadDataException
      -> InvalidUserException

等等

会像这样抛出:

throw new BadDataException(BadDataException.DATA_TOO_LONG);
于 2013-01-06T00:18:49.003 回答
0

我不确定您所说的“目录方法”到底是什么意思(您能否提供参考或更详细的描述?)但是根据您提供的信息,我不清楚静态 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. 避免使用枚举或子类的字符串类型解决方案。如果您不需要在运行时定义新的异常类型(如果您这样做,那应该是一个危险信号,表明您的设计存在更深层次的错误)并且有一个包含构建异常所需的所有必要信息的枚举:

    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 的每个子类都应该包含所有必要的信息,除了只能在构建时提供的信息。因此,应该有最少的“分布在整个代码中的文本”,因为任何样板/可重用字符串都应该在 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");
        }
    }
    

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

于 2013-01-06T18:34:53.443 回答