Backend/Java

[Effective Java : Item 59] 라이브러리를 익히고 사용하라

김세진 2024. 3. 20. 11:05
반응형

 

 

 

 

개요

 

static Random rnd = new Random();

static int random(int n) {
    return Math.abs(rnd.nextInt()) % n;
}

 

위 코드는 0부터 n보다 작은 정수 중 하나를 출력하는 간단한 메서드이다. 괜찮은 듯 보이지만 세 가지 문제점을 내포하고 있다.

 

1. n이 그리 크지 않은 2의 제곱수라면 같은 수열이 반복된다.

2. n이 2의 제곱수가 아니라면 몇몇 숫자가 평균적으로 더 자주 반환된다. n값이 크면 현상이 더 두드러진다.

3. 지정한 범위 바깥의 수가 종종 튀어나올 수 있다. rnd.nextInt()는 Integer.MIN_VALUE 를 반환할 수 있는데, 이를 Math.abs()로 절대값으로 반환하고자 하면 오버플로우가 발생하기 때문이다.

 

public static void main(String[] args) {
    int n = 2 * (Integer.MAX_VALUE / 3); // 2의 제곱수가 아닌 범위 설정
    int low = 0;
    for (int i = 0; i < 1000000; i++) {
        if (random(n) < n / 2) {
            low++;
        }
    }
    System.out.println(low); // 666,666의 근사치
}

 

위의 main 코드를 실행하면 500,000의 근사치가 아닌 666,666의 근사치를 출력하는 것을 볼 수 있다. 문제는 이뿐만이 아니다. 아래 코드에서 위에서 언급된 3번 문제를 살펴보자.

 

static Random rnd = new Random();

static int random(int n) {
    return Math.abs(Integer.MIN_VALUE) % n;
}

public static void main(String[] args) {
    System.out.println(random(1000000));
}

 

 

분명 Math.abs 로 절대값을 반환하도록 했지만, 음수가 반환된 것을 볼 수 있다.

 

위의 결함들을 해결하기 위해서는 의사난수 생성기, 정수론, 2의 보수 계산 등에 대한 조예가 깊어야 하나, 직접 해결할 필요는 없다. 이미 이와 관련한 문제를 해결한 메서드인 Random의 nextInt(int) 메서드가 추가되었기 때문이다. 해당 알고리즘에 능통한 개발자들이 설계 및 구현을 하고 여러 전문가들이 모여 해당 메서드가 잘 동작함을 검증했다. 약 20년 가까이 버그가 보고된 적이 없고, 설사 새로 보고되더라도 다음 릴리즈에서 수정되어 제공될 것이다.

 

한편, 자바 7부터는 Random 대신 ThreadLocalRandom 을 사용하는 것이 좋다. 더 고품질의 난수를 생성하고 성능 또한 더 좋다.

 

 


표준 라이브러리 사용 시 이점

 

1. 다른 개발자의 지식 및 경험 활용

위에서 보았다시피, 결함을 해결하기 위해 다방면의 지식을 습득해야 하지만 이미 다른 전문가나 개발자가 충분히 심사숙고하여 만들고 검증했기 때문에 그럴 필요가 없다. 또한 여러 문제에 부딪혔을 때 다른 개발자들의 앞선 경험을 활용할 수 있다.

 

2. 시간 절약

당연하게도 여러 지식을 습득하고 그것을 구현하는 데에는 많은 시간과 노력이 소모될 것이다. 하지만 내가 한 고민은 이미 그 방면의 전문가가 해결한 경우가 많을 것이다. 이렇듯 라이브러리를 사용하면 하부 공사보단 애플리케이션 기능 개발에 집중할 수 있다.

 

3. 지속적인 성능 개선

사용자가 많고, 업계 표준 벤치마크를 사용해 성능을 확인하기 때문에 표준 라이브러리 제작자들은 지속적인 개선을 하는 경우가 많다.

 

4. 기능 다각화

릴리즈가 거듭될 때마다 성능 뿐 아니라 신규 기능이 추가되는 경우도 많다.

 

5. 친숙한 코드

내가 작성한 코드가 다른 개발자들에게 낯익은 코드가 되어 가독성이 좋고 유지보수 및 활용하기 쉬운 코드가 된다.

 

 

 

기능을 직접 구현하는 경우

 

위의 이점에도 불구하고 기능을 직접 구현하는 경우가 있는데, 크게 두 가지 경우가 있을 것이다.

 

라이브러리에 그런 기능이 있는지 잘 모르는 경우

라이브러리가 방대하고 빠르게 발전하기 때문에 모두 익히기는 불가능하겠지만, java.lang, java.util, java.io와 그 하위 패키지들은 익숙해질 필요가 있다. 또한 컬렉션 프레임워크와 스트림 라이브러리, java.util.concurrent도 마찬가지이다.

 

 

라이브러리가 필요한 기능을 충분히 제공하지 못하는 경우

1. 표준 라이브러리를 충분히 탐색하여 사용하려고 시도해보자.

2. 원하는 기능이 없다면, 구글의 구아바(Guava)와 같이 고품질의 서드파티 라이브러리를 활용해보자.

3. 그러한 서드파티 라이브러리도 없다면 직접 구현하자.

 

 


정리

 

1. 아주 특별한 기능이 아닌 경우 누군가 라이브러리로 만들었을 가능성이 크다. 찾아서 활용하도록 하자.

2. 많은 주목을 받는 라이브러리는 보통 직접 작성하는 코드보다 품질이 좋고, 점차 개선될 가능성이 크다.

 

 

 

반응형