Java 具有实例的类枚举结构?

Java 具有实例的类枚举结构?,java,enums,Java,Enums,我使用以下枚举类型: enum Status {OK,TIMEOUT,EXCEPTION} 但现在我想存储异常的确切内容。很遗憾,您无法实例化枚举类型。什么是最好的方式使类似以下的事情成为可能 switch(status) { case(OK) {System.out.println("Everything OK!");break;} case(TIMEOUT) {System.out.println("Timeout :-(");break;} case(EXCEPT

我使用以下枚举类型:

enum Status {OK,TIMEOUT,EXCEPTION}
但现在我想存储异常的确切内容。很遗憾,您无法实例化枚举类型。什么是最好的方式使类似以下的事情成为可能

switch(status)
{
 case(OK)        {System.out.println("Everything OK!");break;}
 case(TIMEOUT)   {System.out.println("Timeout :-(");break;}
 case(EXCEPTION) {System.out.println("We have an exception: "+status.exception);break;}
}
我的想法

  • 单身人士班级

    class Status
    {
     final Exception e;
     public final Status OK = new Status(null);
     public final Status TIMEOUT = new Status(null);
     public Status(Exception e) {this.e=e;}
    }
    
  • 然后我可以做:

     if(status==Status.OK) {System.out.println("Everything OK!");}
     else if(status==Status.TIMEOUT) {System.out.println("Timeout :-(");}
     else {System.out.println("We have an exception: "+status.exception);}
    
    二,。几类

    class Status {}
    class StatusOK extends Status {}
    class StatusTimeout extends Status {}
    class StatusException extends Status
    {
     final Exception e;    
     public StatusException(Exception e) {this.e=e;}    
    }
    
    然后我需要一堆“instanceOf”语句

    p.S.:好吧,看来我解释得不够清楚。在我的程序中,我回答请求并存储这些请求的处理状态:

    Map<Request,Status> request2Status;
    

    除非一切正常,否则我会使用异常

    当异常被设计用来做这类事情时,我认为没有必要使用
    enum


    在您和原始异常之间的层的顶部添加另一层,您可以执行此操作

    interface Status {
       String getMessage();
    }
    
    enum Statuses implements Status {
       OK("Everything OK"), TIMEOUT("Timeout :-(");
    
       private final String message;
       private Statuses(String message) { this.message = message; }
    
       String getMessage() { return message; }
    }
    
    class ExceptionStatus implement Status {
       private final String message;
       String getMessage() { return "Exception: " + message; }
    }
    
    // to print the message
    System.out.println(status.getMessage());
    

    除非一切正常,否则我会使用异常

    当异常被设计用来做这类事情时,我认为没有必要使用
    enum


    在您和原始异常之间的层的顶部添加另一层,您可以执行此操作

    interface Status {
       String getMessage();
    }
    
    enum Statuses implements Status {
       OK("Everything OK"), TIMEOUT("Timeout :-(");
    
       private final String message;
       private Statuses(String message) { this.message = message; }
    
       String getMessage() { return message; }
    }
    
    class ExceptionStatus implement Status {
       private final String message;
       String getMessage() { return "Exception: " + message; }
    }
    
    // to print the message
    System.out.println(status.getMessage());
    

    有几种方法可以实现这一点,但所有这些方法都取决于您不使用枚举或不专门使用枚举。请记住,枚举基本上是一个只有定义良好的单例作为值的类

    一种可能的重构方法是使用具有定义良好的单例的普通类,而不是枚举:

    class Status implements Serializable {
      // for serialization
      private enum InternalStatus {
        OK, TIMEOUT, EXCEPTION
      }
      public static final Status OK = new Status(null, InternalStatus.OK);
      public static final Status TIMEOUT = new Status(null, InternalStatus.TIMEOUT);
    
      private final Exception exception;
      private final InternalStatus internalStatus;
    
      private Status(Exception exception, InternalStatus internalStatus) {
        this.exception = exception;
        this.internalStatus = internalStatus;
      }
    
      public Exception getException() {
        return exception;
      }
    
      public static Status exceptionStatus(Exception cause) {
        if (cause == null) throw new NullPointerException();
        return new Status(cause, InternalStatus.EXCEPTION);
      }
    
      // deserialization logic handling OK and TIMEOUT being singletons
      private final Object readResolve() {
        switch (internalStatus) {
        case InternalStatus.OK:
          return OK;
        case InternalStatus.TIMEOUT:
          return TIMEOUT;
        default:
          return this;
        }
      }      
    }
    
    您现在可以检查
    status==status.OK
    status==status.TIMEOUT
    。如果您的状态变量既不是OK也不是TIMEOUT,那么它一定是由异常引起的,您可以通过
    getException
    检索异常


    另一个缺点是,您失去了
    开关
    功能,必须通过
    if
    进行检查。有几种方法可以做到这一点,但所有这些方法都取决于您不使用枚举或不专门使用枚举。请记住,枚举基本上是一个只有定义良好的单例作为值的类

    一种可能的重构方法是使用具有定义良好的单例的普通类,而不是枚举:

    class Status implements Serializable {
      // for serialization
      private enum InternalStatus {
        OK, TIMEOUT, EXCEPTION
      }
      public static final Status OK = new Status(null, InternalStatus.OK);
      public static final Status TIMEOUT = new Status(null, InternalStatus.TIMEOUT);
    
      private final Exception exception;
      private final InternalStatus internalStatus;
    
      private Status(Exception exception, InternalStatus internalStatus) {
        this.exception = exception;
        this.internalStatus = internalStatus;
      }
    
      public Exception getException() {
        return exception;
      }
    
      public static Status exceptionStatus(Exception cause) {
        if (cause == null) throw new NullPointerException();
        return new Status(cause, InternalStatus.EXCEPTION);
      }
    
      // deserialization logic handling OK and TIMEOUT being singletons
      private final Object readResolve() {
        switch (internalStatus) {
        case InternalStatus.OK:
          return OK;
        case InternalStatus.TIMEOUT:
          return TIMEOUT;
        default:
          return this;
        }
      }      
    }
    
    您现在可以检查
    status==status.OK
    status==status.TIMEOUT
    。如果您的状态变量既不是OK也不是TIMEOUT,那么它一定是由异常引起的,您可以通过
    getException
    检索异常



    缺点是,您失去了
    开关
    功能,必须通过
    进行检查,如果

    您应该使
    正常
    超时
    最终
    。谢谢!如果没有解决方案可以使用交换机功能,那么这就解决了我的问题!我唯一不喜欢的是最后一个领域的获得者(在我眼里可能只是公开的),但我想这是个人品味的问题。无论如何,转换是邪恶的。如果只需要打印消息,可以在构造对象时将消息分配给字段。新问题:反序列化后,静态字段不再保持相等。因此,我的
    if(status==status.OK)
    在序列化对象并在以后反序列化后不起作用。@kirdie如果需要序列化,则需要自定义序列化逻辑。最简单的方法是使用
    writeReplace
    readResolve
    为OK和TIMEOUT写入特殊对象,并在读取后替换它们。您应该使您的
    OK
    TIMEOUT
    成为最终版本。谢谢!如果没有解决方案可以使用交换机功能,那么这就解决了我的问题!我唯一不喜欢的是最后一个领域的获得者(在我眼里可能只是公开的),但我想这是个人品味的问题。无论如何,转换是邪恶的。如果只需要打印消息,可以在构造对象时将消息分配给字段。新问题:反序列化后,静态字段不再保持相等。因此,我的
    if(status==status.OK)
    在序列化对象并在以后反序列化后不起作用。@kirdie如果需要序列化,则需要自定义序列化逻辑。最简单的方法是使用
    writeReplace
    readResolve
    为OK和TIMEOUT编写特殊对象,并在阅读后替换。很抱歉,我似乎没有足够清楚地解释我的问题,我在问题描述中补充说,在当时我不再有例外。在这种情况下,我会说你有一层翻译,这是一个问题,而不是它的帮助。我会删除它,这样您就只需要原始异常,而不是添加一个层来反转您和原始异常之间的层添加的行为;saveToDisk(request2Status)…几天后
    Map request2Status=loadFromDisk();向用户显示请求状态(请求状态2)抱歉,似乎我没有足够清楚地解释我的问题,我在问题描述中补充说,我在当时不再有例外。在这种情况下,我会说你有一层翻译,这是一个问题,而不是它的帮助。我会删除它,这样您就只需要原始异常,而不是添加一个层来反转您和原始异常之间的层添加的行为;saveToDisk(request2Status)…几天后
    Map request2Status=loadFromDisk();向用户显示请求状态(请求状态2)我不太确定你是否应该在同一个问题中发布新的评论。如果问题是一个移动的目标,那么很难理解所有的答案。问题仍然和以前一样,只是先前提出的解决方案有一个问题。但是你的副标题是New solution,并且
    
    class Status implements Serializable {
      // for serialization
      private enum InternalStatus {
        OK, TIMEOUT, EXCEPTION
      }
      public static final Status OK = new Status(null, InternalStatus.OK);
      public static final Status TIMEOUT = new Status(null, InternalStatus.TIMEOUT);
    
      private final Exception exception;
      private final InternalStatus internalStatus;
    
      private Status(Exception exception, InternalStatus internalStatus) {
        this.exception = exception;
        this.internalStatus = internalStatus;
      }
    
      public Exception getException() {
        return exception;
      }
    
      public static Status exceptionStatus(Exception cause) {
        if (cause == null) throw new NullPointerException();
        return new Status(cause, InternalStatus.EXCEPTION);
      }
    
      // deserialization logic handling OK and TIMEOUT being singletons
      private final Object readResolve() {
        switch (internalStatus) {
        case InternalStatus.OK:
          return OK;
        case InternalStatus.TIMEOUT:
          return TIMEOUT;
        default:
          return this;
        }
      }      
    }