Is IllegalStateException appropriate for an immutable object?

You would IllegalStateException if:

  • The method cannot complete its work due to the value (s) of one or more fields
  • Are these fields final and assigned only in the constructor?

Tutorial example: your class is immutable Collection<BigInteger> , and your method should return the maximum element, but this instance is empty.

I read a Kevin Bourillon blog post on this subject, and I'm not sure which rule applies.

UnsupportedOperationException - this means that the called method will always fail for an instance of this class (specific type), regardless of how the instance was created.

Definitely not. Many instances of this class are not empty, and the operation would be successful.

IllegalStateException -... there is at least one alternative state in which the instance could be that passed the test ... <snip> ... Please also note that this exception is appropriate regardless of whether it is possible to mutate this aspect of the state of the instance, or it's too late.

Not really. This instance was constructed with zero length, so this instance is not and would never be nonempty.

IllegalArgumentException - An exception to this exception means that there is at least one other value for this parameter that could trigger a question check.

It can be used if the parameter in question is an implicit parameter of this . This is an exception that I am tempted to quit, but I am concerned that this may be confusing.


Update : changed the example from Collection<Integer> to Collection<BigInteger> , since the fact that there was an authentication element ( Integer.MIN_VALUE ) distracts from the question.

+6
java exception
source share
6 answers

I think an IllegalStateException is appropriate here. An instance could be in the correct state if it was built correctly (i.e., the Part is “Too Late”).

+4
source share

This is not like any of the usual exception classes mentioned above fit into the sample tutorial.

You should throw a NoSuchElementException as exactly what the Collections.max() method is.

+11
source share

If the state of the class is valid (empty collection), the maximum element is zero. If the condition is invalid, an IllegalArgumentException should be thrown during construction.

+3
source share

The IllegalStateException is closest to what you want: "This exception is appropriate regardless of whether it is possible to mutate this aspect of the state of the instance."

Not an UnsupportedOperationException, as it may succeed for some instance of this class and throw an IllegalArgumentException for a method that (presumably) takes no arguments, certainly confuses people.

+3
source share

Is IllegalStateException appropriate for an immutable object?

No, because immutable objects have only one state and cannot be transferred from one legal state to another.

So you create an immutable object, and your object should have a max method

 class YourObject { public BigInteger max(){ ... } } 

I this case of IllegalAgumentException should be correct, but only until this method is executed, but when the object is created!

So, in this case, if you have an immutable bigintegers collection and you create it with null elements, you get an “invalid argument” when creating the collection when you need to throw an exception.

I agree with John, if in your use case or in your analysis you are ready to support the rest of the operations, you can throw a NoSuchElementException , but I think that would postpone the problem. It would be better to avoid creating the object in the first place.

So, throwing an IllegalArgumentException will look like this:

  // 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 } } 

Client:

  YourObject o = new YourObject(); // throws IllegalArgumentException // the rest is not executed.... doSomething( o ) ; ... doSomething( YourObject o ) { BigInteger maximum = o.max(); } 

In this case, you do not need to check anything in doSomething , because the program will fail when creating an instance, which, in turn, will be fixed during development.

Throwing NoSuchElementException will look as follows:

  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 } } 

Client:

  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... ) } 

Keep in mind that if a program fails, the best thing you can do is for it to fail quickly .

Collections.max has a different purpose, because, being a utility method (not an immutable object), it cannot be held responsible for the empty (it was not present when it happened), the only thing it can do is say: "In this collection there is no such thing as max ", therefore, NoSuchElementException.

One final note, RuntimeExceptions, should only be used to program errors (those that can be fixed by testing the application before release)

+2
source share

You should throw an UnsupportedOpertationException because this is what the Java Standard Library does in the same circumstances. Your example is a protocol of type classifier objects. This template has been defined in the Empirical Study of Object Protocols in the Wild :

Some types disable certain methods for the lifetime of an object. In the category of quality type, an instance of an object introduces the abstract state S at the time of construction, which it will never leave. Calling an instance of method m, if disabled in state S, will always fail.

In your example, your object introduces an abstract state, which I will call EmptyCollection at build time, and it never leaves that state because the collection field is final . In the abstract state of EmptyCollection, all calls to the getMax() instance method will always fail.

Beckman studied open source Java programs that looked for object protocols and classified the resulting classes. The third most common protocol category, displayed in 16.4% of the selected protocols, was a type classifier.

Beckman's paper lists many examples of type classifiers, and I selected three of them, and in each case the unavailable method throws an UnsupportedOperationException :

  • When you create an unmodifiable list by calling Colections.unmodifiableList(...) , and then call the add method on the resulting list.
  • When you create java.nio.ByteBuffer which is not supported by an array, then calls the array method.
  • When creating java.imageio.ImageWriteParam , which does not support compression, then calls the setCompressionMode method.

Note that these examples do not follow the advice of Kevin Bourion that you are quoting. The failure of these methods depends on how the instances were created. In examples 1 and 2, instances that succeed and fail may have different specific classes, since List and ByteBuffer are abstract. However, ImageWriteParam is a specific class, so one instance of ImageWriteParam can ImageWriteParam UnsupportedOperationException , and the other can't. Since the designers of the standard Java library also defined exception types, I will follow their example, and not Mr. Burillon.

PS You should use an IllegalStateException if instead the abstract state of your object may change at runtime. The other 83.6% of the examples in Beckman's paper are of this type.

+2
source share

All Articles