Pattern matching does not work if you use an enum
List<String> list = cons("a", nil());
switch(list) {
case Cons<String>(var car, var cdr) -> ...
case Nil -> ...
}
Nil is typed List<Void> which is not compatible with List<String>.You may be able to use extractors as the inverse of the static methods cons() and nil() but that adds more boilerplate.
Disjunctive enums like in Rust or Scala 3 is a simpler way to define ADT.