If you’re defining an Java API, value objects are your friend. And interfaces aren’t suited to that task.
Java gets this wrong all over:
Annotations. They use interfaces to define value objects, and consequently it’s quite awkward for tools like Guice to define annotation values.
NamedImpl.javais boilerplate hell.
Generic type descriptors. Hidden inside each of Guava, Gson, and Guice are mechanical implementations of
WildcardType. This wasted code is particularly tragic because Java 8’s
TypeVariableinterface broke backwards compatibility.
Setinterfaces are too big to implement directly, so we have
Setwere just abstract classes, Java 8 wouldn’t have needed default methods!
I’m annoyed that this mistake continues to be made. JAX-RS defined its headers type as an interface without a good way to build an instance in a unit test. Instead every application needs its own implementation for testing.
Interfaces are wonderful! They’re useful in all kinds of modeling problems. But for defining value objects, interfaces are a bad fit.