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 );
#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()
方法以及substring
的String.
方法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);
}
评论
而不是添加逗号然后删除它,而不是将逗号添加到最后一项呢?使用基于索引的方法会很好。 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());