1

我使用以下枚举类型:

enum Status {OK,TIMEOUT,EXCEPTION}

但现在我想存储 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;}
}

我的想法

  1. 单例类

    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);}

2.几个类

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”语句。

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

Map<Request,Status> request2Status;

因此我不能使用像 Status.getMessage(exception); 这样的东西。因为在我的代码中的那个位置,我不知道它是哪个异常。这就是为什么我想将它保存状态中。

选择的解决方案

private static class LearnStatus implements Serializable
    {               
        private static final long   serialVersionUID    = 1L;
        public static final LearnStatus OK = new LearnStatus(null);
        public static final LearnStatus TIMEOUT = new LearnStatus(null);
        public static final LearnStatus NO_TEMPLATE_FOUND = new LearnStatus(null);
        public static final LearnStatus QUERY_RESULT_EMPTY = new LearnStatus(null);
        public static final LearnStatus NO_QUERY_LEARNED = new LearnStatus(null);

        public final Exception exception;

        private LearnStatus(Exception exception) {this.exception = exception; }

        public static LearnStatus exceptionStatus(Exception cause)
        {
            if (cause == null) throw new NullPointerException();
            return new LearnStatus(cause);
        }

        @Override public String toString()
        {
            if(this==OK) {return "OK";}
            if(this==TIMEOUT) {return "timeout";}
            if(this==NO_TEMPLATE_FOUND) {return "no template found";}
            if(this==QUERY_RESULT_EMPTY) {return "query result empty";}
            if(this==NO_QUERY_LEARNED) {return "no query learned";}
            return "<summary>Exception: <details>"+exception.getLocalizedMessage()+"</details></summary>"; 
        }
    }

这方面的问题

如果我在其中序列化一个对象,Status.OK则反序列化后将if(status==Status.OK)不再起作用。

新解决方案

我现在在类中包含了一个枚举类型。你怎么看待这件事?

private static class LearnStatus implements Serializable
    {
        public enum Type {OK, TIMEOUT, NO_TEMPLATE_FOUND,QUERY_RESULT_EMPTY,NO_QUERY_LEARNED,EXCEPTION}

        public final Type type;

        private static final long   serialVersionUID    = 1L;
        public static final LearnStatus OK = new LearnStatus(Type.OK,null);
        public static final LearnStatus TIMEOUT = new LearnStatus(Type.TIMEOUT,null);
        public static final LearnStatus NO_TEMPLATE_FOUND = new LearnStatus(Type.NO_TEMPLATE_FOUND,null);
        public static final LearnStatus QUERY_RESULT_EMPTY = new LearnStatus(Type.QUERY_RESULT_EMPTY,null);
        public static final LearnStatus NO_QUERY_LEARNED = new LearnStatus(Type.NO_QUERY_LEARNED,null);

        public final Exception exception;

        private LearnStatus(Type type, Exception exception) {this.type=type;this.exception = exception;}

        public static LearnStatus exceptionStatus(Exception cause)
        {
            if (cause == null) throw new NullPointerException();
            return new LearnStatus(Type.EXCEPTION,cause);
        }

        @Override public String toString()
        {
            switch(type)
            {
                case OK:                return "OK";
                case TIMEOUT:           return "timeout";
                case NO_TEMPLATE_FOUND: return "no template found";
                case QUERY_RESULT_EMPTY:return "query result empty";
                case NO_QUERY_LEARNED:  return "no query learned";
                case EXCEPTION:         return "<summary>Exception: <details>"+exception.getLocalizedMessage()+"</details></summary>";
                default: throw new RuntimeException("switch type not handled");
            }           
        }
    }
4

2 回答 2

3

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

   System.out.println("Everything OK!");
} catch(TimeoutException te) {
   System.out.println("Timeout :-(")
} catch(Exception e) {
   System.out.println("We have an exception: " + e);
}

我认为没有必要使用enumwhen Exceptions 被设计为做这种事情。


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

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());
于 2012-08-10T10:13:35.510 回答
1

有几种方法可以解决这个问题,但所有这些方法都取决于您不使用 Enums 或者您不专门使用它们。请记住,枚举基本上是一个只有定义明确的单例作为值的类。

对此的一种可能的重构是使用具有明确定义的单例而不是枚举的普通类:

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.OKstatus == Status.TIMEOUT。如果您的状态变量既不是 OK 也不是 TIMEOUT,它一定是由异常引起的,您可以通过getException.

不利的一面是,您失去了switch功能,必须通过if.

于 2012-08-10T10:17:33.910 回答