sourcecode

Java에서 구분된 항목의 문자열을 작성하는 가장 좋은 방법은 무엇입니까?

copyscript 2022. 8. 27. 10:10
반응형

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", "," );

여러 가지 조건이 있기 때문에 이것이 그다지 효율적이지 않다는 것을 깨달았지만, 저는 최적화보다는 명확성을 추구했습니다.

Ruby에서는, 대신, 이것과 같은 것을 할 수 있습니다.그것은 훨씬 우아하게 느껴집니다.

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

그러나 Java에는 join 명령어가 없기 때문에 그에 상응하는 것을 찾을 수 없었습니다.

Java에서 이를 수행하는 가장 좋은 방법은 무엇일까요?

Java 8 이전 버전:

Apache의 Commons lang은 여기서 당신의 친구입니다.Ruby에서 참조하는 것과 매우 유사한 결합 방법을 제공합니다.

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


Java 8:

8을 통해 가능StringJoiner ★★★★★★★★★★★★★★★★★」String.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"

java.util에서 동작하는 join 스타일의 유틸리티 메서드를 작성할 수 있습니다.리스트

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, ",");

Android의 경우 Commons의 String Utils 클래스는 이용할 수 없기 때문에 이를 위해 사용하였습니다.

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

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

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의 String Utilities에 대한 기사입니다.

Java 8에서는 다음을 사용할 수 있습니다.

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

Stream API의 예에 대해서는 이 답변도 참조해 주십시오.

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

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

목록에 null이 있는 경우 다음을 사용할 수 있습니다.

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

는 프리픽스 및 서픽스도 지원합니다.

list.stream().map(String::valueOf)
        .collect(Collectors.joining(delimiter, prefix, suffix));

일반화할 수 있지만, Java에는 가입이 없습니다.

이게 더 잘 될 수도 있어요.

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();
}

!("변환 가능한 문자 시퀀스")에 기반한 접근 방식을 사용합니다.")

말씀하신 대로 모든 문자열 연결로 인해 문자열이 생성되고 있습니다. StringBuilder안 그럴 거야

★★★★StringBuilder대신? 에서StringBuilder★★★★★★★★★★★★★★★★★★:

가능한 경우 이 클래스는 대부분의 구현에서 더 빠르기 때문에 StringBuffer보다 우선적으로 사용할 것을 권장합니다.

이치노좋은 가입 시설이 있습니다.
http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?com/google/common/base/Join.htmlhttp.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);
    }
}

오브젝트 컬렉션에 가입하기 전에 오브젝트를 문자열로 변환할 필요가 없기 때문에 오브젝트 컬렉션에 더 적합하다고 생각합니다.

Apache Commons StringUtils 클래스에는 Join 메서드가 있습니다.

자바 8

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

Java 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(","));

와 String Builder 를 합니다.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;
    }

}

이 경우 Java 유형을 사용할 수 있습니다.그리고 또StringBuffer 불필요한 이 포함되어 있습니다.

최소한의 것(문자열 결합을 위해 Apache Commons 또는 Gauva를 프로젝트 종속성에 포함시키고 싶지 않은 경우)

/**
 *
 * @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();
}

join() 메서드를 직접 써보는 것은 어떨까요?Strings와 딜리미터 String의 파라미터 집합으로 사용됩니다.메서드 내에서 수집을 반복하고 결과를 StringBuffer로 빌드합니다.

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

이클립스 컬렉션을 사용하는 경우makeString() ★★★★★★★★★★★★★★★★★」appendString().

makeString()를 반환하다String " "와 유사, 「」과 같은 표현.toString().

그것은 세 가지 형태가 있다.

  • makeString(start, separator, end)
  • makeString(separator) strings 。
  • 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이3가지 형식이 , 첫추가되어 있습니다. 이 명령어에는 동일한 3가지 형식이 있으며 첫 번째 인수인 부록이 추가됩니다.

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(",");

주의: 저는 이클립스 컬렉션의 커밋입니다.

도 아마 '어울릴 것 같다'를 할 것 같아요.StringBuilderappend이 방법을 사용하면 Java가 제공하는 솔루션만큼 효과적입니다.

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";
}

다른 도우미 방식으로 루프를 이동하거나 StringBuffer 대신 StringBuilder를 사용할 수도 있습니다.

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

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

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"));
    }
}

Spring 컨텍스트에 있는 사용자에게는 String Utils 클래스도 유용합니다.

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

  • collection To Comma Delimited String(컬렉션 콜)
  • collection To Delimited String (컬렉션 coll, 문자열 구분자)
  • arrayToDelimitedString(개체[]arr, 문자열 구분자)

그리고 다른 많은 것들도요.

이는 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);

다음과 같은 작업을 수행할 수 있습니다.

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

기본적으로 다음과 같습니다.

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();
    }
}

이것이 실제로 더 나은지는 모르겠지만 적어도 String Builder를 사용하고 있기 때문에 조금 더 효율적일 수 있습니다.

아래는 매개 변수 구분 작업을 수행하기 전에 매개 변수 목록을 작성할 수 있는 보다 일반적인 방법입니다.

// 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");
}

이 방법은 나쁘지 않지만 + 기호를 사용하는 대신 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;
        }
}

스트링 작성을 완료한 후 반환된 String Buffer에서 String()을 호출하기만 하면 됩니다.

문자열 연결을 사용하는 대신 코드가 스레드화되지 않은 경우 String Builder를, 스레드화되지 않은 경우 String Buffer를 사용해야 합니다.

당신은 이 일을 필요 이상으로 복잡하게 만들고 있어요.먼저 예제의 끝부분부터 시작합시다.

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

String이 아닌 String Builder를 사용하는 방법이 약간 변경되면 다음과 같이 됩니다.

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();

또한 두 번째 호출에서 " "를 대체하여 임의의 값으로 설정할 수 있는 일반 딜리미터 문자열로 추가할 수도 있습니다.추가할 필요가 있는 것(무조건) 목록이 있는 경우 문자열 목록을 사용하는 메서드에 이 코드를 넣을 수 있습니다.

//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(); 

찾고 있는 것 같은 느낌을 받기 위해 다음과 같은 몇 가지 작업을 수행할 수 있습니다.

1) 목록 클래스 확장 - 여기에 결합 메서드를 추가합니다.join 메서드는 단순히 딜리미터(join 메서드의 파라미터일 수 있음)를 연결하고 추가하는 작업을 수행합니다.

2) Java 7은 java에 확장 메서드를 추가할 것 같습니다.이것에 의해, 특정의 메서드를 클래스에 부가하는 것만으로, 그 join 메서드를 작성해, List 또는 Collection에 확장 메서드로 추가할 수 있습니다.

Java 7이 아직 출시되지 않았기 때문에 솔루션 1은 아마도 현재 유일한 현실적인 솔루션일 것입니다:) 그러나 이 솔루션은 정상적으로 작동합니다.

이 두 가지를 모두 사용하려면 평소와 같이 목록 또는 컬렉션에 모든 항목을 추가한 다음 새로운 사용자 지정 메서드를 호출하여 '참가'하면 됩니다.

언급URL : https://stackoverflow.com/questions/63150/whats-the-best-way-to-build-a-string-of-delimited-items-in-java

반응형