如果符合以下情况,您会抛出IllegalStateException
final
并仅在构造函数中分配?教科书示例:您的类是不可变的Collection<BigInteger>
,并且您的方法应该返回最大元素,但此实例为空。
我已阅读有关该主题的Kevin Bourillon`s blog post,我不确定适用哪条规则。
UnsupportedOperationException - 这意味着无论实例的构造方式如何,对于此类的实例(具体类型),调用的方法总是会失败。
绝对不是。这个类的许多实例都不是空的,操作也会成功。
IllegalStateException - ...确实存在至少一个有问题的实例可能已进入的备用状态,它将通过检查...&lt; snip&gt; ...另请注意,无论是否可以实际改变实例状态的这一方面,或者已经太晚,这个例外都是合适的。
不完全。这个实例是用零长度构造的,所以这个实例不是,而且永远不会是非空的。
IllegalArgumentException - 抛出此异常意味着此参数至少存在一个其他值会导致问题通过。
如果相关参数是隐式this
参数,则可以应用。这是我想要抛出的例外,但我担心它可能会令人困惑。
更新:将示例从Collection<Integer>
更改为Collection<BigInteger>
,因为存在标识元素(Integer.MIN_VALUE
)会从问题中分散注意力。
答案 0 :(得分:11)
这听起来不像上面提到的任何常见异常类都适合Textbook示例。
你应该抛出一个NoSuchElementException
,就像Collections.max()
方法那样。
答案 1 :(得分:4)
我认为IllegalStateException
在这里是合适的。如果构造正确(即“已经太晚了”部分),该实例可能处于正确的状态。
答案 2 :(得分:3)
如果类的状态有效(空集合),则max元素仅为null。如果状态无效,则应该在构造时抛出IllegalArgumentException。
答案 3 :(得分:3)
IllegalStateException最接近你想要的:“无论是否可以实际改变实例状态的这个方面,这个异常都是合适的。”
Not UnsupportedOperationException,因为它可能对该类的某个实例成功,并且为一个(可能)不带参数的方法抛出IllegalArgumentException肯定会让人感到困惑。
答案 4 :(得分:2)
IllegalStateException是否适用于不可变对象?
不,因为不可变对象只有一个状态,并且无法从一个合法状态变为另一个合法状态。
所以,你正在构造一个不可变对象,你的对象应该有一个max方法
class YourObject {
public BigInteger max(){ ... }
}
我这个案例IllegalAgumentException
应该是正确的,但是在方法执行之前是正确的,但是在创建对象时!
因此,在这种情况下,如果你有一个不可变的大整数集合,并且你用零元素创建它,你就会在创建集合时收到一个“无效参数”,那就是你必须抛出异常。
我同意Jon,如果你的用例,或者在你的分析中,你愿意支持其余的操作,你可以抛出NoSuchElementException
,但我认为这将推迟问题。最好是首先避免创建对象。
因此,抛出IllegalArgumentException就像:
// this is my immutable object class
final class YourObject {
private final Collection<BigInteger> c;
public YourObject( BigInteger ... values ) {
if( values.length == 0 ) {
throw new IllegalAgumentException("Must specify at least one value");
}
... initialize the rest...
}
public BigInteger max() {
// find and return the max will always work
}
}
客户:
YourObject o = new YourObject(); // throws IllegalArgumentException
// the rest is not executed....
doSomething( o ) ;
...
doSomething( YourObject o ) {
BigInteger maximum = o.max();
}
在这种情况下,您不需要检查doSomething
中的任何内容,因为程序在创建实例时会失败,而实例又会在开发时修复。
投掷NoSuchElementException
就像:
final class YourObject {
private final Collection<BigInteger> c;
public YourObject( BigInteger ... values ) {
// not validating the input :-/ oh oh..
... initialize the rest...
}
public BigInteger max() {
if( c.isEmpty() ) { throw NoSuchElementException(); }
// find and return the max will always work after this line
}
}
客户:
YourObject o = new YourObject(); // it says nothing
doSomething( o ) ;
...
doSomething( YourObject o ) {
BigInteger maximum = o.max();// ooops!, why? what?...
// your object client will start questioning what did I do wrong
// and chais of if( o != null && o.isEmpty() || moonPhaseIs... )
}
请记住,如果一个程序失败,你可以做的最好的事情是to making it fail fast。
Collections.max有不同的目的,因为作为一个实用工具方法(不是一个不可变对象),他不能对空集合的创建负责(当发生这种情况时他不在场),他唯一能做的就是就是说“这个集合中没有max这样的东西”因此NoSuchElementException。
最后一句话,RuntimeExceptions,should be used for programming mistakes only(可以通过在发布之前测试应用程序来解决这些问题)
答案 5 :(得分:2)
你应该抛出一个UnsupportedOpertationException
,因为这就是Java标准库在相同的情况下所做的事情。您的示例是类型限定符对象协议。此模式在"An Empirical Study of Object Protocols in the Wild":
某些类型会在生命周期内禁用某些方法 物体。在类型限定类别中,对象实例将在构造时进入抽象状态S,它将永远不会离开。调用实例 方法m,如果在状态S中禁用它将始终失败。
在您的示例中,您的对象进入一个抽象状态,我在构造时将其称为 EmptyCollection ,并且它永远不会离开该状态,因为集合字段为final
。在 EmptyCollection 抽象状态中,对getMax()
实例方法的所有调用都将始终失败。
Beckman研究了寻找对象协议的开源Java程序,并对结果类进行了分类。第三种最常见的协议类别出现在16.4%的采样协议中,是类型限定符。
Beckman的论文列出了许多类型限定符示例,我选择了其中的三个,并且在每种情况下,不可用的方法都会抛出UnsupportedOperationException
:
Colections.unmodifiableList(...)
创建不可修改的列表,然后在结果列表中调用add
方法时。java.nio.ByteBuffer
,然后调用array
方法。java.imageio.ImageWriteParam
时,请调用setCompressionMode
方法。请注意,这些示例 not 遵循Kevin Bourillon建议您引用。这些方法的失败取决于实例的构造方式。在示例1和示例2中,成功和失败的实例可能具有不同的具体类,因为List
和ByteBuffer
是抽象的。但是,ImageWriteParam
是一个具体类,因此ImageWriteParam
的一个实例可能抛出UnsupportedOperationException
而另一个实例可能不抛出IllegalStateException
。由于Java标准库设计者还定义了异常类型,我将遵循他们的领导而不是Bourillon先生。
P.S。您应该使用{{1}}而不是对象的抽象状态可以在运行时更改。贝克曼论文中其他83.6%的例子属于这种类型。