Search code examples
javaarrayslistliskov-substitution-principle

Is Arrays.asList a violation of Liskov Substitution Principle?


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?


Solution

  • 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.