본문 바로가기
public void static main()/Book

[Effective Java] 아이템 17

by 햄리뮤 2023. 1. 18.
반응형

으아아아ㅏ아ㅏㅏ 최소 2개여서.... 17까지는 하고 자자ㅏㅏㅏㅏㅏ.....

 

[책 규칙]

노란색 - 자세히 알아보고싶은 부분

초록색 - 핵심 개념 (블로그 정리시는 검은색으로!)

빨간색 - 무슨말인지 모르겠는 부분

[아이템 17] 변경 가능성을 최소화 하라

불변 클래스란?

  • 인스턴스의 내부 값을 수정할 수 없는 클래스다. 
  • 불변 인스턴스에 간직된 정보는 고정되어 객체가 파괴되는 순간까지 절대 달라지지 않는다.
  • 불변 객체는 근본적으로 스레드 안전하여 따로 동기화할 필요 없다.
    • 여러 스레드가 동시에 사용해도 절대 훼손되지 않는다.
    • 불변 객체에 대해서는 그 어떤 스레드도 다른 스레드에 영향을 줄 수 없다.
  • 불변 객체는 자유롭게 공유할 수 있음은 물론, 불변 객체끼리는 내부 데이터를 공유할 수 있다.
  • 불변 객체는 그 자체로 실패 원자성을 제공한다. 상태가 절대 변하지 않으니 잠깐이라도 불일치 상태에 빠질 가능성이 없다.
실패 원자성
메서드에서 예외가 발생한 후에도 그 객체는 여전히(메서드 호출전과 똑같은) 유효한 상태여야 한다는 성질. 불변 객체의 메서드는 내부 상태를 바꾸지 않으니 이 성질을 만족한다.

클래스를 불변으로 만들려면 규칙을 지켜야 한다!

  • 객체의 상태를 변경하는 메서드(변경자)를 제공하지 않는다.
  • 클래스를 확장할 수 없도록 한다. 
    • 하위 클래스에서 부주의하게 혹은 나쁜 의도로 객체의 상태를 변하게 만드는 사태를 막아준다. 상속을 막는 대표적인 방법은 클래스를 final로 선언하는 것 등이 있다.
  • 모든 필드를 final로 선언한다.
    • 시스템이 강제하는 수단을 이용해 설계자의 의도를 명확히 드러내는 방법이다. 새로 생성된 인스턴스를 동기화 없이 다른 스레드로 건네도 문제없이 동작하게끔 보장하는 데도 필요하다.
  • 모든 필드를 private으로 선언한다.
    • 필드가 참조하는 가변 객체를 클라이언트에서 직접 접근해 수정하는 일을 막아준다. 기술적으로는 기본 타입 필드나 불변 객체를 참조하는 필드를 public final로만 선언해도 불변 객체가 되지만, 이렇게 하면 다음 릴리스에서 내부 표현을 바꾸지 못하므로 권하지는 않는다.
  • 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다.
    • 클래스에 가변 객체를 참조하는 필드가 하나라도 있다면 클라이언트에서 그 객체의 참조를 얻을 수 없도록 해야 한다. 이런 필드는 절대 클래이언트가 제공한 객체 참조를 가리키게 해서는 안 되며, 접근 메서드가 그 필드를 그대로 반환해서도 안 된다. 생성자, 접근자, readObject 메서드 모두에서 방어적 복사를 수행하라.

게터(getter)가 있다고 해서 무조건 세터(setter)를 만들지는 말자! 클래스는 꼭 필요한 경우가 아니라면 불변이어야 한다.

 

다른 합당한 이유가 없다면 모든 필드는 private final 이어야 하고,
생성자는 불변식 설정이 모두 완료된, 초기화가 완벽히 끝난 상태의 객체를 생성해야 한다.

확실한 이유가 없다면 생성자와 정적 팩터리 외에는 그 어떤 초기화 메서드도 public으로 제공해서는 안된다!

 

 

1. 아이템 개념

  • 불변 클래스: 인스턴스의 내부 값을 수정할 수 없는 클래스

2. 필요한 이유

  • thread-safe 하여 병렬 프로그래밍에 유욯하고 동기화를 고려하지 않아도 된다.
    • 멀티 쓰레드 환경에서 동기화 문제가 발생하는 이유는 공유 자원에 동시 쓰기 때문이다. 하지만 만약 공유 자원이 불변의 자원이라면 더이상 동기화를 고려하지 않아도 될 것이다. 
  • 실패 원자성 메소드를 만들 수 있다.
    • 가변 객체를 통해 어떠한 작업을 하는 도중 예외가 발생하면 해당 객체가 불안정한 상태에 빠질 수 있다. 그리고 불안정한 상태를 갖는 객체는 또 다른 에러를 유발할 수 있다. 하지만 불변객체라면 어떠한 예외가 발생하여도 메소드 호출 전의 샅애를 유지할 수 있을 것이다. 그리고 예외가 발생하여도 오류가 발행하지 않은 것 처럼 다음 로직을 처리할 수 있다.
  • 가비지 컬렉션의 성능을 높일 수 있다.
    • 불변의 객체는 한번 생성된 이후에 수정이 불가능한 객체로 Java에서는 final 키워드를 사용하여 불변의 객체를 생성할 수 있다. 이렇게 객체를 생성하기 위해서는 객체를 가지는 컨테이너도 존재한다는 것인데 당연히 불변의 객체가 먼저 생성되어야 컨테이너가 이 객체를 참조할 수 있을 것이다. 즉, 컨테이너는 컨테이너가 참조하는 가장 젋은 객체들보다 더 젊다는 것(늦게 생성됨)이다. 이러한 점은 GC가 수행될 때, GC컨테이너 하위의 불변 객체들은 skip할 수 있도록 도와준다. 왜냐면 해당 컨테이너가 살아있다는 것은 하위의 불변 객체들 역시 처음에 할당된 그상태로 참조되고 있다는 것을 의미하기 때문이다.

3. 아이템 개념의 반대 개념이나 관련 개념

4. 실무에서는 어떤식으로 사용되는가 (실제 코드 사용예시)

  • Setter 메소드를 사용하지 않아야 한다.
  • 모든 필드를 final 과 private을 사용하여 선언해야한다.
  • 클래스를 final 로 선언하여 Overriding을 막아야 한다.
  • 객체를 생성하기 위한 생성자 혹은 정적 팩토리 메소드를 추가해야 한다.
  • 인스턴스 필드에 가변객체가 포함된다면 방어적 복사를 이용하여 전달해야 한다.
public final class ImmutableClass {
    /*
    * Integer 와 String 은 immutable 객체로
    * 값을 변경하는 Setter 가 없어서 값이 변하지 않는다.
    * */
    private final Integer immutableField1;
    private final String immutableField2;
    private final Date mutableField;

    private ImmutableClass(Integer immutableField1, String immutableField2, Date mutableField){
        this.immutableField1 = immutableField1;
        this.immutableField2 = immutableField2;
        this.mutableField = new Date(mutableField.getTime());
    }

    public static ImmutableClass createImmutableClass(Integer immutableField1, String immutableField2, Date mutableField){
        return new ImmutableClass(immutableField1,immutableField2,mutableField);
    }

    public Integer getImmutableField1() {
        return immutableField1;
    }

    public String getImmutableField2() {
        return immutableField2;
    }

    /*
    * Date 는 가변 객체로 인스턴스 변수의 참조를 return 하지 않는다.
    * 대신에 new 예약어를 사용해서 방어적복사를 수행한다.
    * */
    public Date getMutableField() {
        return new Date(mutableField.getTime());
    }

    @Override
    public String toString() {
        return "immutableField1 = " + immutableField1 + ", immutableField2 = " + immutableField2 + ", mutableField = " + mutableField;
    }
}

5. 장점

  • 쓰레드에 안전하여 멀티 쓰레드 환경에서 동기화를 고려하지 않아도 된다.
  • 불변객체를 필드로 사용할 때 방어적 복사가 필요없다.
  • 불변객체는 내부상태가 변경되지 않으므로, Map, Key 나 Set과 같은 요소로 사용하기에 적합하다.
  • 불변객체를 한번 메모리에 할당하게 되면 같은 객체를 계속 호출하여도, 새롭게 할당하지 않아도 되므로 GC의 성능을 높힐 수 있다.

6. 단점

  • 생성할 때 초기값이 아닌, 새로운 값을 입력하려면 새 객체를 만들어야한다.
  • 자원의 소모가 많아진다.
  • 코드의 재사용성이 떨어진다.

 

 

 

 

 

https://yeon-kr.tistory.com/162#:~:text=%ED%95%98%EC%A7%80%EB%A7%8C%20%EB%8B%B9%EC%97%B0%ED%9E%88%20%EB%B6%88%EB%B3%80%20%EA%B0%9D%EC%B2%B4%EC%9D%98,%EC%9D%B4%20%EB%96%A8%EC%96%B4%EC%A7%84%EB%8B%A4%EA%B3%A0%20%EB%A7%90%ED%95%A0%20%EC%88%98%20%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4.

 

Java 불변 객체 - Immutable Object

1. 서론 자바의 객체를 불변 객체로서 보호하는 방법입니다. 2. 불변 객체란 (Immutable Object) 객체가 불변하다는 것은 생성된 이후에 변하지 않는 것을 의미합니다. 아마도 자바 언어를 처음 배울

yeon-kr.tistory.com

https://velog.io/@bey1548/%EB%B6%88%EB%B3%80-%EA%B0%9D%EC%B2%B4-%EB%B0%8F-final%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0

 

불변 객체 및 final을 사용하는 이유

불변 객체(Immutable Object)란 객체 생성 이후 내부의 상태가 변하지 않는 객체이다.read-only 메소드만을 제공하며 객체의 내부 상태를 제공하는 메소드를 제공하지 않거나 제공하는 경우 방어적 복

velog.io

https://dev-cool.tistory.com/23

 

불변객체(Immutable Object)를 사용해야하는 이유

1. 불변객체(Immutable Object)란? 불변객체는 말그대로 변하지않는 객체로 객체가 생성된후 내부 상태가 변하지 않는 객체를 의미한다. 불변객체는 Setter 메소드를 제공하지 않으며, 내부상태를 제공

dev-cool.tistory.com

 

 

 

** 그냥 하루하루 개인 공부한 것을 끄적 거리는 공간입니다.

이곳 저곳에서 구글링한 것과 강의 들은 내용이 정리가 되었습니다.

그림들은 그림밑에 출처표시를 해놓았습니다.

문제가 될시 말씀해주시면 해당 부분은 삭제 하도록하겠습니다. **

반응형

'public void static main() > Book' 카테고리의 다른 글

[Effective Java] 아이템 18  (0) 2023.01.24
[Effective Java] 아이템 5  (0) 2023.01.24
[Effective Java] 아이템 15  (0) 2023.01.18
[Effective Java] 아이템 13  (0) 2023.01.10
[Effective Java] 아이템 10 ~ 아이템 11  (0) 2023.01.10

댓글