在Java中定义错误代码/字符串的最佳方法?

在Java中定义错误代码/字符串的最佳方法?,java,enums,Java,Enums,我正在用Java编写一个web服务,并试图找出定义错误代码及其相关错误字符串的最佳方法。我需要一个数字错误代码和一个错误字符串组合在一起。错误代码和错误字符串都将发送到访问web服务的客户端。例如,当发生SQLException时,我可能希望执行以下操作: // Example: errorCode = 1, // errorString = "There was a problem accessing the database." throw new SomeWebServ

我正在用Java编写一个web服务,并试图找出定义错误代码及其相关错误字符串的最佳方法。我需要一个数字错误代码和一个错误字符串组合在一起。错误代码和错误字符串都将发送到访问web服务的客户端。例如,当发生SQLException时,我可能希望执行以下操作:

// Example: errorCode = 1, 
//          errorString = "There was a problem accessing the database."
throw new SomeWebServiceException(errorCode, errorString);
客户端程序可能会显示以下消息:

“发生了错误#1:出现了错误 访问数据库时出现问题。“

我的第一个想法是使用错误代码的
Enum
,并重写
toString
方法来返回错误字符串。以下是我的想法:

public enum Errors {
  DATABASE {
    @Override
    public String toString() {
      return "A database error has occured.";
    }
  },

  DUPLICATE_USER {
    @Override
    public String toString() {
      return "This user already exists.";
    }
  },

  // more errors follow
}

我的问题是:有没有更好的方法?我更喜欢代码解决方案,而不是从外部文件读取。我在这个项目中使用Javadoc,能够在线记录错误代码并在文档中自动更新它们会很有帮助。

当然有更好的enum解决方案实现(通常非常好):

您可能希望重写toString()以只返回描述-不确定。无论如何,主要的一点是,您不需要为每个错误代码分别重写。还请注意,我明确指定了代码,而不是使用序数值-这使得以后更容易更改顺序和添加/删除错误

别忘了这根本不是国际化的——但除非您的web服务客户端向您发送区域设置描述,否则您自己也无法轻松地将其国际化。至少他们会在客户端使用i18n的错误代码…

重载toString()似乎有点棘手--这似乎是toString()正常使用的一个延伸

那么:

public enum Errors {
  DATABASE(1, "A database error has occured."),
  DUPLICATE_USER(5007, "This user already exists.");
  //... add more cases here ...

  private final int id;
  private final String message;

  Errors(int id, String message) {
     this.id = id;
     this.message = message;
  }

  public int getId() { return id; }
  public String getMessage() { return message; }
}

对我来说似乎干净多了。。。就我而言,我更喜欢将错误消息外部化到属性文件中。 在应用程序国际化的情况下(每种语言一个属性文件),这将非常有用。修改错误消息也更容易,而且不需要重新编译Java源代码

在我的项目中,通常我有一个包含错误代码(字符串或整数,不太重要)的接口,该接口在属性文件中包含此错误的键:

public interface ErrorCodes {
    String DATABASE_ERROR = "DATABASE_ERROR";
    String DUPLICATE_USER = "DUPLICATE_USER";
    ...
}
在属性文件中:

DATABASE_ERROR=An error occurred in the database.
DUPLICATE_USER=The user already exists.
...
解决方案的另一个问题是可维护性:您只有2个错误,并且已经有12行代码。 因此,想象一下您的枚举文件将有数百个错误需要管理

我(和我公司的其他团队成员)更喜欢提出异常,而不是返回错误代码。错误代码必须到处检查、传递,当代码量变大时,往往会使代码无法读取

然后,error类将定义消息

PS:而且实际上也关心国际化!

PPS:如果需要,您还可以重新定义raise方法并添加日志记录、筛选等(至少在例外类和好友可扩展/更改的环境中)

我建议您查看java.util.ResourceBundle。你应该关心I18N,但即使你不关心,它也是值得的。将消息外部化是一个非常好的主意。我发现,能够给商业人士提供一个电子表格,让他们能够准确地输入他们想要看到的语言是很有用的。我们编写了一个Ant任务来在编译时生成.properties文件。它使I18N变得微不足道


如果您也使用Spring,那就更好了。他们的MessageSource类对于这类事情很有用。

在我的上一份工作中,我对enum版本进行了更深入的研究:

public enum Messages {
    @Error
    @Text("You can''t put a {0} in a {1}")
    XYZ00001_CONTAINMENT_NOT_ALLOWED,
    ...
}
@错误、@Info、@Warning保留在类文件中,并在运行时可用。(我们还有一些其他注释来帮助描述消息传递)

@文本是编译时注释

我为此编写了一个注释处理器,它执行以下操作:

// Example: errorCode = 1, 
//          errorString = "There was a problem accessing the database."
throw new SomeWebServiceException(errorCode, errorString);
  • 确认没有重复的消息编号(第一条下划线之前的部分)
  • 语法检查消息文本
  • 生成包含文本的messages.properties文件,该文本由枚举值键入
我编写了一些实用程序例程,帮助记录错误,将它们包装为异常(如果需要)等等

我想让他们让我把它开源。。。
--斯科特

有点晚了,但我只是在为自己寻找一个不错的解决方案。如果您有不同类型的消息错误,您可以添加简单的自定义消息工厂,以便您可以指定以后需要的更多详细信息和格式

public enum Error {
    DATABASE(0, "A database error has occured. "), 
    DUPLICATE_USER(1, "User already exists. ");
    ....
    private String description = "";
    public Error changeDescription(String description) {
        this.description = description;
        return this;
    }
    ....
}

Error genericError = Error.DATABASE;
Error specific = Error.DUPLICATE_USER.changeDescription("(Call Admin)");
编辑: 好的,在这里使用enum有点危险,因为您会永久地更改特定的enum。
我想最好改为类并使用静态字段,但不能再使用“==”。因此,我想这是一个很好的例子,说明了不应该做什么(或者只在初始化时做):

错误代码/消息定义枚举仍然是一个很好的解决方案,尽管它有i18n方面的问题。实际上,我们可能有两种情况:代码/消息显示给最终用户或系统集成商。对于后一种情况,不需要I18N。我认为web服务最有可能是后一种情况。

只是为了不断鞭笞这匹死马-当向最终客户显示错误时,我们很好地使用了数字错误代码,因为他们经常忘记或误读实际的错误消息,但有时可能会保留并报告一个数字值,这可以为您提供实际发生的情况的线索。

使用
接口作为消息常量通常是个坏主意。它将作为导出API的一部分永久泄漏到客户端程序中。谁知道呢,后来的客户端程序员可能会将错误消息(public)解析为程序的一部分

public enum ErrorCodes {
NO_File("No file found. "),
private ErrorCodes(String value) { 
    this.errordesc = value; 
    }
private String errordesc = ""; 
public String errordesc() {
    return errordesc;
}
public void setValue(String errordesc) {
    this.errordesc = errordesc;
}
fileResponse.setErrorCode(ErrorCodes.NO_FILE.errordesc());
public interface ICode {
     /*your preferred code type here, can be int or string or whatever*/ id();
}

public interface IMessage {
    ICode code();
}
public enum DatabaseMessage implements IMessage {
     CONNECTION_FAILURE(DatabaseCode.CONNECTION_FAILURE, ...);
}