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.java
is boilerplate hell. -
Generic type descriptors. Hidden inside each of Guava, Gson, and Guice are mechanical implementations of
GenericArrayType
,ParameterizedType
,TypeVariable
, andWildcardType
. This wasted code is particularly tragic because Java 8’sTypeVariable
interface broke backwards compatibility. -
Collections. The
List
andSet
interfaces are too big to implement directly, so we haveAbstractList
andAbstractSet
. IfList
andSet
were 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.