Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Arrays.asList a violation of Liskov Substitution Principle? [duplicate]

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?

like image 865
Gonen I Avatar asked Sep 19 '25 02:09

Gonen I


2 Answers

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.

like image 195
Sergey Kalinichenko Avatar answered Sep 20 '25 15:09

Sergey Kalinichenko


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.

like image 23
Andy Turner Avatar answered Sep 20 '25 16:09

Andy Turner