개발하는 두더지

[Effective Java 규칙42] varargs는 신중히 사용하라 본문

Java,Android

[Effective Java 규칙42] varargs는 신중히 사용하라

덜지 2018. 10. 16. 11:37

[Effective Java 규칙42] varargs는 신중히 사용하라

Effective Java 2/E 책과 구글링을 통해 내용을 정리하고 개인적인 견해가 포함된 글입니다.


자바 1.5부터 가변 인자 메서드 ( variable arity method ) 라고 부르는 varargs 메서드가 추가되었다. 이 메서드는 인자를 0개 이상 받을 수 있다. 동작원리는 클라이언트에서 전달된 인자 수에 맞는 배열이 자동으로 생성되고, 모든 인자가 해당 배열에 대입된다. 그리고 해당 배열이 메서드에 인자로 전달된다.


아래는 varargs를 이용한 간단한 샘플이다.

public class varargsTest {
static int sum(int... args) {
int sum = 0;
for(int arg : args)
sum += arg;

return sum;
}

public static void main(String[] args) {
System.out.println(varargsTest.sum(1,2,3,4,5));
}
}


배열을 마지막 인자로 받는 메서드는, 기존 소스에 아무 영향을 주지 않으면서 마지막을 varargs 인자로 바꿀 수 있다.

static int min(int firstArg, int... args) {
int min = firstArg;
for(int arg : args) {
if(arg < min)
min = arg;
}
return min;
}

성능이 중요한 환경이라면 varargs 사용에 더욱 신중해야 한다. varargs 메서드를 호출할 때마다 배열이 만들어지고 초기화되기 때문에 오버헤드를 감당할 수 없다면 다른 패턴을 사용해야 한다. 만약 95%정도가 3개 이하의 인자가 전달된다고 가정해보자. 아래 코드처럼 오버로딩 메서드를 만들면 5% 정도의 호출에 대해서만 새로운 배열이 만들어진다. 보통 적절치 않지만 대부분의 성능 최적화 기법이 이렇게 때문에 막상 사용하면 유용하다.

public void foo() {}
public void foo(int a1) {}
public void foo(int a1, int a2) {}
public void foo(int a1, int a2, int a3) {}
public void foo(int a1, int a2, int a3, int... rest) {}

EnumSet 클래스의 정적 팩터리 메서드들은 이 패턴을 사용해서 enum 생성 비용을 최소로 한다. EnumSet은 비트 필드를 대신하면서도 그에 맞는 성능을 내야했기에 이 패턴이 적절했다.




Arrays.asList 의 경우 이 메서드는 여러 인자를 하나의 리스트로 합칠 목적으로 만들어진 것은 아니였다. 그래서 varargs가 플랫폼에 추가되었을 때, 아래와 같이 코드를 수정했다.

List<String> numbers = Arrays.asList("one", "two", "three");

자바 1.5 이전에는 보통 배열을 출력하기 위해 아래와 같이 사용했는데, [[I@75b84c92] 와 같은 쓸모없는 값이 출력된다.

자바 1.4 버전까지는 객체 참조 자료형에 대해서만 동작됐고, 기본 자료형(primitive type) int, long 과 같은 배열은 컴파일이 되지도 않았다.

int[] list = {1, 2, 3, 4, 5 };
System.out.println(Arrays.asList(list));


그래서 1.5 버전부터 Arrays 클래스에는 어떤 자료형이라도 문자열로 변환할 수 있는 Arrays.toString 메서드가 생겨났다.










Comments