Java 8을 사용하여 객체 목록을 toString () 메소드에서 얻은 문자열로 변환


206

Java 8에는 유용한 새로운 것들이 많이 있습니다. 예를 들어, 객체 목록을 스트림으로 반복 한 다음 Object인스턴스 의 특정 필드에서 값을 합칠 수 있습니다. 예 :

public class AClass {
  private int value;
  public int getValue() { return value; }
}

Integer sum = list.stream().mapToInt(AClass::getValue).sum();

따라서 인스턴스 StringtoString()메소드 출력을 한 줄로 연결하는 메소드 를 빌드하는 방법이 있는지 묻습니다 .

List<Integer> list = ...

String concatenated = list.stream().... //concatenate here with toString() method from java.lang.Integer class

그 가정 list정수를 포함 1, 2그리고 3내가 그 기대 concatenated이다 "123""1,2,3".


답변:


369

간단한 방법 중 하나는 목록 항목을 StringBuilder

   List<Integer> list = new ArrayList<>();
   list.add(1);
   list.add(2);
   list.add(3);

   StringBuilder b = new StringBuilder();
   list.forEach(b::append);

   System.out.println(b);

당신은 또한 시도 할 수 있습니다 :

String s = list.stream().map(e -> e.toString()).reduce("", String::concat);

설명 : map은 정수 스트림을 문자열 스트림으로 변환 한 다음 모든 요소의 연결로 축소되었습니다.

참고 : 이것은 normal reductionO (n 2 ) 에서 수행됩니다.

더 나은 성능을 사용 A에 대한 StringBuilder또는 mutable reductionF. BOLLER의 대답과 비슷.

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

참조 : 스트림 감소


2
예, 인라인 솔루션이 아니라 솔루션입니다.
mat_boy

그것을 얻지 못했습니다. 당신은 무엇을 기대하고 있습니까?
Shail016

2
왜 "O (n2)에서 수행되는 정상적인 감소"를 이해하지 못합니다. 나에게 그것은 O (n)처럼 더 "보인다"...
datahaki

2
@datahaki Java 사람은 아니지만 반복 문자열 연결 (축소)에는 각 반복마다 배열 (재) 할당이 필요하므로 O (n ^ 2)가됩니다. join다른 쪽에서는 최종 문자열을 채우기 전에 채우기 위해 충분히 큰 단일 배열을 사전 할당하여 O (n)으로 만듭니다.
Eli Korvigo

2
아주 좋은 팁. "::"표기법을 사용하여 단순화 할 수 있습니다. 그래서 list.stream().map(Object::toString).reduce("", String::concat). 사용 map e-> e.toString()은 약간 중복됩니다.
e2a

194

joiningAPI에 수집기가 있습니다 . 의 정적 메소드입니다 Collectors.

list.stream().map(Object::toString).collect(Collectors.joining(","))

의 호출로 인해 완벽 toString하지는 않지만 작동합니다. 다른 구분 기호가 가능합니다.


7
완전성 : 정확한 코드를 작동 시키려면import static java.util.stream.Collectors.joining;
Mahdi

7
왜 매핑과 명시적인`toString '이 필요한가? 콜렉터가 String 요소를 예상하는 경우 암시 적으로 변환을 호출해야합니다.
바젤 시사 니

10

Java 8 없이이 작업을 수행하려는 경우를 대비하여 꽤 좋은 트릭이 있습니다. List.toString ()은 이미 다음과 같은 컬렉션을 반환합니다.

[1,2,3]

특정 요구 사항에 따라 목록 항목에 [] 또는,을 포함하지 않는 한 원하는대로 사후 처리 할 수 ​​있습니다.

예를 들어 :

list.toString().replace("[","").replace("]","") 

또는 데이터에 대괄호가 포함될 수있는 경우 :

String s=list.toString();
s = s.substring(1,s.length()-1) 

꽤 합리적인 출력을 얻을 수 있습니다.

각 라인에 하나의 배열 항목을 다음과 같이 만들 수 있습니다.

list.toString().replace("[","").replace("]","").replaceAll(",","\r\n")

이 기술을 사용하여 작은 앱의 목록에서 HTML 툴팁을 다음과 같이 만들었습니다.

list.toString().replace("[","<html>").replace("]","</html>").replaceAll(",","<br>")

배열이 있으면 대신 Arrays.asList (list) .toString ()으로 시작하십시오.

나는 이것이 최적이 아니라는 사실을 전적으로 소유 할 것이지만, 생각하는 것만 큼 비효율적이지는 않으며 읽고 이해하기가 매우 간단합니다. 그러나 융통성이 없습니다. 특히 데이터에 쉼표가 포함되어 있으면 replaceAll로 요소를 분리하지 말고 데이터에 대괄호가 있으면 하위 문자열 버전을 사용하십시오.하지만 숫자 배열은 거의 완전한.


이 방법은 일반적으로 작동하지만 List의 구조를 강제하지는 않습니다 toString(). AbstractCollection그러나 기본적 으로이 구조를 사용 List하며 Java SE의 모든 범용 구현도 마찬가지 라고 생각합니다 . 그렇지 않은 예제의 예로 org.springframework.util.AutoPopulatingListSpring에서 구현하지 않으므로 toString()" org.springframework.util.AutoPopulatingList@170a1"를 반환 합니다.
M. Justin

Arrays.toString()Arrays.asList(list).toString()동등한 문자열을 반환하도록 정의되어 있고 더 간결하며 추가 객체 생성이 필요하지 않으므로 보다 낫습니다 .
M. Justin

@ M.Justin이 답변의 배열 부분에 대한 나쁜 점은 아니지만 일반 "목록"은 어떻습니까? 실제로 Arrays.toString ()을 사용할 수는 없습니다. 언급 한 AutoPopulatingList와 같은 방법으로이 기술을 사용하는 방법을 제안 하시겠습니까? 아마도 : new ArrayList (autoPopulatingList) .toString ()? 또는 배열로 변환 할 수 있다고 생각합니다. 만약 당신이 그러한 문제에 부딪쳤다면 당신은 1.8 이상
Bill K

5

다른 답변은 괜찮습니다. 그러나 Collectors.toList () 를 매개 변수로 Stream.collect ()에 전달하여 요소를 ArrayList로 반환 할 수도 있습니다 .

System.out.println( list.stream().map( e -> e.toString() ).collect( toList() ) );

당신이 사용하는 경우 System.out.print(LN)를 (list)그것은 사용 toString()목록을 인쇄 할 요소의 방법을. 따라서이 코드는 toStringList 내에서 일어나는 일을 반복합니다 .
Shirkam

1
정적으로 가져 오지 않는 한 Collectors.toList ()이어야합니다.
mwieczorek

예. 예를 들어 정적으로 가져 왔습니다. 나는 대답의 본문에 "Collectors.toList ()"를 언급했다 ...;)
Eddie B

2

StringListName = ObjectListName.stream (). map (m-> m.toString ()) .collect (Collectors.toList ());


2

String API에는 "joining list of string"유스 케이스를위한 메소드가 있으며, Stream도 필요하지 않습니다.

List<String> myStringIterable = Arrays.asList("baguette", "bonjour");

String myReducedString = String.join(",", myStringIterable);

// And here you obtain "baguette,bonjour" in your myReducedString variable

1
List<String> list = Arrays.asList("One", "Two", "Three");
    list.stream()
            .reduce("", org.apache.commons.lang3.StringUtils::join);

또는

List<String> list = Arrays.asList("One", "Two", "Three");
        list.stream()
                .reduce("", (s1,s2)->s1+s2);

이 방법을 사용하면 객체 목록에서 문자열 결과를 작성할 수도 있습니다.

List<Wrapper> list = Arrays.asList(w1, w2, w2);
        list.stream()
                .map(w->w.getStringValue)
                .reduce("", org.apache.commons.lang3.StringUtils::join);

여기서 reduce 함수를 사용하면 새 문자열을 추가하려는 초기 값을 가질 수 있습니다.

 List<String> errors = Arrays.asList("er1", "er2", "er3");
            list.stream()
                    .reduce("Found next errors:", (s1,s2)->s1+s2);

1

루프 내 에서 단순 + 루프 인 Shail016bpedroso answer ( https://stackoverflow.com/a/24883180/2832140 ) 에서 제안 된 두 가지 접근 방식을 모두 테스트하는 것보다 훨씬 빠르게 실행되는 것으로 보입니다.StringBuilderappend(String)forlist.stream().map([...] .

예제 :이 코드 Map<Long, List<Long>>는 다음을 사용하여 json 문자열 빌드를 안내합니다 list.stream().map([...].

if (mapSize > 0) {
    StringBuilder sb = new StringBuilder("[");

    for (Map.Entry<Long, List<Long>> entry : threadsMap.entrySet()) {

        sb.append("{\"" + entry.getKey().toString() + "\":[");
        sb.append(entry.getValue().stream().map(Object::toString).collect(Collectors.joining(",")));
    }
    sb.delete(sb.length()-2, sb.length());
    sb.append("]");
    System.out.println(sb.toString());
}

개발자 VM에서 junit은 일반적으로 테스트를 실행하는 데 0.35 초에서 1.2 초가 걸립니다. 다음 코드를 사용하는 동안 0.15 ~ 0.33 초가 걸립니다.

if (mapSize > 0) {
    StringBuilder sb = new StringBuilder("[");

    for (Map.Entry<Long, List<Long>> entry : threadsMap.entrySet()) {

        sb.append("{\"" + entry.getKey().toString() + "\":[");

        for (Long tid : entry.getValue()) {
            sb.append(tid.toString() + ", ");
        }
        sb.delete(sb.length()-2, sb.length());
        sb.append("]}, ");
    }
    sb.delete(sb.length()-2, sb.length());
    sb.append("]");
    System.out.println(sb.toString());
}

0

우리 시도해볼 수 있을까요?

public static void main(String []args){
        List<String> stringList = new ArrayList<>();
        for(int i=0;i< 10;i++){
            stringList.add(""+i);
        }
        String stringConcated = String.join(",", stringList);
        System.out.println(stringConcated);

    }

0
String actual = list.stream().reduce((t, u) -> t + "," + u).get();

7
일반적으로 게시물의 코드 작동 방식에 대한 설명을 게시물에 추가하는 것이 좋습니다. 이를 통해 새로운 개발자는 코드의 기능을 이해할 수 있습니다.
Caleb Kleveter

1
@CalebKleveter는 a List를 하나로 줄이고 String각 요소를 쉼표 ( ,) 로 구분 합니다.
Joe Almore

2
list가 List <String> 인 경우에만 솔루션이 작동합니다. OP는 그러한 클래스를 지정하지 않았습니다. 그의 질문에는 List <Integer>조차도 지적됩니다. 이 경우 코드가 컴파일되지 않습니다.
RubioRic

0

스트림 api를 사용하여 정수 스트림을 단일 문자열로 변환합니다. 제공된 답변 중 일부의 문제점은 문자열 작성으로 인해 O (n ^ 2) 런타임을 생성한다는 것입니다. 더 나은 해결책은 StringBuilder를 사용하고 마지막 단계로 문자열을 결합하는 것입니다.

//              Create a stream of integers 
    String result = Arrays.stream(new int[]{1,2,3,4,5,6 })                
            // collect into a single StringBuilder
            .collect(StringBuilder::new, // supplier function
                    // accumulator - converts cur integer into a string and appends it to the string builder
                    (builder, cur) -> builder.append(Integer.toString(cur)),
                    // combiner - combines two string builders if running in parallel
                    StringBuilder::append) 
            // convert StringBuilder into a single string
            .toString();

객체 컬렉션을 단일 문자열로 변환하여이 프로세스를 한 단계 더 발전시킬 수 있습니다.

// Start with a class definition
public static class AClass {
    private int value;
    public int getValue() { return value; }
    public AClass(int value) { this.value = value; }

    @Override
    public String toString() {
        return Integer.toString(value);
    }
}

// Create a stream of AClass objects
        String resultTwo = Arrays.stream(new AClass[]{
                new AClass(1),
                new AClass(2),
                new AClass(3),
                new AClass(4)
        })
                // transform stream of objects into a single string
                .collect(StringBuilder::new,
                        (builder, curObj) -> builder.append(curObj.toString()),
                        StringBuilder::append
                )
            // finally transform string builder into a single string
            .toString();

-1

Java 8 이상

String s = Arrays.toString(list.stream().toArray(AClass[]::new));

가장 효율적이지는 않지만 적은 양의 코드가있는 솔루션입니다.


-2

또한 이렇게 할 수 있습니다.

    List<String> list = Arrays.asList("One", "Two", "Three");
    String result = String.join(", ", list);
    System.out.println(result);

list가 List <String> 인 경우에만 솔루션이 작동합니다. OP는 그러한 클래스를 지정하지 않았습니다. 그의 질문에는 List <Integer>조차도 지적됩니다.
RubioRic
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.