为了账号安全,请及时绑定邮箱和手机立即绑定

从泛型返回异常

从泛型返回异常

Helenr 2021-08-04 16:16:08
我目前有多个类,即FacadeA... FacadeZ,其扩展FacadeBase. FacadeBase应该有(某种通用方法?),即checkFacade,它会抛出一个异常FacadeAException......FacadeZException它扩展了FacadeException.目前就我所知。我坚持使用通用部分(或任何可以解决我的问题的方法)。是的,我知道我不能像我的例子中写的那样实例化泛型。public abstract class FacadeBase {  public void checkFacade(final String facadeId) throws Facade<A...Z>Exception {    if (!isFacadeAvailable(facadeId)) {      throw new Facade<A...Z>Exception(facadeId);    }  }  ...}public class FacadeA extends FacadeBase {  public void doSomethingWithFacadeA(final String facadeId) throws FacadeAException {    checkFacade(facadeId));    ...  }}public class FacadeAException extends FacadeException {  private FacadeAException(final String message) {    super(message);  }}public abstract class FacadeException extends Exception {  private FacadeException(final String message) {    super(message);  }}
查看完整描述

3 回答

?
翻阅古今

TA贡献1780条经验 获得超5个赞

您可以使用泛型,但这还不够,因为您需要在运行时实例化特定类型。

从广义上讲,您有两种方法:


反思方式

声明方式

1)反射方式不简单。Java 并没有提供所有你需要做的事情。您可以启发或使用库作为 Spring 来做到这一点。

该org.springframework.core.GenericTypeResolver应特别是帮助你。

您可以使用以下static Class<?> resolveTypeArgument(Class<?> clazz, Class<?> genericIfc) 方法:


针对给定的目标类解析给定泛型接口的单个类型参数,该类假定实现泛型接口并可能为其类型变量声明具体类型。


如 :


public abstract class FacadeBase<T extends FacadeException> {


    private final Class<T> genericClazz;

    public FacadeBase () {

        this.genericClazz = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), FacadeBase.class);    

    }

}

现在,您可以使用genericClazz.newInstance()或 better来实例化泛型的类Constructor.newInstance()。


2)声明式方式更简单,但需要一些样板代码。


使您的抽象类成为指定异常类型并提供存储要抛出的异常的构造函数的泛型类。

例如 :


public abstract class FacadeBase<T extends FacadeException> {


    private Supplier<T> suppException;


    public FacadeBase(Supplier<T> suppException) {

        this.suppException = suppException;

    }


    public void checkFacadeAvailability(final String facadeId) throws T {

        if (!isFacadeAvailable(facadeId)) {

            throw suppException.get();

        }

    }

}

子类应该使用它们的供应商调用超级构造函数:


public class FacadeA extends FacadeBase<FacadeExceptionA>{


    public FacadeA(Supplier<FacadeExceptionA> suppException) {

        super(suppException);

    }   

}

作为替代方案,你可以更换Supplier一个Class参数,但总的想法是一样的。


查看完整回答
反对 回复 2021-08-04
?
慕神8447489

TA贡献1780条经验 获得超1个赞

停在 有两个很好的理由throws FacadeException

  • FacadeBase.checkFacade无论如何,合同都会迫使客户捕捉FacadeException(假设编程接口的良好做法)

  • 异常类不能是通用的。尽管您可以Exceptionthrows子句中使用类型参数,但这只是过度设计(除了违背最佳实践)

所以子类应该throws  Facade<A...Z>Exception在适用的地方完全声明或省略这个子句。但这对客户端/调用者没有影响(除非他们采取不鼓励的声明子类类型的方式)

如果您需要检查调用方引发了哪个异常,那么无论如何您都必须知道具体的异常类,因为instanceof  T无论如何您都无法检查。


查看完整回答
反对 回复 2021-08-04
?
达令说

TA贡献1821条经验 获得超6个赞

据我了解,问题的核心是如何按照checkFacade()以下伪代码示意性表示的方式声明和实现一个方法:


public abstract class FacadeBase {

  public void checkFacade(final String facadeId) throws Facade<A...Z>Exception {

    if (!isFacadeAvailable(facadeId)) {

      throw new Facade<A...Z>Exception(facadeId);

    }

  }

  ...

}

我首先注意到,将特征异常与具体FacadeBase子类相关联会破坏抽象。子类当然可能会抛出它们自己的特定异常,但是一旦其他类知道或特别关心那些异常,特别是为了能够识别这些子类,抽象就会崩溃。


特别是,如果您的isFacadeAvailable(facadeId)方法与FacadeBase在 Java 类路径中可用的子类有关,那么这似乎与该外观实现的特征异常可用有关。在这种情况下,您不能期望能够实例化FacadeQExceptionwhenFacadeQ不可用,并且当类路径中不存在任何异常时,您可能会遇到类加载失败。


其次,我观察到因为所有的Facade[A-Z]Exceptions 都扩展了FacadeException,FacadeBase.checkFacade()所以可以简单地声明FacadeException而不是声明所有单独的异常。这不会阻止其他代码捕获特定异常,如果这些异常确实仍然被此方法抛出。


为了实际抛出个别例外,您需要先建立他们,并呼吁无论是大的switch块,大if/ then/else语句,一个工厂方法,或适当的异常类的反射实例,或这些的某种组合. 请注意,异常是对象;它们可以分配给变量并从方法中返回。一个throw语句可以抛出任何 Throwable;它不需要是新实例化的。因此,您可以考虑以下方面的内容:


public void checkFacade(final String facadeId) throws FacadeException {

    if (!isFacadeAvailable(facadeId)) {

        throw createFacadeException(facadeId);

    }

}


private FacadeException createFacadeException(String facadeId) {

    if ("A".equals(facadeId)) {

        return new FacadeAException();

    } else // ...

}

但是,我敦促您考虑提供FacadeException一个成员来传达不可用外观的ID,而不是通过抛出特定于外观的异常来实现。或者如果你不想把它放在FacadeException自己身上,那么定义一个FacadeUnavailableException携带它的子类:


public class FacadeUnavailableException extends FacadeException {

    private final String facadeId;


    private FacadeAException(String message, String facadeId) {

        super(message);

        this.facadeId = facadeId;

    }


    public String getFacadeId() {

        return facadeId;

    }

}

有了这个,你的问题就变得简单多了:


public void checkFacade(final String facadeId) throws FacadeUnavailableException {

    if (!isFacadeAvailable(facadeId)) {

        throw new FacadeUnavailableException("unavailable", facadeId);

    }

}


查看完整回答
反对 回复 2021-08-04
  • 3 回答
  • 0 关注
  • 207 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信