본문 바로가기
JAVA

가변인수

by oncerun 2022. 11. 5.
반응형

 

가변 인수에 대한 내용은 자바스크립트를 공부하면서 rest 파라미터에 대한 내용으로 알고 있었다. 

자바를 사용해 개발을 진행할 때는 잘 사용하지 않는 기능이였는데, 최근 자바에 대한 공부를 진행하면서 관련 내용이 있어 정리하려고 한다. 

 

사실 가변인수에 대한 내 생각은 부정적이다. 그 이유는 바로 모호함이다.

모호함은 프로그래머를 고생시킨다.

가변 인수를 사용할 수 있는 메서드를 정의했다고 해도 이를 사용하는 측에서는 반드시 확인을 하게 된다.

모호하게 가변적으로 인수를 더 받을 수 있는 것보단 확실하게 파라미터 정의를 통해 알려주는 쪽이 좋다고 생각한다. 

 

물론 이를 위해 메소드 오버 로딩 등 코드의 중복이 발생할 수 있지만 모호함으로 인해 발생하는 사이드 이펙트를 생각해보면 더 좋은 코드가 아닐까 생각한다. 

 

가변 인수는 클라이언트에서 인수의 개수를 조절할 수 있는 기능이다. 

해당 가변인수를 사용한 메서드를 호출하면 정의된 타입을 가진 배열이 자동적으로 만들어 진다.

 

가변 인수를 활용한 메서드는 ClassCastException이 발생할 여지가 있습니다. 이는 Heap Pollution이라고 하는 과정입니다.

 

Heap Pollution

Java generic type에서 변수화 된 타입이 가리키는 오브젝트의 타입이 해당 변수화 된 타입의 타입과 다를 때를 의미한다.

public class HeapPollutionDemo {
    public static void main(String[] args) {
        Set s = new TreeSet<Integer>();
        Set<String> ss = s;            // unchecked warning

        s.add(new Integer(42));        // another unchecked warning

        Iterator<String> iter = ss.iterator();
        while (iter.hasNext()) {
           String str = iter.next();   // ClassCastException thrown
           System.out.println(str);
        }
    }
}

 

이 는 실제 형 변환을 하여 가변 인수의 타입과 변환되는 타입이 일치되지 않는 경우가 아니더라도 발생합니다.

public void varargs(List<String>... stringArgs){
    Object[] object = stringArgs; //Object 배열에 가변인수 배열 할당.
    
    object[0] = List.of(1,2,3);  //가변인수가 데이터전달을 하지 않고 타입이 변환된 채로 재할당(heap pollutin) 
    
    String result = stringArgs[0].get(0); // 가변인수 배열이 이중 배열구조로 되어 요소 취득
    
}

타입이 변하지 않는 코드로 보이지만 제네릭은 실체화되지 않는다. 컴파일 시점에 이는 형 변환이 이루어지게 되는데 

이 과정에서 ClassCastException이 발생한다. 

 

 

물론 정확한 가변 인수에 대한 타입 캐스팅 없이 안전하게 사용한다면 매우 좋은 기능이 될 수 있습니다. 

실제 매우 편리한 기능이기도 합니다.

 

제네릭 가변 인수를 가진 메서드를 작성했다면 호출자에게 알려주는 방법도 매우 좋은 것 같습니다.

 

만약 해당 메서드가 정말 type-safe 하다면 자바 7에서 나온 @SafeVarargs 에노 테이션을 통해 호출자 쪽에서 발생하는 경고를 숨길 수 있습니다. 

 

그럼 type-safe 한 가변 인수 메서드의 조건은 뭘까요?

 

- 가변 인수 배열의 참조값을 외부로 반환하지 않는다.  오류에 범위가 커질 수 있는 부분으로 보입니다.

- 단순 데이터 전달

 

즉 해당 가변 인수를 통해 복잡한 무언가를 하지 않고 호출자의 의도가 단순히 전달을 위해서만 사용한다면 이는 type-safe 해질 수 있습니다. 

 

이를 활용하는 특정 예시는 setter가 있을 수 있을 것 같네요.

 

자바 빈인 경우 말고 빌더 패턴을 이용하는 경우 필수 값 외에 가변 인수를 통해 추가적인 작업을 해줄 수 있을 것 같습니다. 

 

하지만 setter를 사용하는 외부 라이브러리들이 많은 경우에는 적합하지 않아 보입니다. 여러 계층적인 구조로 복잡한 클래스의 인스턴스를 생성할 때 하위 타입의 빌더에서 필요에 따라 구현하는 방법도 생각해보았습니다. 

 

근데 이 방법 말고도 더 좋은 방법이 있을 것 같습니다. 인스턴스를 만들 때 어떠한 변형을 가하는 것이 의미 있는 메서드 네이밍을 통해 변형을 가하는 것보다 좋다고는 생각할 수 없을 것 같습니다. 

 

코드의 수를 줄인다?, 가변 인자라 생성 시 필수 값을 강제하지는 못할 것 같고, 이는 뭔가 의도를 숨기는 역할을 할 수도 있겠다는 생각이 드네요. 

 

일단 가벼운 프로젝트에 적용해서 사용해보아야겠습니다

 

 

 

 

 

 

반응형

'JAVA' 카테고리의 다른 글

S3 다중 업로드를 병렬로 처리 시 발생할 수 있는 문제..(CountDownLatch)  (0) 2022.12.03
keytool  (0) 2022.11.14
JDK Dynamic Proxy  (0) 2022.01.22
Server Networking Proxy  (0) 2021.11.14
메일 발송  (0) 2021.11.06

댓글