当前位置: 首页 > 知识库问答 >
问题:

如果一个操作将使对象进入非法状态,该抛出什么异常?

岳昊空
2023-03-14

考虑<代码>产品<代码> > <代码>数量>代码>,可以通过给定的<代码>金额< /代码>来增加和减少。数量不得变为负值,如果将要发生,必须禁止操作,并警告用户。

public class Product{
    
    private int quantity;
    
    public Product() {
        quantity = 10;
    }
    
    public void decreaseQuantity(int amount) {
        int decreasedQuantity = quantity - amount;
        if(decreasedQuantity < 0 )
            throw new RuntimeException(String.format("Decrease quantity (%s) exceeds avaiable quantity (%s)",
                    amount, quantity));
        
        quantity = decreasedQuantity;
    }
}

例如,如果一个产品的数量为10,而我试图删除20,则抛出RuntimeException。SonarCloud建议用自定义异常替换RuntimeException,但我想知道是否有适合这种情况的标准异常(有效Java:支持使用标准异常)。

最合适的异常似乎是非法状态异常。来自javadoc

表示方法已在非法或不适当的时间被调用。换句话说,Java环境或Java应用程序不处于用于所请求操作的适当状态。

和有效Java

如果调用方法时,对象的状态对该操作无效,则使用此异常。您可能有一个文件句柄,并且在打开它之前调用read。

然而,在我看来,我的例子和文档中假设的有一个微妙的区别:使操作非法的不是对象本身的状态,而是对象的状态和输入参数的值。阅读使用示例(如IllegalStateExcture的预期用途是什么?)无论输入参数如何,对象始终处于拒绝操作的状态。

共有3个答案

徐卓
2023-03-14

java。lang.IllegalArgumentException在这种情况下是合适的-它是一个明智的选择,并被广泛用于应用软件和框架中,以达到您所建议的目的。

在第三方库中也有一些很好的选项来支持这些前置条件和状态断言。例如,如果您使用Spring,您可以选择对前置条件和状态断言方法使用org.springframework.util.Asrett类。

这导致简洁的代码:

public int findIndex(List<E> collection, E matchItem) {

    Assert.notNull(collection,"Mandatory collection parameter is null.");
    Assert.notNull(matchItem,"Mandatory matchItem parameter is null.");

    return collection.indexOf(matchItem);
}

对于使用java.lang.IllegalStateExcture,可以传递一个合法的参数值,该参数值导致可以用此异常表示的非法状态。例如,当数量为2时,将数量减少3 IMO最好用java.lang.IllegalStateExc0019来表示,而不是java.lang.IllegalArgumentExc0019

於乐语
2023-03-14

核心java库中没有什么是灌篮。然而,让你自己的例外可能是你最好的选择,这是一个势均力敌的比赛之间的使用IllegalArgumentExc0019

由于模糊的原因,我被告知。不使用它的主要原因是因为短绒工具会对你大喊大叫。他们对你大喊大叫的原因有两个,要确定正确的做法是让他们闭嘴,还是引导他们的建议,就要关注这两个原因:

>

  • 异常的类型名称本身就是信息。例如,抛出新的NullPointerExcture("x is null")是要写的哑代码(尽管它很常见)。这是多余的-只是new NullPointerExc0019("x")是合适的。RuntimeExc0019几乎不传递任何信息。你大部分时间都在避免这个陷阱:虽然运行异常实际上几乎没有传达任何信息,但异常的消息说明了一切,因此,linter试图阻止的事情(抛出一个不能正确传达问题性质的异常)没有发生,因此你应该考虑告诉短绒停止抱怨...除了:

    您需要合适的异常类型的第二个原因是,您真的,真的不希望打算捕获此类型的代码必须对异常消息进行字符串分析。因此,如果您可以预见某些代码想要调用您的方法,然后以任何方式对条件(试图减去比可用的更多)做出反应,而不是破坏所有上下文,那么您应该抛出一个异常意味着这个特定的条件,而不是别的。如果你的意图是捕捉一个特定的条件,那么RuntimeExc0019永远不适合捕捉(它几乎永远不合适,句号——有时你想运行代码并对任何问题做出反应,不管它的性质如何,但是然后cat(异常e)是适当的捕捉块,或者甚至Throwable

    Linter不会大喊大叫,但您仍然没有真正获得第二个好处(也就是说,允许调用者捕捉这个特定问题,而不是参数的其他问题)。这在“心理上”也有点可疑:你最初忽视它的理由并没有错。通常,IAE被理解为暗示非法参数是非法的,而不管该对象的状态如何。但这并不是用IAE的javadoc编写的,也不是普遍适用的。

    因此,不利因素是:

    • 强迫调用者抓住(IllegalArgumentExc0019 e)来处理想要对减法做出反应的问题有点难。IAE仍然太“笼统”。
    • 这可能有点令人困惑。

    优点很简单:

    • 它已经在那里了。

    我认为这比IAE严重得多。这基本上是同一个故事,除了这里的混淆是ISE通常用于标记对象的当前状态,即您试图调用的操作根本不可用。以一种经过调整的方式,这实际上是真的(对象的状态是有3个项目;因此它现在不是处于decreaseQuantity(5)是可用操作的状态),但它感觉比IAE更混乱:ISE感觉产品对象本身处于无效状态。我假设该产品是一个遗留产品,现在没有或将来再也不会有库存,或者是某种虚拟产品类型(表示“未知产品”或类似异国情调的产品对象)。

    但是,同IAE一样:ISE的javadoc并没有明确说明你做不到。因此,如果你更喜欢抛出这个,你可以,这并不能证明是不正确的,最坏的情况是这只是糟糕的代码风格。棉绒工具永远不会因为它而责怪你,或者如果它这样做了,棉绒工具是错误的。

    优点:

    • 您的库的用户不可能做出错误的假设(即IAE的意思是:无论处于何种状态,争论都是非法的);这样就不那么令人困惑了
    try {
      product.decreaseQuantity(5);
    } catch (QuantityInsufficientException e) {
      ui.showOrderingError("Regretfully we don't have this item in stock at the quantity you want");
    }
    

    可读性略高于cat(IllegalArgumentExc0019),更重要的是,更可靠:IAE是一个经常使用的异常,以至于有一天你会编辑decreseQuantity方法,并引入一个代码路径,将IAE抛出给其他一些原因,现在你有一个很难找到的错误。

  • 谢璞
    2023-03-14

    java.lang.IllegalArgumentExc0019是这种情况下的正确答案。

    示例等同于有效Java-第三版(第301页)中的以下示例:

    考虑一个代表一副牌的物体的情况,假设有一种方法可以从一副牌中处理一手牌,这把牌的大小作为参数。如果调用方传递的值大于套牌中剩余的卡的数量,则可以将其解释为IllegalArgumentExc0019(HandSize参数值过高)或IllegalStateExc0019(套牌中包含的卡太少)。在这种情况下,规则是如果没有参数值可以工作,则抛出IllegalStateExcture,否则抛出IllegalArgumentExcure。

    IllegalStateException不正确,因为对象的状态不阻止调用decreaseQuantity:您可以调用它,只需使用适当的输入值即可。

     类似资料:
    • 这是我如何使用它 - 此外,我已经在超文本传输协议GET周围放置了一个最终块- 这是我的堆栈跟踪- 我正在使用Quartz来安排监控Httpendpoint的工作…这是我的连接池配置 马文依赖..神器版本 编辑-嗯,这个问题通过在最后一个块中不关闭CloseableHttp客户端而得到解决…有人能告诉我为什么它会这样吗?如果我关闭客户端,为什么连接池会关闭? 上面的closeablehttpcli

    • 我有密码 我想知道抛出怎么会发生这种情况。这显然发生在我的应用程序的一个用户身上,但我无法跟踪出了什么问题。

    • 我正在尝试使用下面的快速加载API 连接…等是完美的。 我确切地知道它在哪里失败 例外情况是 < code >线程“main”Java . lang . illegalstateexception中出现异常:示例失败。 这是我试图上传的表格。它是格式,当我通过记事本打开它时,它看起来像这样 为什么我会得到这个异常?我该如何改进?据我理解问题是< code > pstmtfld . setascii

    • 在使用Hibernate的持久化实体的上下文中,我想给开发人员提供更多的线索,当他们遇到。 我曾考虑在延迟加载的字段getter中捕获它,然后抛出一个带有新消息的IllegalStateException: IllegalStateExcture似乎完全适合: 表示方法已在非法或不适当的时间被调用。换句话说,Java环境或Java应用程序不处于用于所请求操作的适当状态。 (来源:https://d

    • 我见过这样的例子 但我也认为这是一种选择 抛出异常或简单返回NotFound (IHttpActionResult实例)有什么好处吗? 我知道响应/请求管道中的某些阶段可以处理这些结果中的任何一个,就像第一个示例一样

    • 在我开始添加更多存储库之前,我的代码只使用一个存储库包就可以正常工作 主数据源配置类: 存储库: 服务层: 服务实施: 实体类: 其他实体和存储库已被排除在外。