Stumbling over the Liskov Substitution Principle

Today I stumbled over a problem living in java for a long time. Iterating elements of a Java Stack will not be done in the order I expected. A Stack in Java is a Vector with additional push, peek and pop methods. As a Vector is a List and a List is an Iterable, the elements of a Stack can be processed using a for-each loop. Inheriting the behaviour from Vector means, that all elements are processed in the order they got added to the Stack. But this is not the order I expected a Stack would be iterated. The following code shows this behaviour.

Stack stack = new Stack<>();
stack.push("first");
stack.push("second");
for (String element : stack) {
  System.out.println(element);
}

Output:

first
second

Taking a look at the web, especially stackoverflow, reveals, that I am not the only guy requesting another order while iterating a Stack. Looking at the java bug tracker provides the reason for the current behaviour. The Stack class inherits the Vector class. Resulting in inherited methods and behaviour which cannot be deactivated. Looking at another piece of code shows this a bit more practical.

Stack stack = new Stack<>();
stack.push("first");
stack.push("second");
stack.add(1,"third");

for(String element : stack) {
  System.out.println(element);
}

Output:

first
third
second

As mentioned in the bug tracker, this behaviour violates the Liskov Substitution Principle, because a Stack does not behave like a Vector, so it should not inherit Vector. In the bug tracker is also mentioned, that this design decision was not a good one. But it has been taken and now we have to live with it. Additionally the JavaDoc comment of the Stack class tells us to use Deques as more complete implementations of a Stack.

Long story short, using a Deque as a Stack in Java looks like the following.

Deque stack = new LinkedList<>();
stack.push("first");
stack.push("second");

for(String element : stack) {
  System.out.println(element);
}

Output:

second
first

In the future I will keep an eye on the classes I use, especially whether an implementation fits the concept it implements or not.

Advertisements