[java] ArrayList를 문자열로 변환하는 가장 좋은 방법

나는이 ArrayList나는 완전히 String으로 출력 할 것인지. 본질적 toString으로 탭으로 구분 된 각 요소를 사용하여 순서대로 출력하고 싶습니다 . 이 작업을 수행하는 빠른 방법이 있습니까? 루프를 반복하거나 각 요소를 제거하고 문자열에 연결할 수는 있지만 매우 느릴 것이라고 생각합니다.



답변

기본적으로 루프를 사용하여 반복하는 ArrayList것이 유일한 옵션입니다.

이 코드를 사용하지 말고, 왜이 코드가 바람직하지 않은지, 대신 어떤 코드를 사용해야하는지 확인하려면이 답변의 맨 아래를 계속 읽으십시오.

ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

String listString = "";

for (String s : list)
{
    listString += s + "\t";
}

System.out.println(listString);

실제로, 문자열 연결은 javac컴파일러가 어쨌든 일련의 append작업으로 문자열 연결을 최적화 하기 때문에 괜찮을 것 StringBuilder입니다. for위 프로그램 의 루프에서 바이트 코드를 디스 어셈블하는 부분은 다음과 같습니다 .

   61:  new #13; //class java/lang/StringBuilder
   64:  dup
   65:  invokespecial   #14; //Method java/lang/StringBuilder."<init>":()V
   68:  aload_2
   69:  invokevirtual   #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   72:  aload   4
   74:  invokevirtual   #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   77:  ldc #16; //String \t
   79:  invokevirtual   #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   82:  invokevirtual   #17; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

보다시피, 컴파일러는를 사용하여 루프를 최적화 StringBuilder하므로 성능에 큰 문제가되지 않습니다.

(두 번째 StringBuilder로, 루프의 각 반복에서 인스턴스화되고 있으므로 가장 효율적인 바이트 코드가 아닐 수 있습니다. 명시 적으로 인스턴스화하고 사용하면 StringBuilder성능이 향상됩니다.)

사실, 어떤 종류의 출력 (디스크 또는 화면)이 문자열 연결의 성능에 대해 걱정하는 것보다 적어도 속도가 느릴 것이라고 생각합니다.

편집 : 주석에서 지적했듯이 위의 컴파일러 최적화는 실제로 StringBuilder각 반복마다 새 인스턴스를 작성합니다 . (이전에 언급 한 것입니다.)

가장 최적화 된 기술 은 루프 외부의 단일 객체 만 인스턴스화하기 때문에 Paul Tomblin 의 응답 입니다.StringBuilderfor

위의 코드를 다시 작성하여 다음을 수행하십시오.

ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

StringBuilder sb = new StringBuilder();
for (String s : list)
{
    sb.append(s);
    sb.append("\t");
}

System.out.println(sb.toString());

이 바이트 코드에서 입증 된 것처럼 StringBuilder루프 외부 에서 한 번만 인스턴스화하고 루프 append내부의 메소드 를 두 번만 호출합니다 (인스턴스화 StringBuilder및 루프 를 보여줍니다 ).

   // Instantiation of the StringBuilder outside loop:
   33:  new #8; //class java/lang/StringBuilder
   36:  dup
   37:  invokespecial   #9; //Method java/lang/StringBuilder."<init>":()V
   40:  astore_2

   // [snip a few lines for initializing the loop]
   // Loading the StringBuilder inside the loop, then append:
   66:  aload_2
   67:  aload   4
   69:  invokevirtual   #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   72:  pop
   73:  aload_2
   74:  ldc #15; //String \t
   76:  invokevirtual   #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   79:  pop

따라서 for루프 내부 가 짧고 StringBuilder각 반복마다 인스턴스를 생성 할 필요가 없으므로 실제로 손 최적화가 더 잘 수행되어야합니다 .


답변

Java 8 이상에서 :

String listString = String.join(", ", list);

list가 String 유형이 아닌 경우, 결합 콜렉터를 사용할 수 있습니다.

String listString = list.stream().map(Object::toString)
                        .collect(Collectors.joining(", "));


답변

Android 에서이 작업을 수행하는 경우 TextUtils 라는 유용한 유틸리티 가 .join(String delimiter, Iterable)있습니다.

List<String> list = new ArrayList<String>();
list.add("Item 1");
list.add("Item 2");
String joined = TextUtils.join(", ", list);

분명히 안드로이드 외부에서는 많이 사용하지는 않지만이 스레드에 추가 할 것이라고 생각했습니다 …


답변

Apache Commons Lang을 다운로드하고 메소드를 사용하십시오.

 StringUtils.join(list)

 StringUtils.join(list, ", ") // 2nd param is the separator.

물론 직접 구현할 수도 있지만 코드는 완전히 테스트되었으며 아마도 가장 좋은 구현 일 것입니다.

저는 Apache Commons 라이브러리의 열렬한 팬이며 Java 표준 라이브러리에 큰 도움이된다고 생각합니다.


답변

이것은 꽤 오래된 질문이지만 구아바Joiner수업을 사용하여 더 현대적인 답변을 추가 할 수 있다고 생각합니다 .

String joined = Joiner.on("\t").join(list);


답변

읽기 쉽고 의미있는 문자열로 List 를 변경 하는 것은 실제로 모든 사람이 직면 할 수있는 일반적인 질문입니다.

사례 1 . 클래스 경로에 아파치의 StringUtils가있는 경우 (rogerdpack 및 Ravi Wallau에서와 같이) :

import org.apache.commons.lang3.StringUtils;
String str = StringUtils.join(myList);

사례 2 . JDK (7)의 방법 만 사용하려는 경우 :

import java.util.Arrays;
String str = Arrays.toString(myList.toArray()); 

혼자서 바퀴를 만들지 마십시오.이 한 줄 작업에는 루프를 사용하지 마십시오.


답변

Java 5부터 빠른 원 라이너를 찾고 있다면 다음과 같이 할 수 있습니다.

myList.toString().replaceAll("\\[|\\]", "").replaceAll(", ","\t")

또한, 목적이 단지 내용을 인쇄하고 “\ t”에 대해 덜 염려한다면 다음과 같이하면됩니다.

myList.toString()

다음과 같은 문자열을 반환합니다

[str1, str2, str3]

ArrayList가 아닌 Array가있는 경우 다음과 같이 동일하게 수행 할 수 있습니다.

 Arrays.toString(myList).replaceAll("\\[|\\]", "").replaceAll(", ","\t")