Arrays.asList(..)
returns a List wrapper around an array. This wrapper has a fixed size and is directly backed by the array, and as such calls to add() or other functions that attempt to modify the list will throw an UnsupportedOperationException.
Developers are often surprised by this, as is evident from questions in stackoverflow.
However the List interface has an add() method which should work unsurprisingly for all derivers of List, according to the Liskov Substitution Principle (LSP)
Is the type returned by Arrays.asList() an example of a violation of the Liskov Substitution Principle?
Strictly speaking, it is, because LSP has no notion of optional interface members: a method is either part of an interface, or it is not part of an interface.
However, Java Class Library explicitly allows for violations of LSP when it designates certain interface methods as optional. List<T>.add()
is one such method. Other mutating methods (addAll
, remove
, etc.) are also marked optional.
Essentially, designers of Java library took a shortcut: rather than making a separate interface for mutable list (extending a read-only list) they went for designating an operation "optional". Moreover, they have not provided a way for you to test the instance of list for being read-only, so your only option is to catch a runtime exception, which is a very bad idea. This amounts to you having to keep track of where your lists came from, and performing optional operations only when you are 100% certain of your list origin.
I think it is not a violation of LSP.
LSP says that all instances of classes implementing a given interface can be used interchangably.
The documentation of List.add
(and other mutating methods) clearly states that an UnsupportedOperationException
might be thrown by implementations of that method.
Throws
UnsupportedOperationException
- if the add operation is not supported by this list
As such, if you're going to invoke this method on an instance of List
from an unknown source, you need to handle the case that add
throws an UnsupportedOperationException
.
If you don't, you're not using the API correctly.
This is not to say that I like the design. I think the fact that trying to invoke the method is the only way to detect that any given method is not supported on an instance is rubbish. I mean, heck, give us an isAddSupported()
method (or similar).
I just don't see that following documented behaviour can be violating LSP.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With