어쩌다 마주친 String...
타입
elasticsearch와 Spring Boot를 연결하기 위해 ElasticConfig
클래스를 작성하던 중, elasticsearch의 호스트가 여러 개인 multi node 환경에서는 어떻게 연결해야하는 것인지 궁금해졌다.
ElasticsearchConfig.java
@Configuration
public class ElasticsearchConfig extends ElasticsearchConfiguration {
@Value("${spring.elasticsearch.username}")
private String username;
@Value("${spring.elasticsearch.password}")
private String password;
@Value("${spring.elasticsearch.uris}")
private String[] esHost;
@Override
public ClientConfiguration clientConfiguration() {
return ClientConfiguration.builder()
.connectedTo(esHost)
.withBasicAuth(username, password)
.build();
}
}
application.yml
파일에 작성된 spring.elasticsearch.uris
는 컴마(,)로 구분되는 스트링이다. 이 값을 @Value
어노테이션을 사용해서 String[]
혹은 List<String>
의 타입으로 받으면 자동으로 배열 혹은 리스트의 형태로 매핑된다.
이때 connectedTo()
메소드의 인자 값이, 예제에선 .connectedTo("localhost:9200")
같은 형태로 작성되어 String
타입을 받는 모습을 볼 수 있다.
그러나 elasticsearch는 분산 처리에 강하여 운영 시 multi-node 환경으로 많이 활용된다. 그렇다면 String
의 리스트 형태로 받을 수 있어야 하는데, 이를 어떻게 사용해야 할지 궁금해져 connectedTo()
메소드의 구현부를 살펴보았다.
ClientConfiguration.java
package org.springframework.data.elasticsearch.client;
public interface ClientConfiguration {
...
default MaybeSecureClientConfigurationBuilder connectedTo(String hostAndPort) {
return connectedTo(new String[] { hostAndPort });
}
MaybeSecureClientConfigurationBuilder connectedTo(String... hostAndPorts);
}
connectedTo()
의 이름을 가진 메소드가 다른 매개변수로 2개 존재했다.
String
타입의 매개변수가 들어오면, 원소를 하나만 갖는 String[]
타입의 변수로 포팅해서 다른 connectedTo()
메소드를 호출하는 방식으로 구현되어있다.
그래서 connectedTo()
메소드의 매개변수로 들어가는 hostAndPorts
의 타입인 String...
은 도대체 뭐지? 하는 의문이 생겼다.
String...
타입이란?
자바에서는 JDK5 버전부터 가변인자라고 부르는 Varargs라는 개념을 도입했다.
간단하게 말해선 String[]
배열 타입과 유사하다. 좀 더 자세히 알아보자
String...
vs String[]
// 출처: https://stackoverflow.com/questions/11973505/what-is-the-difference-between-string-and-string-in-java
public void myMethod(String... foo) {
// do something
// foo is an array (String[]) internally
System.out.println(foo[0]);
}
myMethod("a", "b", "c");
// OR
myMethod(new String[]{"a", "b", "c"});
// OR without passing any args
myMethod();
// 출처: https://stackoverflow.com/questions/11973505/what-is-the-difference-between-string-and-string-in-java
public void myMethod(String[] foo) {
// do something
System.out.println(foo[0]);
}
// compilation error!!!
myMethod("a", "b", "c");
// compilation error too!!!
myMethod();
// now, just this works
myMethod(new String[]{"a", "b", "c"});
참고한 Stackoverflow 답변과 그 예제 코드에 따르면, String...
타입의 매개변수는 함수의 내부에선 String[]
타입과 유사하게 활용된다.
public void myMethod(String... string){
System.out.println("String... class: " + string.getClass());
}
public void test() {
String[] list = new String[] {"A", "B"};
System.out.println("String[] class: " + list.getClass());
myMethod();
myMethod("a");
myMethod("a", "b");
}
// result
// String[] class: class [Ljava.lang.String;
// String... class: class [Ljava.lang.String;
// String... class: class [Ljava.lang.String;
// String... class: class [Ljava.lang.String;
간단한 테스트 메소드를 작성해서 getClass()
메소드의 결과를 보면, String...
매개변수가 함수의 내부로 들어가면 String[]
타입으로 변환되어 사용되는 것이라고 짐작해볼 수 있다.
String...
과 String[]
의 가장 큰 차이는 매개변수에 실제 값을 대입할 때 나타난다.
매개변수의 타입이 String[]
인 경우, String[]
타입의 변수만 대입할 수 있다.
그러나 String...
타입인 경우, String[]
타입의 변수는 물론 String
타입의 변수를 컴마로 여러 개 늘어놓는 형태도 가능하며 심지어 아무 변수도 넘겨주지 않는 방식으로도 메소드 호출이 가능하다.
// ERROR
public void myMethod(String... foo, int bar);
// CORRECT
public void myMethod(int bar, String... foo);
추가로 메소드의 매개변수로 String...
타입을 사용하려면 꼭 매개변수의 가장 마지막에 넣어주어야한다.