Skip to content

Latest commit

 

History

History
122 lines (79 loc) · 5.78 KB

File metadata and controls

122 lines (79 loc) · 5.78 KB

불편객체

기본형과 참조형의 공유

자바는 항상 값을 복사해서 새로운 변수에 대입힌다. 또한 자바의 데이터 타입을 크게 보면 **기본형(Primitive Type)**과 **참조형(Reference Type)**으로 나눌 수 있다.

  • 기본형 : 하나의 값을 여러 변수에 절대로 공유하지 않는다.
스크린샷 2024-04-16 오후 6 49 30
  • 참조형 : 하나의 객체를 참조값을 통해 여러 변수에서 공유할 수 있다.
스크린샷 2024-04-16 오후 6 50 02

공유 참조와 사이드 이펙트

사이드 이펙트(Side Effect)란 프로그래밍에서 어떤 계산이 주된 작업 외에 추가적인 부수 효과를 일으키는 것을 말한다. 주로 공유 참조된 값을 변경할 때 발생되는데 아래와 같은 경우이다.

public static void main(String[] args){
        ClassA a=enw ClassA("서울");
        ClassA b=classA;

        b.setValue("부산"); // -> 사이드 이펙트 발생
}
스크린샷 2024-04-16 오후 6 50 24

외 결과는 a 와 b 의 값에 같이 영향을 주어 a b 모두 부산이라는 결과가 출력된다.

이렇게 주된 작업 외에 추가적으로 부수 효과를 일으키는 것을 사이드 이펙트라 한다. 프로그래밍에서 사이드 이펙트는 부통 부정적인 의미로 사용되는데, 사이드 이펙트는 프로그램의 특정 부분에서 발생한 변경이 의도치 않게 다른 부분에 영향을 미치는 경우에 발생한다. 이로 인해 디버깅이 어려워지고 코드의 안정성이 저하될 수 있다.

스크린샷 2024-04-16 오후 6 50 50

사이드 이펙트 해결방안

  1. 서로 다른 인스턴스를 참조하면 된다.
ClassA a = new ClassA("서울");
ClassA b = new ClassA("부산");
  1. 불변객체를 활용한다.
public classA{
    String final value;
    
    ClassA ClassA(String value){
        this.value = value;
    }
    
    public String getValue(){
        return this.value;    
    }
}

사이드 이펙트의 근본적인 원인은 값의 공유가 아닌 공유된 값이 변경되었기 때문에 발생한다. 그럼 변경을 하지 못하게 final을 사용하여 변수 값의 변경을 막거나 set()메소드를 없애 변경을 막으면 된다.

  • 불변이라는 단순한 제약을 사용해서 사이드 이펙트라는 큰 문제를 막을 수 있다.
    • 객체의공유 참조는 막을 수 없다. 그래서 객체의 값을 변경하면 다른 곳에서 참조하는 변수의 값도 함께 변경되는 사이드 이펙트가 발생한다. 사이드 이펙트가 발생하면 안되는 상황이라면 불변 객체를 만들어서 사용하면 된다.
    • 불변 객체는 값을 변경할 수 없다. 따라서 불변 객채의 값을 변경하고 싶다면 변경하고 싶은 값으로 새로운 불견 객체를 생성해야 한다. 이렇게 하면 기존 변수들이 참조하는 값에 영향을 주지 않는다.

만약 공유된 변수만 값을 변경하고 싶다면 withValue()메서드를 만들면 된다.

public ClassA withValue(String newValue){
    return new ClassA(newValue) 
}

이렇게 하면 원본을 변경하지 않고 값을 변경할 수 있다.

주의

ClassA a = new ClassA("서울");
a.withValue("부산"); // 반환값을 받아야 값이 수정된다(자주 있는 실수)

System.out.println("a = " + a.getValue);

위처럼 값을 변경하고 변경된 값을 받지 않으면 원본이 바뀌지 않으니까 값이 바뀌지 않는다.

ClassA a = new ClassA("서울");
a = a.withValue("부산");// 이렇게 바꿔줘야된다.

System.out.println("a = " + a.getValue);

withXxx() 메서드는 불변 객체에서 값을 변경하는 경우 관례처럼 사용된다. 원본 객체의 상태가 그대로 유지됨을 강조하면서 변경사항을 새 복사본에 포함하는 과정을 간결하게 표현할 수 있다. 또한 이는 Coffe with Sugar 같이 설탕을 커피에 추가하는거처럼 원래의 상태를 새롭게 변형한다는 것을 의미한다.

  • set메서드 : 내부 값을 변경할때 사용
  • with메서드 : 기존값을 유지하면서 새로운 값을 반환할 때 사용한다.(주로 불변객체에 사용)

참고로 String, Integer, LocalDate 등 수 많은 클래스가 불변으로 설계되어 있다.

🤔불변인 클래스(final)가 값을 변경하는 메서드를 가지고 있다고?

그러면 해당 메서드는 값을 반환한다고 인지하면 된다.

모든 클래스를 불변으로 만드는 것은 아니다.

우리가 만드는 대부분의 클래스는 값을 변경할 수 있게 만들어진다. 예를 들어서 회원 클래스의 경우 회원의 여러 속성을 변경할 수 있어야 한다. 가변 클래스가 더 일반적이고, 불변 클래스는 값을 변경하면 안되는 특별한 경우에 만들어서 사용한다고 생각하면 된다. 때로는 같은 기능을 하는 크래스를 하나는 불변으로 하나는 가변으로 각각 만드는 경우도 있다.

  • 클래스를 불변으로 설계하는 이유
    • 캐시 안정성
    • 멀티 쓰레드 안정성
    • 엔티티의 값 타입

이 외에도 많이 있다.