Collections
defensive copy: 入力Listの後続変更から状態を守る
List.copyOfで受け取ったListをコピーすると、呼び出し元による後続変更が内部状態へ漏れません。
SourceMemberNames.java
Java 21
package examples.defensivecopy;
import java.util.List;
public final class MemberNames {
private final List<String> names;
public MemberNames(List<String> names) {
this.names = List.copyOf(names);
}
public List<String> values() {
return names;
}
}TestMemberNamesTest.java
Java 21
package examples.defensivecopy;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
class MemberNamesTest {
@Test
void constructorは入力Listをコピーして後からの変更を受けない() {
var input = new ArrayList<>(List.of("Ada"));
var names = new MemberNames(input);
input.add("Linus");
assertEquals(List.of("Ada"), names.values());
}
@Test
void 公開するListも変更できない() {
var names = new MemberNames(List.of("Ada"));
assertThrows(UnsupportedOperationException.class, () -> names.values().add("Linus"));
}
}01Assertion
このテストで確認できること
- 入力Listを変更しても保持済みの値は変わらない
- 公開したListは変更できない
可変コレクションをそのまま保持すると、コンストラクタの外からオブジェクトの不変条件を壊せます。境界でコピーして所有者を分けます。
OBSERVED RESULT
expected: values → [Ada]
actual: [Ada]
expected exception: UnsupportedOperationException