Удалить последнюю запятую
Я хочу объединить строки вместе, но при этом часто случается, что запятая слишком много, и поэтому мне нужно удалить эту запятую. В этом коде я использую подстроку 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 );
14 ответов
Можно использовать методы командной строки, такие как StringUtil.join
, чтобы объединить элементы в массиве или в объект коллекции. Обратитесь к API-интерфейсу StringUtil StringUtil.join
.
Например:
StringUtils.join(["a", "b", "c"], "--") // => "a--b--c"
for ( String p : paramList )
{
if (result.length() > 0) result.append( ", " );
result.append( p );
}
Java 8 предоставляет метод String.join()
, поэтому вы можете сделать это, не зависимо от внешней библиотеки.
List<String> paramList = new ArrayList<String>();
paramList.add("param1");
paramList.add("param2");
String withoutLastComma = String.join(", ", paramList);
Я считаю, что лучше знать, как записать его , а затем использовать библиотеку. Обычно я предпочитаю проверять цикл перед , тем самым избегая необходимости проверять каждый раз в цикле:
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));
}
}
Одним из возможных способов является использование Joiner из Google Guava library :
result = Joiner.on(", ").join(paramList);
Странно, что до сих пор никто не упомянул об итераторном подходе.
Итак, вот оно:
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();
}
Не вмешиваться в индексы, подстроку и т. д. и т. д.
И давайте использовать его:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
System.out.println(join(list, ", "));
Update:
NPE-безопасный подход мог бы избежать использования toString()
в next()
(спасибо @David Harkness):
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());
while (iterator.hasNext()) {
builder.append(delim).append(iterator.next());
}
return builder.toString();
}
То, что я использую, является переменной, которую я инициализирую как пустой, а затем устанавливаю внутри цикла.
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());
Несколько альтернативных вариантов здесь - любой из таких может просто решить только четкие намерения, хотя это вряд ли проблема.
Это может быть немного яснее, хотя и не очень, используя lastIndexOf
:
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);
Или, наконец, используйте библиотеку строк, связанную с другими предоставленными ответами; хотя мысль о том, что это делает, означает, что кузнец 'взломает орех' , но он вполне может быть оправдан в зависимости от того, какие другие операции вам нужно выполнить.
Мне нравится эта техника:
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));
}
String listString = Arrays.toString(paramList.toArray());
System.err.println( listString );
Вернется:
[param1, param2]
Это имеет дополнительное преимущество использования метода String.valueOf (object), который будет печатать «null» в случае нулевых объектов. Метод Arrays.toString () также довольно прямолинейный, если вы просто хотите его переопределить. Удаление скобок:
int iMax = paramList.size() - 1;
if (iMax == -1) {
return "";
}
String[] params = paramList.toArray();
StringBuilder b = new StringBuilder();
for (int i = 0; ; i++) {
String param = params[i];
b.append(param);
if (i == iMax) {
return b.toString();
}
b.append(", ");
}
Удивленный никто не внес вклад в спецификацию единичного теста:
- полезный результат должен содержать запятые
max(0, paramList.length() - 1)
. - надежное решение не должно бросать
IndexOutOfBoundsException
, если список пуст. - эффективное решение обеспечит реалистичную оценку емкости
StringBuilder
.
Результат может быть ошибочным или бесполезным, если какой-либо параметр содержит запятую. Java8 String.join
должен быть изменен для того, чтобы отмечать эту возможность «конфликтующее разграничение» во время компиляции и принимать только привязываемые строки, которые впоследствии могут быть разделены, потому что они уже были экранированы или процитированы или не выполняются или не может содержать разделитель.
В качестве альтернативы ручного перехода через цикл для создания разделенного запятыми содержимого списка, вы можете использовать метод List toString()
List вместе с substring
метод String.
String contents = paramList.toString(); //returns [param 1, param2]
//remove `[` and `]`
System.out.println(contents.substring(1, contents.length()-1));
Вот более эффективная альтернатива методу 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);
}
Если вы используете java 8, вы можете использовать StringJoiner :
StringJoiner sj = new StringJoiner(",");
for ( String p : paramList )
{
sj.add(p);
}