The one good principle. And I now I can see why: it was invented by people who knew their maths — type theory in this case. In lay terms it’s simple: anything you can observe about the base class, remains true of its derived classes. That way you can pretend instances of the derived classes are also instances of the base class, without any nasty surprise.
On the one hand, duh: that’s just subtyping. But on the other hand, very few type systems enforce it — Java and C++ do not. That makes it very easy to make a dumb mistake like overriding a stable sort() method, and make it not stable for the derived class.
Javas immutable lists are an example of that right in the standard library.
The super type List has mutability. When you call any of these methods in the immutable list, you get an exception.
So if you have an arbitrary List object, you have no idea whether calling any method that mutates the object will work or not.
And this is doubly bad with the linter demanding you use Stream.toList() (which returns an immutable list) instead of Stream.collect(Collectors.toList()) (which returns a mutable list).
Horrible, dumb design.