Search code examples
javacloneablejava-recordjava-16

Is it okay to make a record cloneable?


I couldn't find any material on Google saying about the use of Cloneable records.

I was thinking of something like this:

record Foo() implements Cloneable {
    public Foo clone() {...}
}

Is it a good thing? Should we avoid it in favor of the future withers?


Solution

  • Apart from the fundamental problems of Cloneable there's another strong reason why one shouldn't make a record Cloneable:

    Records are inherently immutable. One of the biggest advantages of immutable classes is that one can stop worrying about object identity: any two objects with the same values can be used entirely interchangeable. The JavaDoc has a concept called Value-based Classes that goes a bit further (by disallowing public constructors and making any explicit use of object identity a mistake), but does describe the basic idea well.

    Therefore creating a clone() of a record would only ever produce a second object that for all intents and purpose should behave exactly the same as the original and can't ever change to behave differently (since records are immutable).

    This suggests that there's no valid reason to clone() a Record.

    And just for completeness sake: it is possible (but again, not suggested) to implement Cloneable in a record:

    record Foo(String a) implements Cloneable {
      public Foo clone() {
        try {
          return (Foo) super.clone();
        } catch (CloneNotSupportedException e) {
          throw new RuntimeException("this can't happen", e);
        }
      }
    }
    

    Running this test code proves that a clone is actually created:

    Foo original = new Foo("bar");
    Foo clonedFoo = original.clone();
    System.out.println(original + " / " + clonedFoo);
    System.out.println(System.identityHashCode(original) + " / " + System.identityHashCode(clonedFoo));
    

    produces this output:

    Foo[a=bar] / Foo[a=bar]
    670700378 / 1190654826