Java, Immutable - 공유 참조의 사이드이펙트
사이드이펙트(Side Effect)는 작업한 영역을 벗어나 다른 곳에서 변화가 일어난 것을 말한다.
다음 이전 글에서 발생한 참조형 변수 공유 코드를 다시 살펴본다.
객체 생성 Rectangle.java
public Rectangle {
private int width;
private int height;
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
@Override
public String toString() {
return "Rectangle width=" +
width +
", height=" +
height;
}
}
참조형 복사 보기
public ReferenceMain {
public static void main(String[] args) {
Rectangle rect1 = new Rectangle(100,30);
Rectangle rect2 = rect1;
System.out.println(rect1);
System.out.println(rect2);
rect2.setWidth(200);
System.out.println("Ractangle rect2 Changed 200");
System.out.println(rect1);
System.out.println(rect2);
}
}
참조형 복사 출력 결과
Rectangle width=100, height=30
Rectangle width=100, height=30
Rectangle rect2 width Changed 200
Rectangle width=200, height=30
Rectangle width=200, height=30
Side Effect
- 개발자가 rect2 객체의 변수 값을 변경할 의도로 작성한다.
- 그렇지만 rect2 객체는 rect1 객체 인스턴스 주소 값과 동일하다. 그래서 rect1 객체 변수도 함께 값이 변경된다.
사이드 이펙트는 부정적인 의미로 사용되고, 프로그램의 변경이 의도치 않은 다른 부분까지 영향을 받아 발생한다. 사이드 이펙트가 발생되면 디버깅이 어려워지며 코드의 안전성이 저하한다.
Rectangle 사이드 이펙트 해결방안
사이드 이펙트의 해결방안은 인스턴스의 같은 주소를 사용하지 않고 new 키워드로 새로운 인스턴스를 만들어 변수로 할당하는 방법이다.
참조형 복사 보기
public ReferenceMain {
public static void main(String[] args) {
Rectangle rect1 = new Rectangle(100,30);
Rectangle rect2 = new Rectangle(100,30);
System.out.println(rect1);
System.out.println(rect2);
rect2.setWidth(200);
System.out.println("Ractangle rect2 Changed 200");
System.out.println(rect1);
System.out.println(rect2);
}
}
참조형 복사 출력 결과
Rectangle width=100, height=30
Rectangle width=100, height=30
Rectangle rect2 width Changed 200
Rectangle width=100, height=30
Rectangle width=200, height=30
rect2 객체의 width 변수 값만 성공적으로 변경되고 rect1 객체의 width 변수에게는 영향을 주지 않는다.
공유 문제 정리
ract1 = ract2 객체 할당으로 인스턴스 공유가 가능하기에 문제가 발생되었고, 이러한 공유를 막으면 문제가 발생되지 않는다.
그리고 하나의 객체는 여러 변수로 할당하는 것을 막을 수 없다.
문제의 코드를 다시 살펴보도록 한다.
Rectangle rect1 = new Rectangle(100, 30);
Rectangle rect2 = rect1;
rect2 = rect1
코드를 작성하지 않도록 하여, 여러 변수가 하나의 참조 값을 공유되지 않으면 해결될 것으로 보인다. 하지만 자바 입장에서는 오류가 아닌 정상적인 문법으로 아무런 문제가 되지 않게 된다.
즉, 객체가 공유되도록 변수에 할당하는 것은 막을 수 없다.
개발자가 주의하여도 실수로 사이드이펙트가 발생되는 코드가 생겨나고, 이를 인지하지 못하면 큰 장애로 남게 된다.
ReferenceMain.java
public ReferenceMain {
public static void main(String[] args) {
Rectangle rect1 = new Rectangle(100,30);
Rectangle rect2 = rect1;
System.out.println(rect1);
System.out.println(rect2);
changeWidth(200);
System.out.println(rect1);
System.out.println(rect2);
}
private static void changeWidth(Rectangle rect, int width) {
System.out.println("Ractangle rect Changed: " + width);
rect.setWidth(width);
}
}
출력 결과
Rectangle width=100, height=30
Rectangle width=100, height=30
Rectangle rect width Changed: 200
Rectangle width=200, height=30
Rectangle width=200, height=30
복잡한 코드인 경우 사이드 이펙트가 발생하였는지 파악이 어렵다.