가변인수
자바 5+ 버전부터 등장한 가변인수 메서드는 명시한 타입의 인수를 0개 이상 받을 수 있습니다.
가변인수 메서드를 호출하면 다음과 같이 처리합니다.
- 가장 먼저 인수의 개수와 길이가 같은 배열을 생성하고
- 인수들을 해당 배열에 저장하여 가변인수 메서드에 건네줌
다음 코드는 입력받은 int 인수들의 합을 계산하는 예제입니다.
위 코드에서 볼 수 있다시피 가변인수 적용 시 메서드를 보다 간결하고 유연하게 만들어주므로, 적절하게 사용하면 코드의 가독성과 유지보수성을 향상할 수 있습니다.
여기까지만 봐서는 가변인수를 무조건 적용해야 하는 것처럼 보이지만, 가변인수 사용 시 몇 가지 규칙과 주의사항이 있습니다.
- 인수를 0개만 받도록 설계하는 것은 좋지 않음
- 힙 오염 주의
- 성능 이슈
- 메서드 당 한 개의 가변인수만 사용 가능
1. 인수를 0개만 받도록 설계하는 것은 좋지 않음
인수 개수는 런타임에 가변인수에 의해 자동으로 생성된 배열의 길이로 알 수 있습니다.
따라서 최솟값을 구하는 메서드처럼 인수를 0개만 넣었을 때 런타임 에러가 발생하는 코드를 컴파일 시점에 잡아낼 수 없습니다.
다행히도 해당 문제에 대한 해결책이 존재합니다.
다음 코드처럼 첫 번째로는 평범한 매개변수를 받고, 가변인수는 두 번째로 받으면 앞서의 문제가 말끔히 사라집니다.
2. 힙 오염 주의
아이템 32에서 언급했다시피 제네릭과 함께 가변인수 사용 시 힙 오염이 발생할 수 있습니다.
- 힙 오염은 제네릭으로 타입이 정의된 데이터 구조에서 실제로는 다른 타입의 데이터가 저장되는 상황
- 일반적으로 제네릭은 컴파일 시에 타입 안전성을 보장하기 위해 사용
- 그러나 가변인자(varargs)나 배열과 같은 특정 상황에서 제네릭이 제대로 동작하지 않으면 힙 오염이 발생 가능
코드 부연 설명
- dangerous 메서드는 List<String> 타입의 리스트들을 받는 가변인자를 가지고 있음
- dangerous 메서드 내에서 List<Integer>을 생성하고, 그것을 Object 배열에 할당
- 배열을 통해 stringLists에 접근하여 List<Integer>를 추가했고 이로 인해 힙 오염(heap pollution)이 발생
- stringLists에 접근하여 List<Integer>인 요소를 List<String>으로 캐스팅하려고 시도하면 ClassCastException이 발생
- 힙 오염이 발생하는 이유는 가변인자를 통해 전달된 stringLists 배열이 List<String>의 배열이라는 것을 보장하지 않기 때문
- 좋은 프로그래밍 실천법은 가변인자(varargs)와 제네릭을 함께 사용하지 않는 것이며, 가능하다면 리스트나 컬렉션을 이용하여 처리하는 것이 더 안전
3. 성능 이슈
성능에 민감한 상황이라면 가변인수가 걸림돌이 될 수 있습니다.
가변인수 메서드는 호출될 때마다 배열을 새로 하나 할당하고 초기화하기 때문에 상당히 비싼 작업입니다.
다행히 가변인수의 유연성이 필요할 때 선택할 수 있는 패턴이 있습니다.
메서드 호출의 95%가 인수를 3개 이하로 사용한다고 가정했을 때 다음처럼 인수가 0인 것부터 4개인 것까지 총 5개를 정의하고 마지막 다중정의 메서드가 인수 4개 이상인 5%의 호출을 담당하도록 작성하는 방식입니다.
EnumSet의 정적 팩터리 of도 위 패턴을 적용해 열거 타입 집합 생성 비용을 최소화하는 것을 볼 수 있습니다.
EnumSet은 비트 필드를 대체하면서 성능까지 보장해야 하기 때문에 아주 적절하게 활용한 예라 할 수 있습니다.
4. 메서드 당 한 개의 가변인수만 사용 가능
자바에서는 메서드당 가변인수를 하나만 사용할 수 있습니다.
즉, 한 메서드 시그니처 내에서는 하나의 가변인수 매개변수만 허용되며 반드시 메서드 파라미터의 마지막에 위치해야 합니다.
정리
메서드의 인수 개수가 일정하지 않을 경우 가변인수를 필요로 하지만, 이에는 몇 가지 주의사항과 제약이 있으므로 신중한 고려 후 적용하는 것이 권장됩니다.
'JAVA > Effective Java' 카테고리의 다른 글
[아이템 55] 옵셔널 반환은 신중히 하라 (0) | 2024.03.12 |
---|---|
[아이템 54] null이 아닌, 빈 컬렉션이나 배열을 반환하라 (0) | 2024.03.11 |
[아이템 52] 다중정의는 신중히 사용하라 (1) | 2024.03.10 |
[아이템 51] 메서드 시그니처를 신중히 설계하라 (0) | 2024.03.09 |
[아이템 50] 적시에 방어적 복사본을 만들라 (0) | 2024.03.09 |