it-swarm-ko.tech

Java에서 구분 된 문자열을 만드는 가장 좋은 방법은 무엇입니까?

Java 응용 프로그램에서 작업하는 동안 필자는 미리 몇 개의 요소가 있는지를 모른 채 다른 웹 서비스에 전달할 쉼표로 분리 된 값 목록을 어셈블해야했습니다. 내 머리 꼭대기에서 나올 수있는 최선의 방법은 다음과 같습니다.

public String appendWithDelimiter( String original, String addition, String delimiter ) {
    if ( original.equals( "" ) ) {
        return addition;
    } else {
        return original + delimiter + addition;
    }
}

String parameterString = "";
if ( condition ) parameterString = appendWithDelimiter( parameterString, "elementName", "," );
if ( anotherCondition ) parameterString = appendWithDelimiter( parameterString, "anotherElementName", "," );

문자열이 모든 곳에서 만들어지기 때문에 이것이 특히 효율적이지는 않다는 것을 알았지 만, 최적화보다 더 명확하게하려고했습니다.

루비에서, 나는 대신이 느낌을 훨씬 더 우아하게 할 수 있습니다 :

parameterArray = [];
parameterArray << "elementName" if condition;
parameterArray << "anotherElementName" if anotherCondition;
parameterString = parameterArray.join(",");

하지만 Java에 join 명령이 없기 때문에 동등한 것을 찾을 수 없었습니다.

그럼, 자바에서 이것을하는 가장 좋은 방법은 무엇입니까?

280
Sean McMains

사전 Java 8 :

Apache의 commons lang은 여러분의 친구입니다 - Ruby에서 여러분이 참조한 것과 매우 유사한 조인 방법을 제공합니다 :

StringUtils.join(Java.lang.Iterable,char)


Java 8 :

Java 8은 StringJoinerString.join()을 통해 즉시 가입 할 수 있습니다. 아래 스 니펫은 어떻게 사용할 수 있는지 보여줍니다.

StringJoiner

StringJoiner joiner = new StringJoiner(",");
joiner.add("01").add("02").add("03");
String joinedString = joiner.toString(); // "01,02,03"

String.join(CharSequence delimiter, CharSequence... elements))

String joinedString = String.join(" - ", "04", "05", "06"); // "04 - 05 - 06"

String.join(CharSequence delimiter, Iterable<? extends CharSequence> elements)

List<String> strings = new LinkedList<>();
strings.add("Java");strings.add("is");
strings.add("cool");
String message = String.join(" ", strings);
//message returned is: "Java is cool"
490
Martin Gladdish

Java.util.Lists에서 작동하는 조인 스타일 유틸리티 메서드를 작성할 수 있습니다.

public static String join(List<String> list, String delim) {

    StringBuilder sb = new StringBuilder();

    String loopDelim = "";

    for(String s : list) {

        sb.append(loopDelim);
        sb.append(s);            

        loopDelim = delim;
    }

    return sb.toString();
}

다음과 같이 사용하십시오.

    List<String> list = new ArrayList<String>();

    if( condition )        list.add("elementName");
    if( anotherCondition ) list.add("anotherElementName");

    join(list, ",");
52
Rob Dickerson

Android의 경우 Commons의 StringUtils 클래스를 사용할 수 없으므로

Android.text.TextUtils.join(CharSequence delimiter, Iterable tokens)

http://developer.Android.com/reference/Android/text/TextUtils.html

46
Kevin

Google의 Guava 라이브러리com.google.common.base.Joiner 클래스는 이러한 작업을 해결하는 데 도움이됩니다.

견본:

"My pets are: " + Joiner.on(", ").join(Arrays.asList("rabbit", "parrot", "dog")); 
// returns "My pets are: rabbit, parrot, dog"

Joiner.on(" AND ").join(Arrays.asList("field1=1" , "field2=2", "field3=3"));
// returns "field1=1 AND field2=2 AND field3=3"

Joiner.on(",").skipNulls().join(Arrays.asList("London", "Moscow", null, "New York", null, "Paris"));
// returns "London,Moscow,New York,Paris"

Joiner.on(", ").useForNull("Team held a draw").join(Arrays.asList("FC Barcelona", "FC Bayern", null, null, "Chelsea FC", "AC Milan"));
// returns "FC Barcelona, FC Bayern, Team held a draw, Team held a draw, Chelsea FC, AC Milan"

다음은 Guava의 문자열 유틸리티에 관한 기사 입니다.

31
Alex K

Java 8에서는 String.join() 를 사용할 수 있습니다.

List<String> list = Arrays.asList("foo", "bar", "baz");
String joined = String.join(" and ", list); // "foo and bar and baz"

또한 Stream API 예제에서 이 대답 을 살펴보십시오.

25
micha

당신은 그것을 일반화 할 수는 있지만, 자바에서 조인은 없습니다.

This 더 잘 작동 할 것입니다.

public static String join(Iterable<? extends CharSequence> s, String delimiter) {
    Iterator<? extends CharSequence> iter = s.iterator();
    if (!iter.hasNext()) return "";
    StringBuilder buffer = new StringBuilder(iter.next());
    while (iter.hasNext()) buffer.append(delimiter).append(iter.next());
    return buffer.toString();
}
20
Vinko Vrsalovic

Java.lang.StringBuilder !에 기반한 접근 방식을 사용하십시오. ( "변경 가능한 문자 시퀀스")

앞에서 언급 한 것처럼 모든 문자열 연결은 문자열을 생성합니다. StringBuilder은 그렇게하지 않습니다.

StringBuilder 대신에 StringBuffer을 사용해야합니까? StringBuilder javadoc에서 :

가능하면 대부분의 구현에서 빠르기 때문에이 클래스를 StringBuffer보다 우선적으로 사용하는 것이 좋습니다.

15
Stu Thompson

java 8에서는 다음과 같이 할 수 있습니다.

list.stream().map(Object::toString)
                        .collect(Collectors.joining(delimiter));

list에 null이 있으면 다음을 사용할 수 있습니다.

list.stream().map(String::valueOf)
                .collect(Collectors.joining(delimiter))
12
gladiator

Google Collections를 사용할 것입니다. Nice Join 시설이 있습니다.
http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?com/google/common/base/Join.html

그러나 만약 내가 그것을 독자적으로 쓰고 싶다면,

package util;

import Java.util.ArrayList;
import Java.util.Iterable;
import Java.util.Collections;
import Java.util.Iterator;

public class Utils {
    // accept a collection of objects, since all objects have toString()
    public static String join(String delimiter, Iterable<? extends Object> objs) {
        if (objs.isEmpty()) {
            return "";
        }
        Iterator<? extends Object> iter = objs.iterator();
        StringBuilder buffer = new StringBuilder();
        buffer.append(iter.next());
        while (iter.hasNext()) {
            buffer.append(delimiter).append(iter.next());
        }
        return buffer.toString();
    }

    // for convenience
    public static String join(String delimiter, Object... objs) {
        ArrayList<Object> list = new ArrayList<Object>();
        Collections.addAll(list, objs);
        return join(delimiter, list);
    }
}

오브젝트 콜렉션을 사용하면 오브젝트를 문자열로 변환 할 필요가 없으므로 오브젝트 콜렉션이 더 효과적이라고 생각합니다.

10
Eric Normand

Apache commons StringUtils 클래스에는 조인 메소드가 있습니다.

8
Alejandro

Java 8

stringCollection.stream().collect(Collectors.joining(", "));
4
gstackoverflow

그리고 최소한의 것 (단지 문자열 조인을 위해 Apache Commons vs Guava를 프로젝트 종속성에 포함시키지 않으려는 경우)

/**
 *
 * @param delim : String that should be kept in between the parts
 * @param parts : parts that needs to be joined
 * @return  a String that's formed by joining the parts
 */
private static final String join(String delim, String... parts) {
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < parts.length - 1; i++) {
        builder.append(parts[i]).append(delim);
    }
    if(parts.length > 0){
        builder.append(parts[parts.length - 1]);
    }
    return builder.toString();
}
3
Thamme Gowda

StringBuilder 및 클래스 Separator 사용

StringBuilder buf = new StringBuilder();
Separator sep = new Separator(", ");
for (String each : list) {
    buf.append(sep).append(each);
}

구분 기호는 구분 기호를 래핑합니다. 구분 기호는 구분 기호의 toString 메서드에 의해 반환됩니다 (빈 문자열을 반환하는 첫 번째 호출이 아니라면).

Separator 클래스의 소스 코드

public class Separator {

    private boolean skipFirst;
    private final String value;

    public Separator() {
        this(", ");
    }

    public Separator(String value) {
        this.value = value;
        this.skipFirst = true;
    }

    public void reset() {
        skipFirst = true;
    }

    public String toString() {
        String sep = skipFirst ? "" : value;
        skipFirst = false;
        return sep;
    }

}
3
akuhn

자바의 StringBuilder 유형을 사용할 수 있습니다. StringBuffer도 있지만, 종종 불필요한 여분의 스레드 안전 로직을 포함합니다.

3
Kent Boogaart

Eclipse Collections 를 사용하는 경우 makeString() 또는 appendString()을 사용할 수 있습니다.

makeString()toString()과 비슷한 String 표현을 반환합니다.

그것은 세 가지 형식을 가지고있다.

  • makeString(start, separator, end)
  • makeString(separator) 기본값은 빈 문자열로 시작하고 끝납니다.
  • makeString()는 구분 기호를 ", "로 기본 설정합니다 (쉼표 및 공백).

코드 예 :

MutableList<Integer> list = FastList.newListWith(1, 2, 3);
assertEquals("[1/2/3]", list.makeString("[", "/", "]"));
assertEquals("1/2/3", list.makeString("/"));
assertEquals("1, 2, 3", list.makeString());
assertEquals(list.toString(), list.makeString("[", ", ", "]"));

appendString()makeString()과 비슷하지만 Appendable (예 : StringBuilder)에 추가되며 void입니다. 추가로 첫 번째 인수 인 Appendable을 갖는 동일한 세 가지 형식이 있습니다.

MutableList<Integer> list = FastList.newListWith(1, 2, 3);
Appendable appendable = new StringBuilder();
list.appendString(appendable, "[", "/", "]");
assertEquals("[1/2/3]", appendable.toString());

콜렉션을 Eclipse Collections 유형으로 변환 할 수없는 경우, 관련 어댑터로 어댑터를 채택하십시오.

List<Object> list = ...;
ListAdapter.adapt(list).makeString(",");

주의 : 나는 이클립스 콜렉션의 커미터이다.

2
Craig P. Motlin

Spring MVC를 사용한다면 다음 단계를 시도해 볼 수있다.

import org.springframework.util.StringUtils;

List<String> groupIds = new List<String>;   
groupIds.add("a");    
groupIds.add("b");    
groupIds.add("c");

String csv = StringUtils.arrayToCommaDelimitedString(groupIds.toArray());

결과는 a,b,c가됩니다.

2
Ankit Lalan

왜 당신 자신의 join () 메소드를 작성하지 않겠습니까? 그것은 Strings와 Delimiter String의 매개 변수 컬렉션으로 사용됩니다. 이 메서드 내에서 컬렉션을 반복하고 결과를 StringBuffer에 작성합니다.

2
Dave Costa

Java 5 변수 args를 사용하면 모든 문자열을 컬렉션이나 배열에 명시 적으로 채울 필요가 없습니다.

import junit.framework.Assert;
import org.junit.Test;

public class StringUtil
{
    public static String join(String delim, String... strings)
    {
        StringBuilder builder = new StringBuilder();

        if (strings != null)
        {
            for (String str : strings)
            {
                if (builder.length() > 0)
                {
                    builder.append(delim).append(" ");
                }
                builder.append(str);
            }
        }           
        return builder.toString();
    }
    @Test
    public void joinTest()
    {
        Assert.assertEquals("", StringUtil.join(",", null));
        Assert.assertEquals("", StringUtil.join(",", ""));
        Assert.assertEquals("", StringUtil.join(",", new String[0]));
        Assert.assertEquals("test", StringUtil.join(",", "test"));
        Assert.assertEquals("foo, bar", StringUtil.join(",", "foo", "bar"));
        Assert.assertEquals("foo, bar, x", StringUtil.join(",", "foo", "bar", "x"));
    }
}
1
Mark B

자바 8 네이티브 유형

List<Integer> example;
example.add(1);
example.add(2);
example.add(3);
...
example.stream().collect(Collectors.joining(","));

Java 8 사용자 정의 객체 :

List<Person> person;
...
person.stream().map(Person::getAge).collect(Collectors.joining(","));
1
Luis Aguilar

스프링 컨텍스트에있는 사람들은 StringUtils 클래스가 유용합니다.

다음과 같은 유용한 단축키가 많이 있습니다.

  • collectionToCommaDelimitedString (콜렉션 콜)
  • collectionToDelimitedString (콜렉션 콜, 문자열 delim)
  • arrayToDelimitedString (Object [] arr, String delim)

그리고 많은 다른 사람들.

이는 Java 8을 아직 사용하지 않고 이미 Spring 컨텍스트에있는 경우에 유용 할 수 있습니다.

나는 이것을 쉽게 더 쉽게 할 수있는 Collection 지원을 위해 Apache Commons (비록 좋지만)를 선호한다.

// Encoding Set<String> to String delimited 
String asString = org.springframework.util.StringUtils.collectionToDelimitedString(codes, ";");

// Decoding String delimited to Set
Set<String> collection = org.springframework.util.StringUtils.commaDelimitedListToSet(asString);
1
рüффп

StringBuilder 메서드를 사용하여 append 메서드를 사용하여 결과를 구성해야하지만 그렇지 않은 경우 Java에서 제공하는 솔루션만큼 좋습니다.

1
newdayrising

Ruby에서하는 것과 똑같은 작업을 Java에서하지 마십시오. 모든 조각을 배열에 추가 한 후에 만 ​​구분 기호로 구분 된 문자열을 생성합니까?

ArrayList<String> parms = new ArrayList<String>();
if (someCondition) parms.add("someString");
if (anotherCondition) parms.add("someOtherString");
// ...
String sep = ""; StringBuffer b = new StringBuffer();
for (String p: parms) {
    b.append(sep);
    b.append(p);
    sep = "yourDelimiter";
}

별도의 도우미 메서드에서 for 루프를 이동하고 StringBuffer 대신 StringBuilder를 사용할 수도 있습니다.

편집 : 추가 순서를 수정했습니다.

1
agnul

그래서 기본적으로 이런 식으로 :

public static String appendWithDelimiter(String original, String addition, String delimiter) {

if (original.equals("")) {
    return addition;
} else {
    StringBuilder sb = new StringBuilder(original.length() + addition.length() + delimiter.length());
        sb.append(original);
        sb.append(delimiter);
        sb.append(addition);
        return sb.toString();
    }
}
0
killdash10

이것이 실제로 더 좋은지는 모르겠지만 최소한 StringBuilder를 사용하고 있습니다. 약간 더 효율적일 수 있습니다.

매개 변수 구분을하기 전에 매개 변수 목록을 작성할 수 있다면 아래의 방법을 좀 더 일반적인 방법으로 사용할 수 있습니다.

// Answers real question
public String appendWithDelimiters(String delimiter, String original, String addition) {
    StringBuilder sb = new StringBuilder(original);
    if(sb.length()!=0) {
        sb.append(delimiter).append(addition);
    } else {
        sb.append(addition);
    }
    return sb.toString();
}


// A more generic case.
// ... means a list of indeterminate length of Strings.
public String appendWithDelimitersGeneric(String delimiter, String... strings) {
    StringBuilder sb = new StringBuilder();
    for (String string : strings) {
        if(sb.length()!=0) {
            sb.append(delimiter).append(string);
        } else {
            sb.append(string);
        }
    }

    return sb.toString();
}

public void testAppendWithDelimiters() {
    String string = appendWithDelimitersGeneric(",", "string1", "string2", "string3");
}
0
Mikezx6r

귀하의 접근 방식은 그렇게 나쁘지는 않지만 + 기호를 사용하는 대신 StringBuffer를 사용해야합니다. +에는 각각의 단일 작업에 대해 새로운 String 인스턴스가 생성된다는 단점이 있습니다. 문자열이 길어질수록 오버 헤드가 커집니다. 따라서 StringBuffer를 사용하는 것이 가장 빠른 방법입니다.

public StringBuffer appendWithDelimiter( StringBuffer original, String addition, String delimiter ) {
        if ( original == null ) {
                StringBuffer buffer = new StringBuffer();
                buffer.append(addition);
                return buffer;
        } else {
                buffer.append(delimiter);
                buffer.append(addition);
                return original;
        }
}

문자열 생성이 끝나면 반환 된 StringBuffer에서 toString ()을 호출하면됩니다.

0
Yaba
//Note: if you have access to Java5+, 
//use StringBuilder in preference to StringBuffer.  
//All that has to be replaced is the class name.  
//StringBuffer will work in Java 1.4, though.

appendWithDelimiter( StringBuffer buffer, String addition, 
    String delimiter ) {
    if ( buffer.length() == 0) {
        buffer.append(addition);
    } else {
        buffer.append(delimiter);
        buffer.append(addition);
    }
}


StringBuffer parameterBuffer = new StringBuffer();
if ( condition ) { 
    appendWithDelimiter(parameterBuffer, "elementName", "," );
}
if ( anotherCondition ) {
    appendWithDelimiter(parameterBuffer, "anotherElementName", "," );
}

//Finally, to return a string representation, call toString() when returning.
return parameterBuffer.toString(); 
0
MetroidFan2002

Dollar 를 사용하여 입력하는 것처럼 간단합니다 :

String joined = $(aCollection).join(",");

주의 : 배열 및 기타 데이터 형식에도 적용됩니다.

이행

내부적으로는 매우 정교한 트릭을 사용합니다.

@Override
public String join(String separator) {
    Separator sep = new Separator(separator);
    StringBuilder sb = new StringBuilder();

    for (T item : iterable) {
        sb.append(sep).append(item);
    }

    return sb.toString();
}

Separator 클래스는 처음 호출되었을 때만 빈 문자열을 반환하고 구분 기호를 반환합니다.

class Separator {

    private final String separator;
    private boolean wasCalled;

    public Separator(String separator) {
        this.separator = separator;
        this.wasCalled = false;
    }

    @Override
    public String toString() {
        if (!wasCalled) {
            wasCalled = true;
            return "";
        } else {
            return separator;
        }
    }
}
0
dfa

Rob Dickerson의 답변을 수정했습니다.

사용하기가 더 쉽습니다.

public static String join(String delimiter, String... values)
{
    StringBuilder stringBuilder = new StringBuilder();

    for (String value : values)
    {
        stringBuilder.append(value);
        stringBuilder.append(delimiter);
    }

    String result = stringBuilder.toString();

    return result.isEmpty() ? result : result.substring(0, result.length() - 1);
}
0
maXp

문자열 연결을 사용하는 대신 코드가 스레드되지 않은 경우 StringBuilder를 사용해야하고 그렇지 않은 경우 StringBuffer를 사용해야합니다.

0
Aaron

그래서 당신이 찾고있는 것 같은 느낌을 갖기 위해 할 수있는 몇 가지 일들 :

1) List 클래스를 확장하고 join 메소드를 추가하십시오. 조인 메소드는 단순히 조인 메소드에 매개 변수가 될 수있는 분리 문자를 연결하고 추가하는 작업을 수행합니다.

2) Java 7에서 Java에 확장 메소드를 추가하는 것처럼 보입니다. 특정 메소드를 클래스에 첨부 할 수 있습니다. 따라서이 조인 메소드를 작성하여 확장 메소드로 List 또는 심지어 to에 추가 할 수 있습니다 수집.

자바 7이 아직 나오지 않았기 때문에 해결책 1이 아마도 유일한 현실입니다. :)하지만 잘 작동합니다.

이 두 가지를 모두 사용하려면 평소처럼 모든 항목을 List 또는 Collection에 추가 한 다음 새 사용자 정의 메서드를 호출하여 해당 항목에 '가입'하십시오.

0
user13276

당신은 이것을 약간 복잡하게 만듭니다. 예제의 끝에서부터 시작해 보겠습니다.

String parameterString = "";
if ( condition ) parameterString = appendWithDelimiter( parameterString, "elementName", "," );
if ( anotherCondition ) parameterString = appendWithDelimiter( parameterString, "anotherElementName", "," );

String 대신 StringBuilder를 조금만 사용하면 다음과 같이됩니다.

StringBuilder parameterString = new StringBuilder();
if (condition) parameterString.append("elementName").append(",");
if (anotherCondition) parameterString.append("anotherElementName").append(",");
...

작업이 끝나면 (다른 조건도 확인해야한다고 가정) 다음과 같은 명령으로 꼬리표를 제거하십시오.

if (parameterString.length() > 0) 
    parameterString.deleteCharAt(parameterString.length() - 1);

마지막으로 원하는 문자열을 가져옵니다.

parameterString.toString();

두 번째 호출에서 ","를 대체하여 아무 것도 설정할 수있는 일반 구분 기호 문자열을 추가 할 수 있습니다. 추가 할 필요가 있음을 알고있는 목록이 있다면 (조건부가 아닌)이 코드를 문자열 목록을 취하는 메서드 안에 넣을 수 있습니다.

0
cjw2600

Izb에서 버전의 약간의 개선 [속도] :

public static String join(String[] strings, char del)
{
    StringBuilder sb = new StringBuilder();
    int len = strings.length;

    if(len > 1) 
    {
       len -= 1;
    }else
    {
       return strings[0];
    }

    for (int i = 0; i < len; i++)
    {
       sb.append(strings[i]).append(del);
    }

    sb.append(strings[i]);

    return sb.toString();
}
0
java al

개인적으로는 로깅 목적으로 다음과 같은 간단한 솔루션을 사용합니다.

List lst = Arrays.asList("ab", "bc", "cd");
String str = lst.toString().replaceAll("[\\[\\]]", "");
0
Philipp Grigoryev

다음과 같이해볼 수 있습니다 :

StringBuilder sb = new StringBuilder();
if (condition) { sb.append("elementName").append(","); }
if (anotherCondition) { sb.append("anotherElementName").append(","); }
String parameterString = sb.toString();
0
martinatime