All Downloads are FREE. Search and download functionalities are using the official Maven repository.

errorprone.bugpattern.Immutable.md Maven / Gradle / Ivy

The newest version!
This check validates that all classes annotated with Error Prone's `@Immutable`
annotation (`com.google.errorprone.annotations.Immutable`) are deeply immutable.
It also checks that any class extending an `@Immutable`-annotated class or
implementing an `@Immutable`-annotated interface are also immutable.

NOTE: Other versions of the annotation, such as
`javax.annotation.concurrent.Immutable`, are currently *not* enforced.

An object is immutable if its state cannot be observed to change after
construction. Immutable objects are inherently thread-safe.

A class is immutable if all instances of that class are immutable. The
immutability of a class can only be fully guaranteed if the class is final,
otherwise one must ensure all subclasses are also immutable.

A conservative definition of object immutability is:

*   All fields are final;
*   All reference fields are of immutable type, or null;
*   It is *properly constructed* (the `this` reference does not escape the
    constructor).

The requirement that all reference fields be immutable ensures *deep*
immutability, meaning all contained state is also immutable. A weaker property,
common with container classes, is *shallow* immutability, which allows some of
the object's fields to point to mutable objects. One example of shallow
immutability is guava's ImmutableList, which may contain mutable elements.

It is possible to implement immutable classes with some internal mutable state,
as long as callers can never observe changes to that state. For example, some
state may be lazily initialized to improve performance.

It is also technically possible to have an immutable object with non-final
fields (see the implementation of `String#hashCode()` for an example), but doing
this correctly requires subtle reasoning about safe data races and deep
knowledge of the Java Memory Model.

If you have an immutable class with mutable fields as described above, you can
mark it as such by [suppressing the Immutable check](#suppression) on it. This
will allow your class to be included in other `@Immutable` classes.

For more information about immutability, see:

*   Java Concurrency in Practice §3.4
*   [Effective Java 3rd Edition §17][ej3e-17]

## Type Parameters

When an `@Immutable` class has type parameters that are used in the type of that
class's fields, that class is called an immutable generic container. Usages of
immutable generic container classes, such as `ImmutableList`, are only actually
deemed immutable if the arguments to all such type parameters are also deemed
immutable. For example, an `ImmutableList` is deemed immutable since
`String`s are immutable. However, an `ImmutableList` is not deemed
immutable since `Object`s are not provably immutable.

When creating generic container classes, Error Prone requires that you declare
whether that container is allowed to be used with mutable, or only with
immutable type parameters.

### `@Immutable(containerOf = ...)`

If you want to allow your immutable generic container to possibly contain
mutable types, use `@Immutable`'s `containerOf` method:

```java
@Immutable(containerOf = "T")
class ImmutableHolder {
  final T ref;
  ...
}
```

Error Prone will allow you to instantiate an `ImmutableHolder` and use
it as a field in another `@Immutable` class. You may instantiate an
`ImmutableHolder`, but since it is mutable, Error Prone would report an
error if that was a field of another `@Immutable` class.

### `@ImmutableTypeParameter`

If you want to allow your `@Immutable` generic container to only contain
immutable types, use `@ImmutableTypeParameter`:

```java
@Immutable
class ImmutableContainer<@ImmutableTypeParameter T> {
  final T ref;
  ...
}
```

Error Prone will allow you to instantiate a `ImmutableContainer` and use
it as a field in another `@Immutable` class. However, it is a compiler error to
instantiate an `ImmutableContainer`.

`@ImmutableTypeParameter` can restrict generic parameters to immutable types
only but the generic itself may not be immutable.

```java
class MutableContainer<@ImmutableTypeParameter T> {
  ...
}
```

You can also use `@ImmutableTypeParameter` to annotate a method's type
parameters:

```java
class SomeMutableClass {
  <@ImmutableTypeParameter T> ImmutableList putInImmutableList(T t) {
    return ImmutableList.of(t);
  }
}
```

### Type Parameters Not Used in Fields

If your `@Immutable` class has a type parameter that is not used in the type of
your class's fields, then there is no need to use `containerOf` or
`@ImmutableTypeParameter`:

```java
@Immutable
class NonContainer {
  ... // No fields whose type contains T
  void process(T element) {
    // process 'element', which won't violate NonContainer's immutability.
  }
}
```

## Suppression

Suppress false positives by adding an `@SuppressWarnings("Immutable")`
annotation to the enclosing element, or the offending field.

To suppress warnings in AutoValue classes, add `@AutoValue.CopyAnnotations` to
ensure the suppression is also applied to the generated sub-class:

```java
@AutoValue
@AutoValue.CopyAnnotations
@Immutable
@SuppressWarnings("Immutable")
class MyAutoValue {
  ...
}
```

[ej3e-17]: https://books.google.com/books?id=BIpDDwAAQBAJ