59. 라이브러리를 익히고 사용하라

✅ 핵심 요약

직접 구현하려 하지 말고, 이미 존재하는 고품질의 라이브러리를 우선 활용하자. 표준 라이브러리나 잘 검증된 서드파티 라이브러리는 안정성, 성능, 유지보수 측면에서 대부분의 경우 우월하다.

📚 필수 개념 요약

개념
설명

표준 라이브러리

자바 JDK에 기본 포함된 기능 모음 (java.util, java.lang, java.io 등)

서드파티 라이브러리

외부에서 배포되는 라이브러리 (예: Guava, Apache Commons)

Random

전통적인 의사난수 생성기. 멀티스레드 환경에서 성능 및 편향 이슈 존재

ThreadLocalRandom

Java 7+에서 도입된 빠르고 안전한 난수 생성기

transferTo

Java 9+에서 InputStream의 데이터를 다른 출력 스트림에 직접 복사하는 메서드


⚔️ Random vs ThreadLocalRandom

항목

Random

ThreadLocalRandom

버전

Java 1.0

Java 7 이후

쓰레드 안전성

멀티스레드 환경에서 성능 저하 발생

각 쓰레드에 독립된 인스턴스 제공 → 빠름

편향성

Math.abs(random.nextInt()) % n 사용 시 편향 발생

nextInt(n) 메서드로 정확한 균등 분포

사용 예

단일 스레드 기반, 간단한 작업

멀티스레드 or 고성능 필요 시 우선 사용


❌ 잘못된 무작위 수 생성 방식 (편향 발생 가능)

import java.util.Random;

public class WrongRandomExample {
    private static Random rnd = new Random();

    // 문제 있는 무작위 정수 생성 메서드
    public static int random(int n) {
        // 🔴 문제점 1: n이 2의 제곱수(예: 8, 16 등)면 특정 수열이 반복될 가능성 있음
        // 🔴 문제점 2: n이 2의 제곱수가 아니면 일부 숫자가 더 자주 생성됨 (분포 왜곡/편향 발생)
        // 🔴 문제점 3: Integer.MIN_VALUE는 Math.abs로 양수로 바꿔지지 않음 (그대로 음수 유지)
        return Math.abs(rnd.nextInt()) % n; // 문제의 핵심 라인
    }

    public static void main(String[] args) {
        int n = 2 * (Integer.MAX_VALUE / 3); // 매우 큰 정수 값 설정
        int low = 0;

        // 무작위 수 100만 개 생성 → 그중 절반 미만의 수가 얼마나 되는지 확인
        for (int i = 0; i < 1_000_000; i++) {
            if (random(n) < n / 2) {
                low++; // 하위 절반 범위에 해당하면 카운트
            }
        }

        // 이상적으로는 50만 개 전후가 나와야 하지만, 실제로는 60만 이상 출력됨 (편향)
        System.out.println("하위 절반 수: " + low);
    }
}

🔍 설명

  • Math.abs(rnd.nextInt()) % n은 직관적이지만 무작위성이 왜곡될 수 있는 매우 위험한 코드입니다.

  • 특히 Integer.MIN_VALUE는 절대값이 자기 자신이므로 음수 결과도 나올 수 있어 의도치 않은 동작이 발생합니다.


✅ 권장 방식: ThreadLocalRandom 사용 (Java 7+)

import java.util.concurrent.ThreadLocalRandom;

public class CorrectRandomExample {
    public static void main(String[] args) {
        // ✅ 0 이상 10 미만의 균등한 무작위 정수 생성
        int num = ThreadLocalRandom.current().nextInt(10);

        // 💡 내부적으로 분포 편향 없이 안전한 난수를 생성
        // 💡 멀티스레드 환경에서도 더 빠르고 효율적으로 동작함
        System.out.println("무작위 숫자: " + num);
    }
}

🔍 설명

  • ThreadLocalRandom은 Java 7부터 도입되었으며, Random보다 빠르고 정확한 무작위 수 생성기입니다.

  • 병렬 환경에서도 성능 저하 없이 잘 작동하고, nextInt(n)을 사용하면 편향 없는 정수를 반환합니다.


transferTo() 메서드로 URL 내용 출력 (Java 9+)

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

public class TransferToExample {
    public static void main(String[] args) throws IOException {
        if (args.length != 1) {
            System.err.println("사용법: java TransferToExample <URL>");
            return;
        }

        // Java 9부터 사용 가능한 transferTo() 메서드
        // URL에서 받아온 데이터를 바로 표준 출력으로 복사
        try (InputStream in = new URL(args[0]).openStream()) {
            // ✅ 입력 스트림의 모든 데이터를 출력 스트림(System.out)에 직접 전달
            in.transferTo(System.out);
        }
    }
}

🔍 설명

  • Java 8까지는 BufferedReaderwhile 루프를 써야 했습니다.

  • Java 9부터는 InputStream.transferTo(OutputStream)을 쓰면 코드 한 줄로 전체 데이터를 복사할 수 있어 더 간단하고 빠릅니다.

  • 입력: URL → 출력: System.out으로 직접 연결


💡 예제 핵심 요약

항목
잘못된 예제
올바른 예제

무작위 수 생성

Math.abs(rnd.nextInt()) % n

ThreadLocalRandom.current().nextInt(n)

문제점

편향, 음수, 반복되는 수열

안전하고 빠른 무작위 수 생성

I/O 스트림 처리

BufferedReader, while 반복

InputStream.transferTo() (Java 9+)

코드 길이

길고 복잡함

짧고 명확함


❗ 자주 발생하는 실수

  1. 라이브러리를 모르고 직접 구현함

  2. Random을 멀티스레드 환경에서 공유함

  3. Java 9+ 기능을 사용하지 않음 (transferTo)

  4. 잘못된 무작위 수 생성 코드 (% 연산으로 편향 발생)

  5. 최신 API 문서 확인을 소홀히 함


💡 핵심 포인트

  • 라이브러리를 익히고 사용하면 이미 검증된 코드를 활용할 수 있음

  • 성능, 안정성, 가독성, 협업 모두에서 직접 구현보다 유리

  • Random, String, List 등 자주 쓰이는 클래스들의 최신 대안을 항상 파악해 둘 것


✅ 결론

  • 라이브러리는 코드를 짧게 만들기 위한 게 아니라, 정확하고 안전하게 만들기 위한 도구다.

  • 성능, 유지보수, 협업 측면에서도 라이브러리 활용이 더 유리하다.


🎯 느낀점

처음에는 ‘내가 직접 구현하는 게 더 빠르지 않을까?’라고 생각했지만, 예제에서처럼 Random이나 transferTo 같은 기능을 보면서 생각이 바뀌었습니다.

  • 라이브러리는 단순히 편리함을 넘어서 정확함과 안전성을 제공합니다.

  • 특히 무작위 수를 잘못 생성한 예제는 충격이었고, ThreadLocalRandom의 필요성을 실감했습니다.

  • transferTo()처럼 자바 버전이 올라가면서 유용한 기능이 계속 추가된다는 것도 배웠습니다.

    앞으로는 기능을 직접 구현하기 전에 "혹시 이거 이미 있는 라이브러리 아닐까"라고 먼저 고민해보려 합니다.

Last updated