불변변수 (Immutable Variable)
불변성
- 지역변수는 변하지 않는다.
- 전역변수는 레퍼런스만 바뀐다.
가변성
함수에 전달한 변숫값 변경
def f = "Foo"
def func(obj) {
obj = "Bar"
}
println f
func(f)
println f
Foo
Foo
class Foo {
String str
}
def f = new Foo(str: "Foo")
def func(Foo obj) {
obj.str = "Bar"
}
println f.str
func(f)
println f.str
Foo
Bar
한빛증권 이메일 보내기 프로젝트

그루비로 작성한 계약 정보를 수정하는 예제
def getCustomerById(Integer customerId) {
Customer.allCustomers.findAll({ customer ->
customer.id == customerId
})
}
수정된 contract 출력 ( collect, each )
Customer.allCustomers.collect({ customer ->
customer.contract.enabled = false
customer.contract
}).each { contract ->
println("= contract : " + contract.begin_date.getTime() + " : " + contract.enabled)
}
[출력결과]
= contract : Sun Oct 02 19:40:00 KST 2016 : false
= contract : Sun Oct 02 19:40:00 KST 2016 : false
= contract : Sun Oct 02 19:40:00 KST 2016 : false
= contract : Sun Oct 02 19:40:00 KST 2016 : false
= contract : Sun Oct 02 19:40:00 KST 2016 : false
= contract : Sun Oct 02 19:40:00 KST 2016 : false
= contract : Sun Oct 02 19:40:00 KST 2016 : false
= contract : Sun Oct 02 19:40:00 KST 2016 : false
= contract : Sun Oct 02 19:40:00 KST 2016 : false
= contract : Sun Oct 02 19:40:00 KST 2016 : false
한빛증권 이메일 프로젝트
class Contact {
public final Integer contact_id;
public final String firstName;
public final String lastName;
public final String email;
public final Boolean enabled;
public Contact(Integer contact_id,
String firstName,
String lastName,
String email,
Boolean enabled) {
this.contact_id = contact_id;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.enabled = enabled;
}
public static void eachEnabledContact(Closure cls) {
Customer.allCustomers.findAll { customer ->
customer.enabled && customer.contract.enabled
}.each { customer ->
customer.contacts.each(cls)
}
}
public void sendEmail(String msg) {
println("--------------------------------------------------")
msg = String.format(msg, firstName, lastName)
println(msg)
}
}
def msg = "안녕하세요, %s %s 고객님\n" +
"금번 폐사가 새로 출시한 상품이 있어 연락드리게 되었습니다. 한번 사용해보시고 구매를 결정하셔\n" +
"도 되니 부담없이 02-2128-8731으로 전화주시면 안내해 드리겠습니다.\n" +
"감사합니다.\n" +
"고객님의 평생 파트너 ‘한빛증권’"
eachEnabledContact({ contact -> contact.sendEmail(msg)})
한빛증권 이메일 요구사항 변경
발신: 한빛증권 신상품 소개 <[email protected]>
수신: 김상민 <[email protected]>
제목: 신상품 안내
안녕하세요, 김창수 고객님
금번 폐사가 새로 출시한 상품이 있어 연락드리게 되었습니다. 한 번 사용해보시고 구매를 결정하
셔도 되니 부담 없이 02-2128-8731로 전화주시면 안내해 드리겠습니다.
감사합니다.
고객님의 평생 파트너 '한빛증권’
운영팀에 따르면 김창수씨는 김상민 → 김창수로 개명을 했는데, 이메일 본문엔 김창수로, 주소는
김상민 <[email protected]>으로 발송이 되었다는 말입니다.

- 동시성 (concurrency) 공유된 변수가 실제로 어느 시점에 어떤 상태라는 보장이 없음을 의미
- 해결책
- Customer.allCustomers 객체의 모든 접근을 동기화한다.
- 모든 접근을 synchronized 블록
- 병목현상이 발생할 있음
- Customer.allCustomers 리스트와 멤버를 변경할 수 없게 한다.
- 수정된 멤버를 가진 새로운 리스트를 생성해야되는 불편
불변성
- 데이터베이스의 트랜잭션과 동일한 개념 ( 변경전, 후만 남게 되기 때문 )
public static List<Customer> setContractForCustomerList(List<Integer> ids, Boolean status) {
Customer.allCustomers.collect { customer ->
if(ids.indexOf(customer.id) >= 0) {
new Customer(
customer.id,
customer.name,
customer.state,
customer.domain,
customer.enabled,
new Contract(
customer.contract.begin_date,
status
),
customer.contacts
)
} else {
customer
}
}
}
public static List<Customer> updateCustomerByIdList(List<Integer> ids, Closure cls) {
Customer.allCustomers.collect { customer ->
if(ids.indexOf(customer.id) >= 0) {
cls(customer)
} else {
customer
}
}
}
public static List<Customer> updateContact(Integer customer_id, Integer contact_id, Closure cls) {
updateCustomerByIdList([customer_id], { customer ->
new Customer(
customer.id,
customer.name,
customer.state,
customer.domain,
customer.enabled,
customer.contract,
customer.contacts.collect { contact ->
if(contact.contact_id == contact_id) {
cls(contact)
} else {
contact
}
}
)
})
}
public static List<Customer> updateContractForCustomerList(List<Integer> ids, Closure cls) {
updateCustomerByIdList(ids, { customer ->
new Customer(
customer.customer_id,
customer.name,
customer.state,
customer.domain,
customer.enabled,
cls(customer.contract),
customer.contacts
)
})
}
정리하기
- 불변변수의 장점
- 버그 추적이 쉬워짐 ( 특정 변수들이 불변이란 사실을 이미 알고 있으므로 )
- 함수 파라미터와 반환값에 대해 더욱 분명히 이해할 수 있음
- 불변변수의 단점
- 대규모의 코드 리팩토링을 수반하므로 단행하기가 만만치 않음