Java Immutable Object

이불빨래장인·2022년 7월 20일
0

CS

목록 보기
1/2

java immutable

기본적인 자바 문법과 활용보다 자바가 어떻게 돌아가는지 궁금해서 만든 시리즈입니다.
틀린 부분이 반드시 있을 수 있으니 댓글로 알려주세요!


문득 자바로 알고리즘을 풀면서 든 생각인데 기존의 알고리즘을 풀던 것과 다르게 문제 상황에 맞는 클래스들을 생성하고 함수를 분리하며 변수들의 scope에 대한 고민이 생겼다. 이런 기본적인 상식을 무시하고 코딩을 하고 있던 거에 회의감이 들어 이번 기회에 한번 쫙 정리해보려고 한다.
일단 immutable 객체를 알아보기 전에 이전 상식들을 점검해보자.


Wrapper 클래스란?


(primitive) wrapper class in Java is one of those eight classes that wrap a (=one) primitive value.
-> (원시) 래퍼 클래스는 (하나의) 원시 값을 래핑하는 클래스들이다. (총 8개)
ex) Integer, Boolean, Long ...
String은 wrapper 클래스가 아니다!


final 키워드


final 키워드는 기본적으로 한번 넣으면 끝 이라는 뜻이다. 이 키워드는 클래스, 메소드, 변수에 붙을 수 있다.
클래스 -> 상속 불가능 (이므로 메소드 오버라이딩 불가)
메소드 -> 변경 불가능 (메소드 오버라이딩 불가)
변수 -> 변경 불가능 (변수 수정 및 재할당 불가)



Immutable class

위 두 기본적인 키워드를 알고 immutable class가 뭔지 공부해보자.
우리가 자주 쓰는 String 클래스와 (primitive) Wrapper 클래스들은 기본적으로 immutable하다.
immutable과 final의 개념을 혼동하는 경우가 있는데 (나처럼) final의 경우에는 컴퍼일 시점에 final 키워드를 참조하는 모든 값을 변경해버리고 수정하지 못하게 한다.
immutable의 경우에는 객체가 생성된 이후 값을 수정할 경우 새로운 객체를 참조해버리게 된다. 그리고 기존에 참조하고 있던 객체는 gc에 의해 사라지게 된다. (더 이상 필요가 없다면)

이렇게 듣기엔 immutable을 왜 사용하는지 모를것이다. 간단하게 예를 들면

public static void main(String[] args) {

    String a  = "a";
    Add(a, "p");
    Add(a, "c");

}

public static void Add(String a, String add) {
    a += add;
    System.out.println(a);
}

위 코드의 결과는 ap ac이다. 왜냐면 Add라는 함수에서 레퍼런스하는 "a"라는 String타입의 변수는 immutable하기 때문에 값을 수정해도 처음에 ap라는 값을 가지는 새로운 객체를 받아서 참조하고 다시 원래 스코프에서 참조하던 a를 넘겨 ac라는 값을 출력하기 때문이다

public static class Tmp{
    public String a;
}

public static void main(String[] args) {
    Tmp a = new Tmp();
    a.a = "a";
    Add(a, "p");
    Add(a, "c");

}

public static void Add(Tmp a, String add) {
    a.a += add;
    System.out.println(a.a);
}

하지만 이 경우에는 결과값이 ap apc이다. Tmp라는 클래스는 immutable하지 않기 때문에 함수에서 변경한 값 그대로 사용하게 되는 것이기 때문이다.

이런 경우들이 있기에 effective자바나 뭐 클린코드나 여러곳에서 최대한 많은 클래스를 immutable하게 만들라는 것이다.
우리가 짠 함수에 다른 사람의 클래스를 가져다 쓰는데 깜빡 잘못하여 클래스 변수를 이상하게 바꾸고 그게 전체 프레임워크에 영향을 준다면 절망적일것이기 떄문이다.


GC에 대해선 많이 모르지만 stack overflow의 형님들 말에 따르면

Immutable objects do not need a defensive copy if you are sharing them across contexts
(.e.g calling code you don't trust) or for thread safety. 
This can mean that reads of immutable objects can be lower in terms of garbage.

On the other hand, every time you change an immutable object, 
you have to create new objects whether this is required or not. 
In this regard, immutable objects can create far more garbage.

The real question is whether you are making lots of reads, or lots of writes (or a mix) 
Depending on usage Immutable objects can save objects or create more objects, 
so it makes sense to use either Immutable or Mutable object 
based on your specific use case.

Note: most of the time, correctness is far, far more important than performance, 
and while in general Immutable objects have higher overhead IMHO, 
it is far easier to prove the correctness of data models using Immutable objects, 
and it is worth using immutable objects for clarity and ease of reasoning alone.

이라고 하신다.

결국 immutable한 객체의 잦은 read or write가 있다면 항상 새로운 객체를 만들어야하기 때문에 많은 gc가 일어날 수 있다. 하지만 많은 경우에 정확도가 최적화보다 중요하기 때문에 정확도를 위해 immutable object를 쓰는게 좋다. 라고 하고 바로 위에는 그래서 우리는 functional programming이라는 걸 사용하기로 했어요~ 와 같은 답변도 있었다.

profile
잡다한 것에 관심이 많은 사람

0개의 댓글