Java 如何在不使用异常的情况下从方法返回失败详细信息,并可选地包含一个值?

Java 如何在不使用异常的情况下从方法返回失败详细信息,并可选地包含一个值?,java,generics,exception,inheritance,exception-handling,Java,Generics,Exception,Inheritance,Exception Handling,首先是一些背景: 我已经实现了一个Result类来携带结果信息。它们是针对失败而实施的,成功结果通常不包含其他信息。在我的一个项目中,我在核心API外部的公共方法中使用它们,或者在需要将详细信息备份到公共API的一层或两层方法中使用它们。该API在容器和命令行客户机中使用,之前进行过非常严格的检查。另一种方法是将此故障上下文信息添加到异常中,并添加几个不同的异常类,这些异常类不属于这些异常。我想这反映了我的一般做法: 结果具有支持的枚举和接口: 结果状态:SUCCESS、FAILURE、CON

首先是一些背景:

我已经实现了一个Result类来携带结果信息。它们是针对失败而实施的,成功结果通常不包含其他信息。在我的一个项目中,我在核心API外部的公共方法中使用它们,或者在需要将详细信息备份到公共API的一层或两层方法中使用它们。该API在容器和命令行客户机中使用,之前进行过非常严格的检查。另一种方法是将此故障上下文信息添加到异常中,并添加几个不同的异常类,这些异常类不属于这些异常。我想这反映了我的一般做法:

结果具有支持的枚举和接口:

  • 结果状态:SUCCESS、FAILURE、CONDITIONAL_SUCCESS等包含int返回码和一般消息(例如“操作成功”)
  • ResultCode:标记枚举结果代码的接口为空,未找到文件,文件无效,文件不兼容。这些主要用于单元和功能测试,但也用于在线帮助(Maven关于故障的帮助在功能上与我正在做的类似)
  • Result为status提供静态工厂方法,为其他键字段提供builder方法,并且是不可变的。以下是生成结果的过程:

    Result.success().withCode( ResultCode ).withMessage( "" );
    
    以及评估返回的结果:

    result.isSuccessful();
    result.hasCode( ResultCode );
    result.getMessage();
    
    我的问题是:

    这种方法非常成功,特别是使功能测试变得轻而易举,但是我有一个主要的差距:在大多数情况下,我只关心结果,而在一些关键领域,我需要返回结果值

    我对第一次尝试不满意:
    ResultPair
    ,它包含结果和值,其中T是值的类型。除非我复制了所有的Result方法,否则使用该类是冗长而笨拙的:获取一个结果,将其添加到ResultPair中,然后在计算之前提取结果和值。乍一看,由于构建器模式的原因,继承将不起作用,我无法想出一种方法来获得结果允许的清晰、干净的代码,而不完全复制结果类

    理想情况下,这种方法允许结果有选择地返回值,但我想不出一种方法可以以类型安全的方式来确保方法签名清楚地指示值的类型,但避免在我不返回值的地方使用无意义的泛型参数

    我真的不介意有两个类,而且复制结果生成器和评估代码并不是世界末日,这感觉是错误的,我觉得缺乏经验会让我感觉更好,我错过了一个(明显的或不那么明显的)解决方案。我使用的是Guava,我想以一种友好的方式禁止空值,因此可能会另外将所有值包装在一个可选值中,但我仍然需要泛型参数(并将其组合到类中以避免出现result.value().get()…好的,我现在正在大声思考。我应该问一个问题…)


    有没有办法满足这些明显相互排斥的要求?

    您可以创建
    ResultPair
    作为void result类的基类:

    public class Result extends ResultPair<Void> { ... }
    
    公共类结果扩展ResultPair{…}
    
    所有相关方法都将在
    ResultPair
    中声明

    更新


    更好的是,只要有一个类型
    Result
    ,只要不想返回值,就使用
    Result
    。或者更确切地说,如果使用
    Void
    作为类型参数在您看来很奇怪,请创建一个新的不可实例化(或单例)类型,意思是“没有结果”,然后改用它:
    result
    ,例如。

    我根本没有想到过,我完全忘记了Void。我不能降低继承方法的可见性,因此这意味着签名中与值相关的方法,但我想我会覆盖这些方法并抛出IllegalStateExceptions。不幸的是,这样做不行。尝试使用返回ResultPair的静态或生成器方法将导致类型与Result不匹配-我必须复制静态方法,并显式转换为生成器方法的Result。是的,这太糟糕了。。。我认为您必须复制这些方法,但请尽量将它们委托给一个通用实现,换句话说,重构它们以减少代码重复。无论如何,感谢您的建议!那么,只要使用一个类
    Result
    ,并在不需要返回值时显式使用
    Result
    。+1一位同事为我们的代码做了一些非常类似的事情,这非常有帮助。