메인 컨텐츠로 가기

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

함수형 사고: 불변성

적은 변화로 Java 코드 함수 강화하기

Neal Ford, 소프트웨어 아키텍트, IBM
Neal Ford사진
Neal Ford는 글로벌 IT 컨설팅 업체인 ThoughtWorks의 소프트웨어 아키텍트이자 Meme Wrangler이다. 애플리케이션, 교육용 자료, 매거진 기사 및 비디오/DVD 프리젠테이션을 설계 및 개발하며 다양한 기술과 관련된 서적의 저자 또는 편집자이기도 하다. 최근에 출판된 책으로는 The Productive Programmer가 있다. 대규모 엔터프라이즈 애플리케이션의 설계 및 빌드에 많은 관심을 가지고 있는 그는 전세계의 개발자 컨퍼런스에서 국제적으로 인정 받고 있는 연사로도 활동하고 있다. 그의 웹 사이트를 살펴보자.

요약:  불변성은 함수형 프로그래밍의 빌딩 블록 중 하나입니다. 이 함수형 사고 기사는 Java® 언어에서 불변성의 많은 측면에 대해 논의하고 기존 스타일과 더 새로운 스타일 모두에서 불변 Java 클래스를 작성하는 방법을 보여줍니다. 이는 또한 Groovy로 불변 클래스를 작성하는 두 가지 방법을 알려주어 Java 구현 방식의 골치거리를 많이 없애줍니다. 독자는 마지막으로 이 추상이 적절한 시점을 학습할 것입니다.

이 연재 자세히 보기

기사 게재일:  2011 년 11 월 01 일
난이도: 중급 원문:  보기 PDF:  A4 and Letter (44KB | 12 pages)Get Adobe® Reader®
페이지뷰:  1709 회
의견:  


객체 지향 프로그래밍을 사용하면 이동하는 부분을 요약하여 코드를 이해할 수 있게 된다. 함수형 프로그래밍을 사용하면 이동하는 부분을 최소화하여 코드를 이해할 수 있게 된다.
— Twitter로 Working with Legacy Code의 저자인 Michael Feathers

이 시리즈의 정보

이 시리즈는 독자의 관점을 함수형 사고방식으로 새로운 방향을 지정하여, 새로운 방식에서 공통적인 문제점을 살펴보고 일상적인 코딩을 개선하는 방법을 찾는 데 도움을 주는 것을 목표로 한다. 이는 함수형 프로그래밍 개념, Java 언어 내에서 함수형 프로그래밍을 허용하는 프레임워크, JVM에서 실행하는 함수형 프로그래밍 언어 및 언어 설계의 일부 미래 성향의 방향을 살펴본다. 이 시리즈는 Java 및 그 추상이 작업하는 방법을 알지만, 함수형 언어를 사용한 경험이 적거나 전혀 없는 개발자들에 적합하도록 맞춰져 있다.

이 기사에서 필자는 함수형 프로그래밍의 빌딩 블록 중 하나인 불변성을 논의한다. 불변 오브젝트의 상태는 구성 이후에 변경할 수 없다. 다시 말해서, 생성자는 오브젝트의 상태를 변형시킬 수 있는 유일한 방법이다. 불변 오브젝트를 변경하려 한다면 수행하지 않는다 — 변경된 값으로 새 오브젝트를 작성하고 참조를 이에 대해 가리킨다. (String은 Java 언어의 핵심으로 제작된 불변 클래스의 고전적인 예제이다.) 불변성은 변경하는 부분을 최소화하는 목표에 일치하기 때문에 함수형 프로그래밍의 핵심이며, 이러한 부분에 대해 추론하기에 더 간편하게 된다.

Java에서 불변 클래스 구현하기

Java, Ruby, Perl, Groovy 및 C# 등의 현대적인 객체 지향 언어는 제어된 방식으로 상태를 간단히 수정하기 위해 편리한 메커니즘을 제작했다. 하지만, 상태는 계산에 매우 근본적이므로 누설되는 곳을 예측할 수 없다. 예를 들어, 고성능의 올바른 멀티스레드형 코드를 쓰는 것은 무수한 변동성 메커니즘으로 인해 객체 지향 언어에서는 어려운 일이다. Java가 상태를 조작하기 위해 최적화되기 때문에 불변성의 혜택을 누리기 위해 이러한 일부 메커니즘을 중심으로 작업해야 한다. 하지만 몇 가지 함정을 방지하는 것을 인식하면 Java로 된 불변 클래스를 빌드하는 것이 더 간편해진다.

불변 클래스 정의하기

Java 클래스가 불변이 되게 하려면 다음을 수행해야 한다.

  • 모든 필드를 final로 만든다.

    필드를 Java에서 final로 정의할 때, 선언 시점 또는 생성자에서 이를 초기화해야 한다. IDE가 독자가 선언 사이트에서 이를 초기화하지 않았다고 표시해도 당황할 필요는 없다. 독자가 생성자에서 적절한 코드를 쓸 때 제정신으로 돌아왔음을 인식할 것이다.

  • 클래스를 final로 만든다. 그러므로 이는 오버라이드될 수 없다.

    클래스가 오버라이드될 수 있으면, 메소드의 작동이 오버라이드될 수 있으며, 그러므로 가장 안전한 방안은 서브 클래싱을 허용하지 않는 것이다. 이는 Java의 String 클래스가 사용한 전략임을 참고한다.

  • 인수 없는(no-argument) 생성자를 제공하지 않는다.

    불변 오브젝트가 있으면, 생성자에 포함할 상태가 무엇이든지 설정해야 한다. 설정된 상태가 없으면, 왜 오브젝트를 보유하는가? Stateless 클래스에서 정적 메소드도 작동할 것이다. 그러므로 불변 클래스에 대해 인수 없는 생성자는 절대 보유해서는 안 된다. 어떠한 이유로 이를 요구하는 프레임워크를 사용하는 중인 경우, private 인수 없는 생성자(이는 리플렉션을 통해 시각화됨)를 제공하여 충족될 수 있는지 확인한다.

    인수 없는 생성자의 부재는 기본 생성자를 강력히 주장하는 JavaBeans 표준을 위반하는 것을 참고한다. 하지만 JavaBeans는 setXXX 메소드가 작동하는 방법으로 인해 어쨌든 불변이 될 수 없다.

  • 하나 이상의 생성자를 제공한다.

    인수 없는 생성자를 제공하지 않았다면 이는 오브젝트로 일부 상태를 추가하는 마지막 기회이다!

  • 생성자 외에 어떤 변형 메소드도 제공하지 않도록 한다.

    일반적인 JavaBeans에 영향을 받은 setXXX 메소드를 방지해야 할 뿐만 아니라 불변 오브젝트 참조를 리턴하지 않도록 주의해야 한다. 오브젝트 참조가 final이라는 사실은 가리키는 것을 변경할 수 없음을 의미하지 않는다. 그러므로 getXXX 메소드에서 리턴한 모든 오브젝트 참조를 방어용으로 복사하도록 한다.

"기존" 불변 클래스

이전 요구사항에 부합하는 불변 클래스는 다음 목록 1에 나타난다.


목록 1. Java에서 불변 Address 클래스

public final class Address {
    private final String name;
    private final List<String> streets;
    private final String city;
    private final String state;
    private final String zip;

    public Address(String name, List<String> streets, 
                   String city, String state, String zip) {
        this.name = name;
        this.streets = streets;
        this.city = city;
        this.state = state;
        this.zip = zip;
    }

    public String getName() {
        return name;
    }

    public List<String> getStreets() {
        return Collections.unmodifiableList(streets);
    }

    public String getCity() {
        return city;
    }

    public String getState() {
        return state;
    }

    public String getZip() {
        return zip;
    }
}

거리 목록의 방어용 사본을 만들기 위해 목록 1에서 Collections.unmodifiableList() 메소드의 사용을 참고하자. 배열 대신에 불변 목록을 작성하기 위해 항상 콜렉션을 사용해야 한다. 비록 배열을 방어용으로 복사할 수 있지만, 이로 인해 원하지 않는 일부 부작용이 나타난다. 다음 목록 2의 코드를 살펴보자.


목록 2. 콜렉션 대신에 배열을 사용하는 Customer 클래스

public class Customer {
    public final String name;
    private final Address[] address;

    public Customer(String name, Address[] address) {
        this.name = name;
        this.address = address;
    }

    public Address[] getAddress() {
        return address.clone();
    }
}

목록 2의 코드 관련 문제점은 다음 목록 3과 같이 호출에서 getAddress() 메소드로 돌아오는 복제된 배열과 관련하여 어느 것이나 시도할 때 명시한다.


목록 3. 정확하지만 직관적이지 않은 결과를 보여주는 테스트

public static List<String> streets(String... streets) {
    return asList(streets);
}

public static Address address(List<String> streets, 
                              String city, String state, String zip) {
    return new Address(streets, city, state, zip);
}

@Test public void immutability_of_array_references_issue() {
    Address [] addresses = new Address[] {
        address(streets("201 E Washington Ave", "Ste 600"), "Chicago", "IL", "60601")};
    Customer c = new Customer("ACME", addresses);
    assertEquals(c.getAddress()[0].city, addresses[0].city);
    Address newAddress = new Address(
        streets("HackerzRulz Ln"), "Hackerville", "LA", "00000");
    // doesn't work, but fails invisibly
    c.getAddress()[0] = newAddress;

    // illustration that the above unable to change to Customer's address
    assertNotSame(c.getAddress()[0].city, newAddress.city);
    assertSame(c.getAddress()[0].city, addresses[0].city);
    assertEquals(c.getAddress()[0].city, addresses[0].city);
}

복제된 배열을 리턴할 때, 기본 배열을 보호한다 — 하지만 일상적인 배열과 같아 보이는 배열을 돌려주는 중이며, 이는 배열의 컨텐츠를 변경할 수 있음을 의미한다. (배열을 보유하는 변수가 final인 경우에도, 이는 배열의 컨텐츠가 아니라 배열 참조 그 자체에만 적용된다.) Collections.unmodifiableList()(및 다른 유형의 Collections에서 메소드의 제품군)를 사용하면 사용 가능한 변형 메소드가 없는 오브젝트 참조를 수신한다.

더 깔끔한 불변 클래스

독자는 불변 필드를 private로 만들어야 한다는 것도 자주 접하게 된다. 필자는 다르지만 명확한 시각을 가지고 있는 사람이 뿌리깊은 가정을 명확히 설명하는 것을 들었으므로 이러한 감상에 동의하지 않는다. Michael Fogus의 Clojure 창시자 Rich Hickey와의 인터뷰에서(참고자료 참조) Hickey는 Clojure의 많은 핵심적인 부분의 데이터 숨기기 요약의 부재에 대해 논한다. Clojure의 이러한 면은 필자가 상태 기반 사고에 매우 열중하고 있기 때문에 항상 필자를 괴롭힌다. 하지만 필자는 노출된 필드가 불변인 경우 이에 대해 독자가 걱정할 필요가 없다는 것을 인식했다. 요약을 위해 우리가 사용하는 많은 보호 장치들은 정말 변형을 방지하는 것에 불과하다. 이러한 두 가지 개념을 분리하여 잘라내면, 더 깔끔한 Java 구현 방식이 나타난다.

다음 목록 4의 Address 클래스의 버전을 고려하자.


목록 4. public 불변 필드가 있는 Address 클래스

public final class Address {
    private final List<String> streets;
    public final String city;
    public final String state;
    public final String zip;

    public Address(List<String> streets, String city, String state, String zip) {
        this.streets = streets;
        this.city = city;
        this.state = state;
        this.zip = zip;
    }

    public final List<String> getStreets() {
        return Collections.unmodifiableList(streets);
    }
}

불변 필드에 대해 공용 getXXX() 메소드를 선언하면 기본적인 표현을 숨기려고 하는 경우에만 혜택을 누린다. 하지만, 이는 이러한 변경을 사소하게 찾을 수 있는 리팩토링 IDE의 시기에 모호한 혜택이다. 필드를 public과 불변으로 만들어 우발적으로 이를 변경하는 것에 대해 걱정하지 않고 코드에서 이에 직접 액세스할 수 있다.

콜렉션을 내부적으로 변형할 필요가 전혀 없는 경우, 생성자에서 임베드된 목록을 unmodifiableList로 캐스트할 수 있으며, 이를 통해 streets 필드를 public으로 만들고 getStreets() 메소드에 대한 필요를 없앨 수 있다. 필자가 다음 예제에서 설명하는 대로, Groovy를 사용하면 getStreets()와 같은 보호 액세스 메소드를 작성하여 필드로 나타나도록 할 수 있다.

불변 public 필드를 사용하는 것은 화난 원숭이에 귀를 기울인다면 처음에는 부자연스럽게 보이겠지만 이러한 차이점이야말로 혜택이다. 즉, 독자는 Java에서 불변 유형을 처리하는 데 익숙하지 않고 이는 다음 목록 5에 시연한 대로 새 유형과 같이 보인다.


목록 5. Address 클래스의 유닛 테스트

@Test (expected = UnsupportedOperationException.class)
public void address_access_to_fields_but_enforces_immutability() {
    Address a = new Address(
        streets("201 E Randolph St", "Ste 25"), "Chicago", "IL", "60601");
    assertEquals("Chicago", a.city);
    assertEquals("IL", a.state);
    assertEquals("60601", a.zip);
    assertEquals("201 E Randolph St", a.getStreets().get(0));
    assertEquals("Ste 25", a.getStreets().get(1));
    // compiler disallows
    //a.city = "New York";
    a.getStreets().clear();
}

화난 원숭이

필자는 Dave Thomas로부터 이 이야기를 처음 들었고, 나중에 필자의 저서인 The Productive Programmer에 나온다(참고자료 참조). 필자는 이 이야기가 진실인지 알지 못하지만(약간 조사해봤음에도 불구하고) 누가 이에 대해 신경을 쓰겠는가? 이는 요점을 훌륭하게 표현한다.

1960년대에는 행동주의 과학자들은 방안에 다섯 마리의 원숭이를 모아놓고 계단식 사다리를 놓고 천장에서부터 바나나 한 더미를 걸어놓는 실험을 수행했다. 원숭이들은 사다리를 타고 올라가서 바나나를 먹을 수 있다는 것을 빠르게 알아냈다. 그 다음에 한 원숭이가 계단식 사다리에 다가갈 때마다 과학자들이 온 방안에 얼음 냉수를 끼얹었다. 곧 어느 원숭이도 사다리 근처에 가지 않을 것이다. 그러면 과학자들은 물에 흠뻑 젖은 원숭이 중 하나를 아직 실험의 주제가 되지 않은 새로운 원숭이로 바꾸었다. 그 원숭이가 사다리에 일직선으로 나아갈 때, 모든 다른 원숭이들이 그를 때려눕혔다. 그는 다른 원숭이들이 때리는지 알지 못했지만, 사다리 근처에 가지 말라는 것을 빠르게 학습했다. 과학자들은 서서히 원래 원숭이들을 절대 냉수로 흠뻑 젖지는 않았지만 사다리에 접근한 원숭이를 공격한 원숭이 그룹이 있을 때까지 새로운 원숭이로 바꾸었다.

요점이 무엇인가? 소프트웨어 프로젝트에서 "이는 우리가 지금까지 한 방법이기" 때문에 많은 사례가 존재한다.

public 불변 필드에 접근하는 것은 getXXX() 호출의 시리즈의 시각적 오버헤드를 방지한다. 컴파일러는 원시 언어 중 하나를 지정하도록 허용하지 않을 것이라는 점도 주목하자. 그리고 street 콜렉션에서 변형 메소드를 호출하려고 노력하는 경우, UnsupportedOperationException이 나타날 것이다(테스트의 맨 위에 포착됨). 코드의 이 스타일을 사용하면 이는 불변 클래스임을 알려주는 강력한 시각적 표시기이다.

부작용

더 깔끔한 구문에서 발생 가능한 불이익은 이러한 새로운 관용어를 배우는 면에서 나오는 노력이다. 하지만 필자는 이를 가치있다고 생각한다. 명백한 스타일적 차이점으로 인해 클래스를 작성할 때 불변성에 대해 생각하도록 권장하고, 불필요한 중복된 코드를 줄인다. 하지만 Java에서 이 코딩 스타일에 일부 부작용이 있다(이는 공평하게 불변성을 직접 수용하도록 절대 제작되지 않았음).

  • Glenn Vanderburg가 필자에게 지적한 것처럼, 가장 큰 부작용은 스타일이 Bertrand Meyer(Eiffel 프로그래밍 언어의 창시자)가 Uniform Access Principle이라고 부르는 것을 위반하는 것이다. 즉, 이는 "모듈로 제공되는 모든 서비스가 균등한 표기법을 통해 사용 가능해야 하며, 이는 스토리지로 구현되었는지 아니면 계산으로 구현되었는지 여부에 따라 배반하지 않는다."이다. 다시 말해서, 필드에 액세스하는 것은 값을 리턴하는 필드 또는 메소드인지 여부를 노출하지 않아야 한다. Address 클래스의 getStreets() 메소드는 다른 필드와 균등하지 않다. 이 문제는 정말로 Java에서 해결될 수 없다. 이는 불변성을 사용하는 방식으로 다른 일부 JVM 언어로 해결된다.
  • 리플렉션에 크게 의존하는 일부 프레임워크는 기본 생성자가 필요하기 때문에 이 관용어로 작업하지 않을 것이다.
  • 오래된 오브젝트를 변형하는 것이 아니라 새 오브젝트를 작성하기 때문에, 업데이트가 많은 시스템은 가비지 콜렉션으로 비효율성을 야기할 수 있다. Clojure와 같은 언어는 불변 참조로 더 효율적이 되는 내장 기능이 있으며, 이는 이러한 언어에서 기본값이다.

Groovy에서 불변성

Groovy로 된 Address 클래스의 public 불변 필드 버전을 빌드하면 다음 목록 6과 같이 훌륭하고 깔끔한 구현 방식이 나타난다.


목록 6. Groovy로 된 불변 Address 클래스

class Address {
    def public final List<String> streets;
    def public final city;
    def public final state;
    def public final zip;

    def Address(streets, city, state, zip) {
        this.streets = streets;
        this.city = city;
        this.state = state;
        this.zip = zip;
    }

    def getStreets() {
        Collections.unmodifiableList(streets);
    }
}

평소대로 Groovy는 Java보다 중복된 코드를 적게 요청한다 — 그리고 다른 혜택도 있다. Groovy를 통해 익숙한 get/set 구문을 사용하여 특성을 작성하도록 허용하기 때문에, 오브젝트 참조에 진정으로 보호된 특성을 작성할 수 있다. 다음 목록 7의 유닛 테스트를 고려하자.


목록 7. Groovy로 균등한 액세스를 보여주는 유닛 테스트

class AddressTest {
    @Test (expected = ReadOnlyPropertyException.class)
    void address_primitives_immutability() {
        Address a = new Address(
            ["201 E Randolph St", "25th Floor"], "Chicago", "IL", "60601")
        assertEquals "Chicago", a.city
        a.city = "New York"
    }

    @Test (expected=UnsupportedOperationException.class)
    void address_list_references() {
        Address a = new Address(
            ["201 E Randolph St", "25th Floor"], "Chicago", "IL", "60601")
        assertEquals "201 E Randolph St", a.streets[0]
        assertEquals "25th Floor", a.streets[1]
        a.streets[0] = "404 W Randoph St"
    }
}

두 경우 모두 불변성 계약 위반으로 인해 예외가 발생할 때 테스트가 종료된다는 것을 참고한다. 하지만, 목록 7에서 streets 특성은 원시 언어와 같이 보이지만 getStreets() 메소드를 통해 실제로 보호된다.

Groovy의 @Immutable 어노테이션

이 시리즈의 기본적인 주장 중 하나는 함수형 언어가 낮은 레벨 세부사항을 더 많이 처리해야 한다는 것이다. 훌륭한 시연은 Groovy 버전 1.7에 추가된 @Immutable 어노테이션이며, 이는 목록 6의 모든 코딩을 미해결로 만든다. 다음 목록 8은 이 어노테이션을 사용하는 Client 클래스를 보여준다.


목록 8. 불변 Client 클래스

@Immutable
class Client {
    String name, city, state, zip
    String[] streets
}

@Immutable 어노테이션의 사용으로 인해 이 클래스에 다음 특성이 있다.

  • 이는 final이다.
  • 특성은 get 메소드를 합성하여 private 지원 필드를 자동으로 보유한다.
  • 특성을 업데이트하는 시도로 인해 ReadOnlyPropertyException이 나타난다.
  • Groovy는 서수 및 맵 기반 생성자 둘 다 작성한다.
  • 콜렉션 클래스는 적절한 랩퍼로 랩핑되고, 배열(그리고 다른 복제 가능한 오브젝트)은 복제된다.
  • 기본 equals, hashcodetoString 메소드는 자동으로 생성된다.

이 어노테이션은 투자에 부합하는 많은 가치를 제공한다! 이는 또한 다음 목록 9와 같이 예상한 대로 작동한다.


목록 9. 예상된 케이스를 제대로 처리하는 @Immutable 어노테이션

@Test (expected = ReadOnlyPropertyException)
void client_object_references_protected() {
    def c = new Client([streets: ["201 E Randolph St", "Ste 25"]])
    c.streets = new ArrayList();
}

@Test (expected = UnsupportedOperationException)
void client_reference_contents_protected() {
    def c = new Client ([streets: ["201 E Randolph St", "Ste 25"]])
    c.streets[0] = "525 Broadway St"
}

@Test
void equality() {
    def d = new Client(
        [name: "ACME", city:"Chicago", state:"IL",
         zip:"60601",
         streets: ["201 E Randolph St", "Ste 25"]])
    def c = new Client(
            [name: "ACME", city:"Chicago", state:"IL",
             zip:"60601",
             streets: ["201 E Randolph St", "Ste 25"]])
    assertEquals(c, d)
    assertEquals(c.hashCode(), d.hashCode())
    assertFalse(c.is(d))
}

오브젝트 참조를 대체하기 위해 시도하면 ReadOnlyPropertyException을 야기한다. 그리고 요약된 오브젝트 참조 중 하나가 가리키는 것을 변경하려고 시도하면 UnsupportedOperationException을 생성한다. 이는 또한 마지막 테스트와 같이 적절한 equalshashcode 메소드를 작성한다 — 오브젝트 컨텐츠는 동일하지만 동일한 참조를 가리키지는 않는다.

물론, Scala와 Clojure 둘 다 불변성을 지원하고 권장하며 이를 위한 정리 구문이 있다. 이에 대한 시사점은 향후 기사에서 나타날 것이다.


불변성의 혜택

불변성을 받아들이는 것은 함수형 프로그래머와 같이 생각하는 방법에서 중요한 사항이다. 비록 Java에서 불변 오브젝트를 빌드하면 선행 복잡도를 약간 더 요청하지만, 이 추상으로 강제된 다운스트림 간소화로 노력이 간편하게 상쇄된다.

불변 클래스는 Java에서 일반적인 걱정거리의 주체를 사라지게 만든다. 함수형 사고방식으로 전환하는 이점 중 하나는 테스트가 코드에서 변경이 발생하는지 확인하기 위해 존재하는 것에 대한 깨달음이다. 다시 말해서, 테스팅의 진짜 용도는 변형을 유효성 검증하는 것이다 — 그리고 변형이 많으면 많을수록 올바르게 되기 위해 더 많은 테스팅이 필요하다. 심각하게 변형을 제한하여 변경이 발생하는 장소를 격리하면, 발생하는 오류에 훨씬 더 적은 공간을 제작하고 테스트할 장소를 더 적게 보유한다. 변경이 구성에서만 발생하기 때문에, 불변 클래스는 유닛 테스트를 쓰기에 더 단순하게 만든다. 복사 생성자가 필요하지 않으며, clone() 메소드를 구현하는 것의 처절한 세부사항에 힘들게 노력할 필요가 없다. 불변 오브젝트는 Map 또는 Set 중 하나에서 키로 사용하기에 훌륭한 후보를 만든다. 이는 Java로 된 사전 콜렉션에서 키는 키로 사용되는 동안 값을 변경할 수 없으므로 불변 오브젝트는 훌륭한 키를 만든다.

불변 오브젝트는 자동으로 스레드로부터 안전하고 동기화 문제가 없다. 이는 또한 예외이기 때문에 알려지지 않거나 원하지 않는 상태에서 절대 존재할 수 없다. 모든 초기화가 구성 시점에 발생하기 때문에, 이는 Java에서 원자적이다. 오브젝트 인스턴스를 보유하기 전에 어느 예외나 발생한다. Joshua Bloch는 이 실패 원자성을 환기시킨다. 즉, 이는 한 번 오브젝트가 생성되면 불변성에 따라 성공 또는 실패가 영원히 해결된다(참고자료 참조).

마지막으로 불변 클래스의 최고의 특성 중 하나는 불변 클래스가 컴포지션 추상에 얼마나 잘 맞는지이다. 다음 기사에서 필자는 컴포지션과 함수형 사고 영역에서 이 점이 왜 중요한지 조사하기 시작할 것이다.


참고자료

교육

  • The Productive Programmer(Neal Ford 저, O'Reilly Media, 2008년): 코딩 효율성을 개선하는 데 도움을 주는 도구와 연습을 논의하는 Neal Ford의 최신 저서이다.

  • Clojure: Clojure는 JVM에서 실행하는 현대식의 함수형 Lisp이다.

  • Rich Hickey Q&A: Michael Fogus는 Clojure 창시자 Rich Hickey를 인터뷰한다.

  • Stuart Halloway on Clojure: 이 developerWorks 팟캐스트에서 Clojure에 대해 자세히 배워보자.

  • Scala: Scala는 JVM에서 현대식의 함수형 언어이다.

  • The busy Java developer's guide to Scala: Ted Neward의 이 developerWorks 시리즈에서 Scala에 대해 더 자세히 학습해보자.

  • Effective Java, 2d ed.(Joshua Bloch, Addison Wesley, 2008년): 실패 원자성에 대해 자세히 읽어보자.

  • 기술 서점에서 다양한 기술 주제와 관련된 서적을 살펴보자.

  • developerWorks Java 기술 영역: Java 프로그래밍과 관련된 모든 주제를 다루는 여러 편의 기사를 찾아보자.

제품 및 기술

토론

  • developerWorks 커뮤니티에 참여하자. 개발자가 이끌고 있는 블로그, 포럼, 그룹 및 Wiki를 살펴보면서 다른 developerWorks 사용자와 의견을 나눌 수 있다.

필자소개

Neal Ford사진

Neal Ford는 글로벌 IT 컨설팅 업체인 ThoughtWorks의 소프트웨어 아키텍트이자 Meme Wrangler이다. 애플리케이션, 교육용 자료, 매거진 기사 및 비디오/DVD 프리젠테이션을 설계 및 개발하며 다양한 기술과 관련된 서적의 저자 또는 편집자이기도 하다. 최근에 출판된 책으로는 The Productive Programmer가 있다. 대규모 엔터프라이즈 애플리케이션의 설계 및 빌드에 많은 관심을 가지고 있는 그는 전세계의 개발자 컨퍼런스에서 국제적으로 인정 받고 있는 연사로도 활동하고 있다. 그의 웹 사이트를 살펴보자.

잘못된 도움말 신고

부정사용 신고

감사합니다. 이 항목은 운영자가 관심을 표시했습니다.


잘못된 도움말 신고

부정사용 신고

제출실패 신고. 나중에 다시 실행해주세요.


디벨로퍼웍스 로그인


IBM ID가 필요하세요?
IBM ID를 잊으셨습니까?


비밀번호를 잊으셨습니까?
비밀번호 변경

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

화면상에 보여지는 닉네임을 정하세요.

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

3개의 &이나 대쉬를 포함해주시고 31글자내로 제한해주세요.


developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


아티클 순위

의견

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=20
Zone=자바
ArticleID=768752
ArticleTitle=함수형 사고: 불변성
publish-date=11012011

태그

Help
검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오.

태그를 더 많이 보거나 적게 보기 위해 슬라이더 막대를 사용하십시오.

인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다.

내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.

검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오. 인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다. 내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.