Java Exception Handling

Java Exception Handling – UnsupportedOperationException

Making our way through our detailed Java Exception Handling series, today we’ll dive into the UnsupportedOperationException. The UnsupportedOperationException is used by a number of built-in Java methods to indicate that the method in question is not currently implemented. This is functionally similar to exceptions found in other languages, such as the .NET NotImplementedException we explored in a previous article.

In today’s article we’ll examine the UnsupportedOperationException in more detail, beginning with a dive into where it sits in the overall Java Exception Hierarchy. We’ll also go over a handful of functional code samples illustrating how UnsupportedOperationExceptions can be thrown in the standard Java library, along with how you might consider using them in your own code, so let’s get started!

The Technical Rundown

All Java errors implement the java.lang.Throwable interface, or are extended from another inherited class therein. The full exception hierarchy of this error is:

Full Code Sample

Below is the full code sample we’ll be using in this article. It can be copied and pasted if you’d like to play with the code yourself and see how everything works.

This code sample also uses the Book.java class, the source of which can be found on GitHub.

It also uses the Logging.java class, the source of which can be found on GitHub.

When Should You Use It?

The overall purpose of the UnsupportedOperationException is to indicate that the called method is not implemented or supported at present. This might be due to ongoing development, which has to yet to finish the method. Another common use for the UnsupportedOperationException is when the called method is required due to implementation of an interface, yet invoking said method would be considered improper or invalid. This is similar behavior to the .NET InvalidOperationException that we looked at a few months ago.

No matter what the intention is, throwing an UnsupportedOperationException is the primary means of indicating that a method is not supported and should produce an error. To illustrate this behavior we’ll start with some of the built-in Java library usage of the UnsupportedOperationException. A common collection of classes that make heavy use of this exception are, well, the Collection-interfaced classes. There are many types of collections within the standard library, and many of them share the same interface implementations, yet they don’t all wish to allow the same functionality.

As an example, imagine that you need a collection that is unmodifiable (i.e. immutable). To accomplish this you might look to the AbstractList<E> class. Since this is an abstract class we must imeplement it ourselves in our own class, so we’ll do so in the DefaultAbstractList<E> class:

As it happens, if we simply need to create an immutable list from AbstractList<E>, we merely need to extend the class and override the get(int index) and size() methods, as seen above. Now we can test our DefaultAbstractList<E> out. We’ll be creating a Book instance and attempting to add that element to our DefaultAbstractList<Book> instance. Our addBookToList(Book book, AbstractList<Book> list) helper method will make this process easier to repeat:

Since AbstractList<E> is a parent class of our DefaultAbstractList<E> class, we’re able to specify it as the expected parameter type of our method, allowing us to pass other class instances that extend AbstractList<E> later on. Otherwise, the functionality of addBookToList(...) is fairly simple: We start by outputting the book info and list class we’re attempting to add it to. Then we call the add(int index, E element) method of the list parameter. Finally, we output the modified list information, including the newly added element.

To test this out our Main.main(...) method creates a new DefaultAbstractList<Book> instance, then attempts to add a new Book instance to it via addBookToList(...):

If you’re familiar with using AbstractLists already, you may see what’s coming. Executing the test code above produces the following output:

Here we catch our first UnsupportedOperationException which, unfortunately, fails to provide much useful information since there’s no associated error message. A bit of digging reveals that the issue is that, while the AbstractList<E> includes the add(int index, E element) method, it intentionally throws an UnsupportedOperationException when invoked. This is because calling an add(...) method of any collection indicates that the collection should be changeable (mutable), which we did not plan for in our DefaultAbstractList<E> class.

To resolve this we’ll create another class that is designed to handle mutable lists, MutableAbstractList<E>:

Our MutableAbstractList<E> class actually includes some basic collection functionality. We’ve added a private ArrayList<E> list property, along with implementation of the add(int index, E element), get(int index), and size() methods. Once again, let’s test this out by creating another new Book instance and attempting to add it to a new MutableAbstractList<E>:

This time we have no trouble invoking the add(int index, E element) method to add our new Book instance, which results in the expected output showing the book being added to the collection:

That’s cool and we’ve now seen how the standard Java library sometimes throws UnsupportedOperationExceptions to indicate invalid method calls. However, let’s look briefly at how we might throw an UnsupportedOperationException in our own code, under the right circumstances. To accomplish this we’ll look at our last custom class, aptly named ImmutableList<E>:

Functionally this class is similar to the MutableAbstractList<E> except, as the name suggests, it shouldn’t allow collection elements to be modified. Thus, both implementations of the add(...) method in this class intentionally throw an UnsupportedOperationException. Unlike the standard Java throws we saw earlier, we’ve opted to include some more useful information in the error message.

Although subtle, we have to use a slightly different addBookToList(...) method signature than before, since ImmutableList<E> doesn’t extend the AbstractList<E> class that our previous examples did. Attempting to use the addBookToList(Book book, AbstractList<E> list) method signature with an ImmutableList<E> argument would result in a compilation error, so we’re using this second method signature instead:

Otherwise, our call to addBookToList(...) is much the same as before:

As expected and intended, executing the above results in a thrown UnsupportedOperationException, which includes our detailed error message:

The Airbrake-Java library provides real-time error monitoring and automatic exception reporting for all your Java-based projects. Tight integration with Airbrake’s state of the art web dashboard ensures that Airbrake-Java gives you round-the-clock status updates on your application’s health and error rates. Airbrake-Java easily integrates with all the latest Java frameworks and platforms like Spring, Maven, log4j, Struts, Kotlin, Grails, Groovy, and many more. Plus, Airbrake-Java allows you to easily customize exception parameters and gives you full, configurable filter capabilities so you only gather the errors that matter most.

Check out all the amazing features Airbrake-Java has to offer and see for yourself why so many of the world’s best engineering teams are using Airbrake to revolutionize their exception handling practices!