我想将字符串连接在一起,但是这样做时经常会出现逗号过多的情况,因此我需要删除该逗号。在这段代码中,我使用substring删除了最后两个字符。

如何使它变得更加美观?

List<String> paramList = new ArrayList<String>( );
paramList.add( "param1" );
paramList.add( "param2" );

StringBuilder result = new StringBuilder();
for ( String p : paramList )
{
  result.append( p ).append( ", " );
}

String withoutLastComma = result.substring( 0, result.length( ) - ", ".length( ) );
System.err.println( withoutLastComma );


评论

而不是添加逗号然后删除它,而不是将逗号添加到最后一项呢?使用基于索引的方法会很好。 for(int i = 0; i
交换追加的顺序-result.append(“,”).append(p)-使您可以使用更简单的提取:result.substring(“,” .length())

显然,下面是一个新的最佳答案:codereview.stackexchange.com/a/58588/23451

如果您不想使用外部库,则您的解决方案将提供最佳的可读性imo。在所有可能的情况下,我总是使用这一方法(尽管通常在此处不适合使用result.deleteCharAt(result.length))
与其为此目的使用任何外部库,不如使用Java 8中提供的Streams库。使用此方法-paramList.stream()。map(String :: valueOf).collect(Collectors.joining());

#1 楼

可以使用诸如StringUtil.join之类的字符串实用程序方法来连接数组或集合对象中的元素。请查阅StringUtil API的StringUtil.join条目。

例如:

StringUtils.join(["a", "b", "c"], "--")  // => "a--b--c"


评论


\ $ \ begingroup \ $
我不明白这种简单的方法可以证明添加库的合理性。
\ $ \ endgroup \ $
–阿萨斯
2011年4月24日23:04

\ $ \ begingroup \ $
@Wes:如果您正在使用重要的生产代码,并且不想承担不必要的依赖项(或者有不使用外部库的政策要求),并且有时间编写/测试/调试/优化自己的代码方法,然后一定要自己动手。我假设OP正在为非关键任务寻找简单的解决方案。
\ $ \ endgroup \ $
– Adeel Zafar Soomro
11年4月25日在13:04

\ $ \ begingroup \ $
Guava有Joiner:Joiner.on(“,”).join(paramList)。它提供了有用的选项,例如也跳过空值。糟糕,已经是答案。
\ $ \ endgroup \ $
– David Harkness
2014年5月18日21:00



\ $ \ begingroup \ $
Java 8现在还具有String.join()方法,请参见下面的答案。
\ $ \ endgroup \ $
– Kolargol00
2014年7月31日下午3:18

\ $ \ begingroup \ $
@Athas:通过对每个新的实用程序方法重复该语句,最终得到该库所有方法的自制副本。而且我什至不要求您为“如此简单的事情”编写的单元测试。
\ $ \ endgroup \ $
– Bananweizen
16年11月13日在18:21

#2 楼

for ( String p : paramList )
{
  if (result.length() > 0) result.append( ", " );
  result.append( p );
}


评论


\ $ \ begingroup \ $
我一直使用这种方法。很明显。在任何语言中,它看起来几乎都是相同的。我从未见过额外的比较在每次迭代中有足够的权重来发挥作用。
\ $ \ endgroup \ $
– hometoast
2011年4月19日在12:44

\ $ \ begingroup \ $
我在.NET中使用了此解决方案,直到发现该字符串具有静态的Join方法。我很惊讶Java没有内置类似的东西。
\ $ \ endgroup \ $
– Kyralessa
2011年5月20日下午3:40

\ $ \ begingroup \ $
我喜欢这个答案实际上如何显示解决问题的方法,而不仅仅是通过使用库方法来避免。并不是说使用库方法是错误的,只是您仍然不知道它是如何实际解决的。
\ $ \ endgroup \ $
–安德鲁·哈格纳(Andrew Hagner)
13年3月20日在17:45

\ $ \ begingroup \ $
这正是StringUtils.join似乎正在做的事情。
\ $ \ endgroup \ $
– would_like_to_be_anon
14年7月22日在16:49

#3 楼

Java 8提供了String.join()方法,因此您无需依赖外部库就可以做到这一点。

List<String> paramList = new ArrayList<String>();
paramList.add("param1");
paramList.add("param2");

String withoutLastComma = String.join(", ", paramList);


评论


\ $ \ begingroup \ $
这个答案正在meta上讨论
\ $ \ endgroup \ $
–rolfl
2014年7月31日下午3:40

\ $ \ begingroup \ $
感谢@rolfl的解释。抱歉,我没有注意到这个问题太老了。 :(
\ $ \ endgroup \ $
– Kolargol00
2014年7月31日在9:09

\ $ \ begingroup \ $
值得一提的是,您也可以使用Collectors.joining()。
\ $ \ endgroup \ $
–Vogel612♦
15年10月20日在15:18

\ $ \ begingroup \ $
该答案有一个建议的编辑,被拒绝了,但可能是一个可行的解决方案-它似乎具有相同的输出
\ $ \ endgroup \ $
–SᴀᴍOnᴇᴌᴀ
6月3日下午16:31

#4 楼

我相信最好知道如何编写它,然后使用一个库。我通常更喜欢在循环之前进行检查,从而避免在循环中每次都要进行检查:

int size = paramList.size();
if (size > 0) {
    result.append(paramList.get(0));
    for (int i = 1; i < size; ++i) {
        result.append(", ").append(paramList.get(i));
    }
}


评论


\ $ \ begingroup \ $
现在,您有两行,而不是一行,将您的项目附加到结果中。这是坏风格。为了简单起见,请不要重复行。这将使正确无误地维护此代码变得更加困难。
\ $ \ endgroup \ $
– klaar
16 Dec 5'在10:54



#5 楼

一种可能的方法是使用Google Guava库中的Joiner:

result = Joiner.on(", ").join(paramList);


#6 楼

奇怪的是,到目前为止,没有人提到迭代器方法。

就这样:

public static <E> String join(Iterable<E> iterable, String delim) {
    Iterator<E> iterator = iterable.iterator();
    if (!iterator.hasNext()) {
        return "";
    }

    StringBuilder builder = new StringBuilder(iterator.next().toString());
    while (iterator.hasNext()) {
        builder.append(delim).append(iterator.next().toString());
    }

    return builder.toString();
}


不会弄乱索引,子字符串等。让我们来使用它: br />
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
System.out.println(join(list, ", "));


评论


\ $ \ begingroup \ $
因为StringBuilder会自动进行操作,所以不需要在元素上调用toString()。另外,您正冒着NPE的风险。
\ $ \ endgroup \ $
– David Harkness
2014年5月18日21:10



#7 楼

我使用的是一个变量,我将其初始化为空,然后在循环中进行设置。

List<String> paramList = new ArrayList<String>( );
paramList.add("param1");
paramList.add("param2");

String separator = "";

StringBuilder result = new StringBuilder();
for (String p : paramList)
{
    result.append(separator)
    result.append(p);
    separator = ", ";
}

System.err.println(result.toString());


评论


\ $ \ begingroup \ $
我经常将此语言用于没有“ join”功能的语言,例如PL / SQL ...
\ $ \ endgroup \ $
–安东尼·西蒙(Anthony Simmon)
2013年12月4日15:16

#8 楼

这里有几个替代选项-尽管几乎没有问题,但所有这些都只能解决使意图清晰化的问题。 />
String withoutLastComma = result.substring(0, result.lastIndexOf(","));


或者只是稍微重构一下,可能更能说明问题:

StringBuilder result = new StringBuilder();
for (int i = 0; i < paramList.size(); i++)
{           
    result.append(paramList.get(i));
    if (i + 1 != paramList.size())
        result.append(", ");
}
System.err.println(result);


或者,最后,使用在提供的其他答案中链接的字符串实用程序库;虽然,这样做的想法使人想到了“大锤砸开螺母”一词,但根据您需要执行的其他操作,它可能是合理的。

评论


\ $ \ begingroup \ $
这使代码更加复杂。用for语句替换foreach会使它更加复杂。但是,您的解决方案有效且正确,但是您必须确保不会带来额外的复杂性。
\ $ \ endgroup \ $
– Gertjan
2011年4月19日在12:23

\ $ \ begingroup \ $
我认为,这样琐碎的结构中的复杂性远远没有达到(尽管从“更复杂”的角度来理解您来自何处)-对于日常工作而言,这是显而易见的,也是不言而喻的。专业程序员(IMO)。我认为,即使仅以下原始命令也应进行此类更改:(0,result.length()-“,” .length());并且,感谢您的输入。 :)
\ $ \ endgroup \ $
–格兰特·托马斯(Grant Thomas)
2011年4月19日在12:27



\ $ \ begingroup \ $
对于这个示例,您是正确的。但是,想象一下有几个嵌套循环的场景。在这种情况下,您会得到类似result [i] .result [j] .result [k]的信息。在那些情况下,foreach可能是一个更具可读性的解决方案,因为很容易犯一些小错误,例如使用1代替i或将i,j&k变量混合。
\ $ \ endgroup \ $
– Gertjan
2011年4月20日在8:08

\ $ \ begingroup \ $
@Gertjan:我同意,幸运的是我们不在这种情况下。 ;)
\ $ \ endgroup \ $
–格兰特·托马斯(Grant Thomas)
2011年4月20日在8:36



#9 楼

我喜欢这种技术:

private String join(Iterable<?> items, String sep) {
    Iterator<?> iter = items.iterator();
    if (!iter.hasNext()) {
        return "";
    }

    StringBuilder builder = new StringBuilder();
    builder.append(iter.next());
    while (iter.hasNext()) {
        builder.append(sep).append(iter.next());
    }

    return builder.toString();
}


我喜欢的是循环内没有浪费的if条件。与之配套的测试:

@Test
public void testEmptyCollection() {
    Assert.assertTrue(join(Collections.emptyList(), ", ").isEmpty());
}

@Test
public void testJoinSingleItem() {
    String item = "hello";
    Assert.assertEquals(item, join(Collections.singletonList(item), ", "));
}

@Test
public void testJoinTwoItems() {
    Integer item1 = 4;
    Integer item2 = 9;
    String sep = ", ";
    String expected = item1 + sep + item2;
    Assert.assertEquals(expected, join(Arrays.asList(item1, item2), sep));
}


评论


\ $ \ begingroup \ $
然后,您会喜欢上面的Alexey的回答。 ;)
\ $ \ endgroup \ $
– David Harkness
2014年5月18日在21:12

\ $ \ begingroup \ $
啊,答案太多了,我忽略了那个答案。通常,我只会在评论中留下一些建议,而不是一个完整的答案。现在为时已晚,无论如何,我还是要保留这个,因为我添加了一些小附加功能。
\ $ \ endgroup \ $
– janos
14年5月18日在21:46



#10 楼

String listString = Arrays.toString(paramList.toArray());
System.err.println( listString );


返回:对于空对象。如果您只想重新实现Arrays.toString()方法,也非常简单。
删除括号:

[param1, param2]


#11 楼

惊讶的是没有人提供了单元测试规范:


有用的结果应该包含max(0, paramList.length() - 1)逗号。
如果列表为空,那么可靠的解决方案不应抛出IndexOutOfBoundsException
有效的解决方案将提供实际的StringBuilder容量估算值。

如果任何参数包含逗号,结果可能会产生误导或无用。 Java8 String.join应该经过重新设计,以在编译时标记这种“定界符冲突”的可能性,并且仅接受要联接的字符串,这些字符串之后可以再次拆分,因为它们已经被转义或加引号,或者不包含或不能包含定界符。 >

评论


\ $ \ begingroup \ $
这个(旧的)答案存在一些问题:1.这将大大降低性能。 2.这通常是不必要的。 3.“可以再次拆分”可能依赖于启发法,这可能导致随机错误。 4.不一定有解决标记错误的好方法。
\ $ \ endgroup \ $
–所罗门·乌科(Solomon Ucko)
18/12/31在19:26

#12 楼

如果您使用的是Java 8,则可以像这样使用StringJoiner:

StringJoiner sj = new StringJoiner(",");
for ( String p : paramList )
{
  sj.add(p);
}


#13 楼

作为手动遍历循环来构造列表的逗号分隔内容的替代方法,您可以利用列表的toString()方法以及substringString.方法

String contents = paramList.toString(); //returns [param 1, param2]

//remove `[` and `]`
System.out.println(contents.substring(1, contents.length()-1));


#14 楼

这是delete方法的一种更有效的替代方法,该方法仅中断StringBuilder而无需询问字符或位置:

@Test
public void appendTest (){
    final String comma = ", ";

    List<String> paramList = new ArrayList<>();
    paramList.add( "param1" );
    paramList.add( "param2" );

    StringBuilder result = new StringBuilder();
    for (String s : paramList) {
        result.append(s).append(comma);
    }
    if (!paramList.isEmpty()){
        result.setLength(result.length() - comma.length());
    }

    System.out.println(result);

}