我想建模一些错误代码。 经典的枚举方法

public enum FileError implement FormattedError {
_10 ("some error with parameters [{0}] and [{1}]"),
_20 ("some other error");
private final String description;
private Error(String description) {
this.description = description;
}
public String getDescription(Object... parameters) {
return // logic to format message
}
...
}

这对我不好,因为我有很多模块,每个模块都有错误代码,而且我不想在所有这些枚举中复制并粘贴样板(构造函数,获取方法,逻辑..)。

所以我去了一个像这样实现的"手动"枚举

public class FileError extends BaseError {
public final static FileError _10  = new FileError (10,"some message with parameters [{0}] and [{1}]");
public final static FileError _20  = new FileError (20,"some other message");
}

我可以在BaseError中定义我的逻辑并重用它。

但它仍然很糟糕,因为无法将变量名链接到数字(_10到10),并且人们复制粘贴可能会重复使用相同的数字而不会引起注意。 我可以添加一个测试以通过反射进行检查,但是然后我如何强制人们将测试用于其实现。

那么,你们对我如何实现这一目标有更好的了解吗?

[edit]请记住,我不想将错误代码放在属性文件中,因为我希望ide将代码中的错误代码与它们的消息链接起来。

集成测试应验证没有重用数字,最好是这些测试应在单元测试后直接运行,以便测试可以使用BaseError.class.getSubClasses()快速获取所有子类型。

Java中定义错误代码/字符串的最佳方法的可能重复项?

要回答有关如何检查重用号码的问题,您可以简单地使用到目前为止已注册的所有号码的静态集合来进行此操作,并检查是否在注册新号码时不存在该号码:

public class BaseError {
// ...
private static Set registeredNums = new HashSet<>();
public BaseError(int N, String msg) {
synchronized(registeredNums) {
assert(!registeredNums.contains(N)) :"Duplicated error code";
registeredNums.add(N);
}
// ...
}
}

用户将需要启用断言。如果您希望检查始终进行,则可以手动抛出AssertionError。

这很有用,谢谢

希望您对此有所了解:

public enum FileError {
SOME_ERROR1("0","Error something1"),
SOME_ERROR2("1","Error something2"),
SOME_ERROR3("2","Error something3"),
private final String code;
private final String message;
FileError(String code, String message) {
this.code = code;
this.message = message;
}
public String get() {
return new CustomException(code, message).toString();
}
}

而您是CustomException类

public class CustomException {
...
@Override
public String toString() {
return String.format(Locale.getDefault(),"%s, %s", code, message);
}
}

有必要使用一些样板代码,但是您可以通过使enum实现一个interface并将其大部分功能静态地放置在interface中,将其保持在最低限度—当然,如果您使用的是Java-7 + 。

interface Error {
/**
* Keeps track of error ranges - for sanity check when errors are registered.
*/
static final Map> errors = new HashMap<>();
/**
* Lookup range.
*/
static final Map range = new HashMap<>();
public static & Error> void register(ErrorRange errorRange, Class theClass) {
// Keep track of all errors - TODO - Make sure each is registered only once.
errors.put(errorRange, EnumSet.allOf(theClass));
// We need the range.
for (Error e : theClass.getEnumConstants()) {
range.put(e, errorRange);
}
}
/**
* Get a formatted string for the error with the provided parameters.
*/
static & Error> String format(E error, Object... parameters) {
// The error number comes from it's range + its ordinal.
int errNo = range.get(error).range + error.ordinal();
// The string comes from the formatted description.
return errNo +"\t" + String.format(error.getDescription(), parameters);
}
// All Errors must have a description.
public String getDescription();
}
/**
* Register of all error ranges.
*/
enum ErrorRange {
// All File errors start at 10,000
FileError(10_000);
final int range;
private ErrorRange(int range) {
this.range = range;
}
}
public enum FileError implements Error {
ParameterError("some error with parameters [{0}] and [{1}]"),
OtherError("some other error");
//
// Start boilerplate
private final String description;
private FileError(String description) {
this.description = description;
}
@Override
public String getDescription() {
return description;
}
// End boilerplate
//
}
static {
// Statically register me with the Error object.
Error.register(ErrorRange.FileError, FileError.class);
}
您正在寻找的是两种方法的结合:
enum ErrorCode {
_10(new FileError(10,"some message with parameters [{0}] and [{1}]")),
_20(new FileError(20,"some other message"));
private final FileError error;
private ErrorCode(FileError err) {
error = err;
}
public FileError getError() {
return error;
}
}

使用此代码,在错误代码和变量之间有明确的链接。为了避免其他人使用相同的错误代码,可以通过将构造函数包设为私有来阻止他们完全创建自己的FileError实例。如果这不是一个选择,则可以按如下方式创建其他子类:

public class UserDefinedFileError extends FileError {
public UserDefinedFileError(int code, String msg){
super(checkCode(code),msg);
}
static int checkCode(int code){
if(code <= 100){ // or check if it exists in a set of used codes
throw new IllegalArgumentException("Error codes lower than 100 are reserved.");
}
}
}