xref: /aosp_15_r20/external/auto/value/userguide/practices.md (revision 1c2bbba85eccddce6de79cbbf1645fda32e723f0)
1# Best practices
2
3
4## <a name="interchangeable"></a>"Equals means interchangeable"
5
6Use AutoValue when you want value semantics. Under value semantics, if `a` and
7`b` are instances of the same AutoValue class, and `a.equals(b)`, then `a` and
8`b` are considered interchangeable, and `a` can be used in place of `b`
9everywhere and vice versa. If your AutoValue use case does not satisfy these
10contracts, then AutoValue may not be a good fit.
11
12## <a name="mutable_properties"></a>Avoid mutable property types
13
14Avoid mutable types, including arrays, for your properties, especially if you
15make your accessor methods `public`. The generated accessors don't copy the
16field value on its way out, so you'd be exposing your internal state.
17
18Note that this doesn't mean your factory method can't *accept* mutable types as
19input parameters. Example:
20
21```java
22@AutoValue
23public abstract class ListExample {
24  abstract ImmutableList<String> names();
25
26  public static ListExample create(List<String> mutableNames) {
27    return new AutoValue_ListExample(ImmutableList.copyOf(mutableNames));
28  }
29}
30```
31
32## <a name="simple"></a>Keep behavior simple and dependency-free
33
34Your class can (and should) contain *simple* intrinsic behavior. But it
35shouldn't require complex dependencies and shouldn't access static state.
36
37You should essentially *never* need an alternative implementation of your
38hand-written abstract class, whether hand-written or generated by a mocking
39framework. If your behavior has enough complexity (or dependencies) that it
40actually needs to be mocked or faked, split it into a separate type that is
41*not* a value type. Otherwise it permits an instance with "real" behavior and
42one with "mock/fake" behavior to be `equals`, which does not make sense.
43
44## <a name="one_reference"></a>One reference only
45
46Other code in the same package will be able to directly access the generated
47class, but *should not*. It's best if each generated class has one and only one
48reference from your source code: the call from your static factory method to the
49generated constructor. If you have multiple factory methods, have them all
50delegate to the same hand-written method, so there is still only one point of
51contact with the generated code. This way, you have only one place to insert
52precondition checks or other pre- or postprocessing.
53
54## <a name="final"></a>Mark all concrete methods `final`
55
56Consider that other developers will try to read and understand your value class
57while looking only at your hand-written class, not the actual (generated)
58implementation class. If you mark your concrete methods `final`, they won't have
59to wonder whether the generated subclass might be overriding them. This is
60especially helpful if you are *[underriding](howto.md#custom)* `equals`,
61`hashCode` or `toString`!
62
63## <a name="constructor"></a>Maybe add an explicit, inaccessible constructor
64
65There are a few small advantages to adding a package-private, parameterless constructor to your abstract class. It prevents unwanted subclasses, and prevents an undocumented public constructor showing up in your generated API documentation. Whether these benefits are worth the extra noise in the file is a matter of your judgment.
66