본문 바로가기
Dev/Effective Java

6. 아이템[6] - 불필요한 객체생성을 피하라

by VIPeveloper 2021. 2. 2.
반응형

1. 서론

포스팅에 대한 코드는 여기에서 보실 수 있습니다.

2. 본론

Q. 객체를 자주 생성함에도 불구하고 그 비용이 크다면 어떻게 해야할까?

A. 객체 하나를 재사용 하는 것이 나을 때가 많다.

 

1. 같은 값이지만 다른 레퍼런스를 가지는 경우

 

예시를 들어보자.

    @Test
    @DisplayName("a, b는 같다.")
    public void test(){
        String a = "java";
        String b = "java";
        assertSame(a,b);
    }

    @Test
    @DisplayName("a, b는 다르다.")
    public void test2(){
        String a = "java";
        String b = new String("java");
        assertNotSame(a,b);
    }

아래는 객체를 새로 생성하게 됨으로 새로운 주소로 할당된다. 따라서 스트링 자체는 같지만, 다른 주소를 참조하므로 다른 레퍼런스가 된다. 이런 불필요한 객체 생성 비용을 줄이자!

 

2. 재사용 빈도가 높고 생성비용이 비싼 경우

 

생성비용이 비싸다면 "캐싱"을 고려하자.

자주 쓰는 값이라면, static final 로 초기에 캐싱해놓고 재사용하는편이 좋다.

 

3. 같은 인스턴스를 대변하는 여러개의 인스턴스를 생성하지 않도록 하자.

    @DisplayName("keyset은 같은 Map을 바라본다")
    @Test
    public void test3(){
        Map<String, Object> test = new HashMap<>();
        test.put("hello","world");

        Set<String> res1 = test.keySet();
        Set<String> res2 = test.keySet();

        assertEquals(res1,res2);
    }

res1,res2는 동일한 인스턴스 test에서 나온 반환값이다. 굳이 한번 더 안만들어도 된다.

 

 

4. 오토박싱

불필요한 박싱/언박싱은 불필요한 메모리를 할당하거나, 재할당할 수 있다.

꼭 박싱 타입이 필요한 경우가 아니라면, 기본타입을 사용하도록 하자.

 

 

아래의 코드를 실행하면 불필요한 인스턴스가 추가 할때마다 생긴다고 한다. 따라서 시간도 많이 소요된다.

    @DisplayName("Long 객체를 무수히 많이 실행함")
    @Test
    public void test4(){
        Long sum = 0L;
        for(long i = 0;i<= Integer.MAX_VALUE;i++){
            sum += i;
        }
    }

5.505초가 걸린 것을 확인

 

반면,  아래의 코드는 불필요한 객체 생성을 방지한다.

    @DisplayName("불필요한 객체생성을 하지 않은 정상 코드")
    @Test
    public void test5(){
        long sum = 0L;
        for(long i = 0;i<= Integer.MAX_VALUE;i++){
            sum += i;
        }
    }

5배 이상 빨라진 코드

 

3. 결론

하지만, 이번 아이템을 객체 생성은 비싸니 피해야 한다로 이해하면 안된다.

가벼운 객체 생성 시에는 객체를 재사용 하는 것 보다는 객체를 새로 만드는 것이 효과적이다.

반응형