java是否适用于不可变对象?
如果出现以下情况,您是否会抛出IllegalStateException
:
- 由于一个或多个字段的值,方法无法执行其工作
- 那些字段是
final
并且只在构造函数中赋值李>
教科书示例:您的类是一个不可变的Collection<BigInteger>
,您的方法应该返回最大元素,但是这个实例是空的
我已经阅读了关于这个主题的Kevin Bourillon`s blog post,我不确定哪条规则适用
UnsupportedOperationException - this means that the method invoked will always fail for an instance of this class (concrete type), regardless of how the instance was constructed.
绝对不是。该类的许多实例都不是空的,并且该操作本应已成功
IllegalStateException - ... there does exist at least one alternate state that the instance in question could have been in, which would have passed the check ... <snip> ... Note also that this exception is appropriate whether or not it is possible to actually mutate this aspect of the instance's state, or it's already too late.
不完全是。此实例是用零长度构造的,因此此实例不是且永远不可能是非空的
IllegalArgumentException - throwing this exception implies that there exists at least one other value for this parameter that would have caused the check in question to pass.
如果所讨论的参数是隐式this
参数,则可能适用。这是我想抛出的一个例外,但我担心这可能会令人困惑
更新:将示例从Collection<Integer>
更改为Collection<BigInteger>
,因为存在标识元素(Integer.MIN_VALUE
)的事实分散了问题的注意力
# 1 楼答案
IllegalStateException最接近您想要的:“无论是否可能实际改变实例状态的这一方面,此异常都是适当的”
不是UnsupportedOperationException,因为它可能会在该类的某个实例中成功,而为(可能)不带参数的方法抛出IllegalArgumentException肯定会让人困惑
# 2 楼答案
我认为
IllegalStateException
在这里是合适的。如果实例构造正确(即“已经太晚了”部分),则该实例可能处于正确的状态# 3 楼答案
听起来你上面提到的任何常见异常类都不适合教科书中的例子
您应该抛出一个^{} ,因为这正是^{} 方法所做的
# 4 楼答案
如果类的状态是有效的(空集合),max元素就是null。如果状态无效,则应在构造时引发IllegalArgumentException
# 5 楼答案
您应该抛出一个
UnsupportedOpertationException
,因为这是Java标准库在相同情况下所做的。您的示例是类型限定符对象协议。此模式在"An Empirical Study of Object Protocols in the Wild"中定义:在您的示例中,您的对象进入一个抽象状态,我将在构造时调用该状态,它永远不会离开该状态,因为集合字段是
final
。在EmptyCollection抽象状态下,对getMax()
实例方法的所有调用都将始终失败Beckman研究了开源Java程序,寻找对象协议,并对结果类进行了分类。第三个最常见的协议类别是类型限定符,占抽样协议的16.4%
Beckman的论文列出了许多类型限定符示例,我选择了其中三个,在每种情况下,unavailable方法都抛出一个
UnsupportedOperationException
:Colections.unmodifiableList(...)
创建不可修改的列表,然后对结果列表调用add
方法时李>java.nio.ByteBuffer
时,然后调用array
方法李>java.imageio.ImageWriteParam
时,然后调用setCompressionMode
方法李>请注意,这些示例并没有遵循您引用的Kevin Bourillon的建议。这些方法的失败取决于实例的构造方式。在示例1和2中,成功和失败的实例可能是不同的具体类,因为
List
和ByteBuffer
是抽象的。但是,ImageWriteParam
是一个具体的类,因此ImageWriteParam
的一个实例可能抛出UnsupportedOperationException
,而另一个实例可能不会抛出。由于Java标准库设计人员也定义了异常类型,我将遵循他们的指导,而不是Bourillon先生的另外,当对象的抽象状态可以在运行时更改时,应该使用
IllegalStateException
。贝克曼论文中的其他83.6%的例子属于这种类型# 6 楼答案
不,因为不可变对象只有一个状态,不能从一个合法状态转移到另一个合法状态
因此,您正在构造一个不可变对象,并且您的对象应该有一个max方法
我认为这种情况下
IllegalAgumentException
应该是正确的,但不是在执行方法之前,而是在创建对象时强>因此,在这个场景中,如果您有一个不可变的BigInteger集合,并且您使用零元素创建它,那么在创建集合时您将收到一个“无效参数”,此时您必须抛出异常
我同意Jon的观点,如果您的用例,或者在您的分析中,您愿意支持其余的操作,您可以抛出
NoSuchElementException
,但是我认为这会推迟问题的解决。最好首先避免创建对象因此,抛出IllegalArgumentException类似于:
客户:
在这种情况下,您不需要检查
doSomething
中的任何内容,因为程序在创建实例时会失败,而这又会在开发时修复抛出
NoSuchElementException
类似于:客户:
记住,如果一个程序失败,你能做的最好的事情就是to making it fail fast
Collections.max有一个不同的目的,因为作为一个实用方法(不是一个不变的对象),他不能对空集合的创建负责(发生时他不在场),他唯一能做的就是说“这个集合中没有max这样的东西”,因此没有任何uchelementexception
最后一句话,RuntimeExceptions,should be used for programming mistakes only(那些可以通过在发布应用程序之前测试它来修复的异常)