Reputation: 23
Could anybody tell me the example below violate LSP or not?
I have an example:
public class Person {
private String name;
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public void validate() {
if (age == null || age < 0) {
throw new IllegalArgumentException("Age can not be null");
}
}
}
and the subclass:
public class Employee extends Person {
private String employeeCode;
public Employee(String name, Integer age, String employeeCode) {
super(name, age);
this.employeeCode = employeeCode;
}
@Override
public void validate() {
super.validate();
if (employeeCode == null) {
throw new IllegalArgumentException("Employee code can not be null");
}
}
}
and the main class:
public class Main {
public static void main(String[] args) {
Person person = new Person("Person", 10);
validate(person); // will be ok. does not throw any exception
Person employee = new Employee("Employee", 30, null);
validate(employee); // will be throw IllegalArgumentException because subtype's employee code is null
}
public static void validate(Person p) {
p.validate();
}
}
In this example the subclass add new property called employeeCode
and override method validate
with additional check for it's own property employeeCode
.
In the main method I create 2 objects. The first one is object of type Person
and the second one is object of type Employee
.
When validate person it is ok because all precondition is ok
but for the employee it will throw an IllegalArgumentException
because it does not match precondition
Employee
violate LSP due to add new validation on employeeCode
?IllegalArgumentException("Employee code can not be null")
to another exception NullPointerException
. So does it violate LSP due to introduce new exception type in subtype (which super type does not have)?Upvotes: 1
Views: 307
Reputation: 11474
No, instances of Person
and Employee
have exactly the same range of behaviours when validate
is called. That is, calling it will either result in an IllegalArgumentException
being thrown, or it won't, so no code which is calling validate
and correctly handling the result of calling it on Person
will fail to correctly handle the result of calling it on Employee
.
n/a
In my opinion: As both IllegalArgumentException
and NullPointerException
are unchecked exceptions, they don't form part of the contract of validate
, which is entitled to throw any subclass of RuntimeException
it feels like. A better design would have throws ValidationException
as part of the signature of validate
.
As @jaco0646 says in their comment above, Java doesn't allow you to formally specify everything about a method.
Suppose I write another subclass of Person
and decide that my validate()
implementation will actually fix any invalid values by setting them to defaults. As we don't expect the validate()
method to mutate the object (even though we have no formal way of saying that), that would violate LSP.
Upvotes: 1