なぜ不変オブジェクトとfinalを使用するのか
なぜ「不変オブジェクト」(Immutable Object)と「final」を使うのか
不変オブジェクトとは?
不変オブジェクト(Immutable Object)とは、オブジェクトの作成後に内部状態が変化しないオブジェクトのことです.
オブジェクトの内部状態を提供する方法を提供したり提供したりしないread-onlyメソッドのみが提供される場合は、防御コピーで提供されます.
Javaの代表不変オブジェクトにStringがあります.
String name = "Old";
name = "New";
name.toCharrArray()[2] = 'o';
JavaのStringは不変クラスなので、nameという変数に「New」を割り当てるのは内部charを変更するのではなく、新しい値を持つオブジェクトを作成します.また,String内部のchar型アレイが修正されても反映されない.Javaは、配列やオブジェクトなどの参照を渡します.したがって、値を参照して修正すると内部の状態が変化するので、内部をコピーして伝達しています.これを防御コピーと呼びます.JavaのStringは、toCharArrayをコピーし、次のように転送します.public char[] toCharArray(){
// Cannot use Arrays.copyOf because of class initialization order issues
char result[] = new char[value.length];
System.arraycopy(value, 0, result, 0, value.length);
return result;
}
なぜ不変オブジェクトとfinalを使用するのか
ただし、共有リソースが不変のリソースであれば、同期を考慮する必要はありません.
常に同じ値を返すため、安定性が保証されるだけでなく、非同期によるパフォーマンスのメリットもあります.
不変オブジェクトは、一度作成した後では変更できないオブジェクトであり、Javaはfinalキーワードを使用して不変オブジェクトを作成することができます.つまり、このようにオブジェクトを作成するためには、オブジェクトを持つコンテナも存在します.もちろん、コンテナは、不変のオブジェクトを作成してからオブジェクトを参照することができます.
つまり、コンテナはコンテナが参照する最も若いオブジェクトよりも若い(作成が遅い).これにより、ゴミ収集器がGCを実行する際にコンテナサブアイテムの不変オブジェクトをSkipするのに役立ちます.このコンテナがまだ生きていることは、サブオブジェクトの不変オブジェクトも最初に割り当てられた状態で参照されることを意味するからである.
最終的には,不変のオブジェクトを利用すると,ゴミ収集器がスキャンする必要があるオブジェクトの数が減少し,スキャンする必要があるメモリ領域や周波数も減少し,GCが実行されても遅延時間が減少する.
不変性のあるコードレイアウト
ex)不変性を保証しない
@RequiredArgsConstructor
@Service
public class UserService {
private final UserRepository userRepository;
private final UserGroupRepository userGroupRepository;
public void getUserGroup(String searchKeyword) {
List<String> userIdList = userRepository.findUserIdList(searchKeyword);
if(userIdList.isEmpty()) {
return UserGroup.builder() .userGroupList(Collections.emptyList()).build();
}
List<UserGroup> userGroupList = userGroupRepository.findAllByUserIdList(userIdList);
updateUserGroupLanguage(userGroupList, userIdList);
return UserGroup.builder() .userIdList(userIdList.isEmpty() ? Collections.emptyList() : userGroupList) .build();
}
private void updateUserGroupLanguage(List<UserGroup> userGroupList, List<String> userIdList) { // 생략 } }
上のコードの疑問点userIdListが空の場合、emptyListとして処理されて返されますが、なぜ次は3つの演算子で空かどうかをチェックしますか?そう思ってもいいです.上記のコード記述の妥当性を決定するために、updateUserGroupLanguage()関数の内部にuserIdList変異体が存在するかどうかを確認する必要があるかもしれません.(最終的には、不要なコードコメント時間が発生し、生産性が低下するなどの問題が発生します.)また、実際にupdateUserGroupLanguage関数を使用してuserIdListを変更することはありません.その論理は不要な論理なので、3つの演算子部分を削除できます.
updateUserGroupLanguageが不変性を保証する関数である場合、関数の内部を不要に表示する必要はありません.すぐにこの部分をクリアできると確信しています.
価格は変わらないと確信しているので、他の人の方法を使うことができます.
Javaは不変オブジェクトを作成する方法
ex)不変クラスの例
最終宣言
public final class ImmutableClass{
private final int age;
private final String name;
private final List<String> list;
private ImmutableClass(int age, String name){
this.age=age;
this.name=name;
this.list = new ArrayList<>();
}
public static ImmutableClass of(int age, String name){
return new ImmutableClass(age, name);
}
public int getAge(){
return age;
}
public String getName(){
return name;
}
public List<String> getList(){
return Collections.unmodifiableList(list);
}
}
上記のコードで注意すべき点は、内部ジェネレータを作成するのではなく、オブジェクトの作成に静的ファクトリメソッドを提供し、クライアントが変更可能なlistJavaでは、作成者が宣言されていない場合、デフォルトの作成者が自動的に作成され、他のクラスでオブジェクトを自由に呼び出すことができます.したがって、内部ジェネレータを作成するよりも、静的ファクトリメソッドによるオブジェクトの作成を強制します.
また、配列または他のオブジェクトまたはコレクションは、参照を渡すことによって変更できます.したがって、参照によって変更できる場合は、戻り値を防御的にコピーする必要があります.
非常に妥当な理由がない限り、階級は融通しなければならない.クラスを一定に保つことができない場合は、可能な変更を最小限に抑えます.
Reference
この問題について(なぜ不変オブジェクトとfinalを使用するのか), 我々は、より多くの情報をここで見つけました https://velog.io/@bey1548/불변-객체-및-final을-사용하는-이유テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol