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+)
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+)
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까지는
BufferedReader
와while
루프를 써야 했습니다.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+)
코드 길이
길고 복잡함
짧고 명확함
❗ 자주 발생하는 실수
라이브러리를 모르고 직접 구현함
Random
을 멀티스레드 환경에서 공유함Java 9+ 기능을 사용하지 않음 (
transferTo
)잘못된 무작위 수 생성 코드 (
%
연산으로 편향 발생)최신 API 문서 확인을 소홀히 함
💡 핵심 포인트
라이브러리를 익히고 사용하면 이미 검증된 코드를 활용할 수 있음
성능, 안정성, 가독성, 협업 모두에서 직접 구현보다 유리
Random, String, List 등 자주 쓰이는 클래스들의 최신 대안을 항상 파악해 둘 것
✅ 결론
라이브러리는 코드를 짧게 만들기 위한 게 아니라, 정확하고 안전하게 만들기 위한 도구다.
성능, 유지보수, 협업 측면에서도 라이브러리 활용이 더 유리하다.
🎯 느낀점
처음에는 ‘내가 직접 구현하는 게 더 빠르지 않을까?’라고 생각했지만, 예제에서처럼 Random
이나 transferTo
같은 기능을 보면서 생각이 바뀌었습니다.
라이브러리는 단순히 편리함을 넘어서 정확함과 안전성을 제공합니다.
특히 무작위 수를 잘못 생성한 예제는 충격이었고,
ThreadLocalRandom
의 필요성을 실감했습니다.transferTo()
처럼 자바 버전이 올라가면서 유용한 기능이 계속 추가된다는 것도 배웠습니다.앞으로는 기능을 직접 구현하기 전에 "혹시 이거 이미 있는 라이브러리 아닐까"라고 먼저 고민해보려 합니다.
Last updated