Как добавить символ новой строки для всех строк, кроме последней? - PullRequest
31 голосов
/ 15 января 2009

Я перебираю HashMap (см. мой предыдущий вопрос для более подробной информации) и строю строку, состоящую из данных, содержащихся в карте. Для каждого элемента у меня будет новая строка, но для самого последнего элемента я не хочу новую строку. Как мне этого добиться? Я думал, что смогу проверить, последняя запись или нет, но я не уверен, как на самом деле это сделать.

Спасибо!

Ответы [ 15 ]

70 голосов
/ 15 января 2009

Измените ваш мыслительный процесс с «добавить разрыв строки все, кроме последнего раза» на «добавить разрыв строки все, кроме первого раза»:

boolean first = true;
StringBuilder builder = new StringBuilder();

for (Map.Entry<MyClass.Key,String> entry : data.entrySet()) {
    if (first) {
        first = false;
    } else {
        builder.append("\n"); // Or whatever break you want
    }
    builder.append(entry.key())
           .append(": ")
           .append(entry.value());
}
68 голосов
/ 15 января 2009

один метод (с извинениями Джону Скиту за то, что он позаимствовал часть его Java-кода):

StringBuilder result = new StringBuilder();

string newline = "";  
for (Map.Entry<MyClass.Key,String> entry : data.entrySet())
{
    result.append(newline)
       .append(entry.key())
       .append(": ")
       .append(entry.value());

    newline = "\n";
}
13 голосов
/ 16 января 2009

А как насчет этого?

StringBuilder result = new StringBuilder();

for(Map.Entry<MyClass.Key,String> entry : data.entrySet())
{
    builder.append(entry.key())
       .append(": ")
       .append(entry.value())
       .append("\n");
}

return builder.substring(0, builder.length()-1);

Обязательные извинения и спасибо Джону и Джоэлу за «заимствование» из их примеров.

9 голосов
/ 15 января 2009

Обычно для такого рода вещей я использую apache-commons-lang StringUtils # join . Хотя написать все эти виды служебных функций не сложно, всегда лучше повторно использовать существующие проверенные библиотеки. Apache-commons полна полезных вещей вроде этого!

4 голосов
/ 16 января 2009

Если вы используете итератор вместо for ... каждый ваш код может выглядеть так:

StringBuilder builder = new StringBuilder();

Iterator<Map.Entry<MyClass.Key, String>> it = data.entrySet().iterator();

while (it.hasNext()) {
    Map.Entry<MyClass.Key, String> entry = it.next();

    builder.append(entry.key())
    .append(": ")
    .append(entry.value());

    if (it.hasNext()) {
        builder.append("\n");
    }
}
3 голосов
/ 25 ноября 2010

Это, наверное, лучший пример ...

final StringBuilder buf = new StringBuilder();
final String separator = System.getProperty("line.separator"); // Platform new line
for (Map.Entry<MyClass.Key,String> entry: data.entrySet()) {
    builder.append(entry.key())
       .append(": ")
       .append(entry.value())
       .append(separator);
}
// Remove the last separator and return a string to use.
// N.b. this is likely as efficient as just using builder.toString() 
// which would also copy the buffer, except we have 1 char less 
// (i.e. '\n').
final String toUse = builder.substring(0, builder.length()-separator.length()-1);
2 голосов
/ 13 мая 2011

Одним из решений является создание пользовательской оболочки для StringBuilder. Он не может быть расширен, поэтому требуется обертка.

public class CustomStringBuilder {

final String separator = System.getProperty("line.separator");

private StringBuilder builder = new StringBuilder();

public CustomStringBuilder appendLine(String str){
    builder.append(str + separator);
    return this;
}

public CustomStringBuilder append(String str){
    builder.append(str);
    return this;
}

public String toString() {
    return this.builder.toString();
}

}

Реализация такая:

CustomStringBuilder builder = new CustomStringBuilder();

//iterate over as needed, but a wrapper to StringBuilder with new line features.

builder.appendLine("data goes here");
return builder.toString();

У этого есть некоторые недостатки:

  • Написание кода, который обычно не ориентирован на «домен / бизнес»
  • Не используется стандартное решение с открытым исходным кодом, например: StringUtils.join
  • Вынужден поддерживать класс, заключающий в себе класс JDK, который является окончательным и, следовательно, обновления требуют длительного срока.

Я выбрал решение StringUtils.join для итерации по коллекциям и даже для создания в коде облегченных шаблонов методов сборки.

2 голосов
/ 16 января 2009

Вот моя краткая версия, в которой вместо дополнительной переменной используется свойство длины StringBuilder:

StringBuilder builder = new StringBuilder();

for (Map.Entry<MyClass.Key,String> entry : data.entrySet())
{
    builder.append(builder.length() > 0 ? "\n" : "")
           .append(entry.key())
           .append(": ")
           .append(entry.value());
}

(Приношу извинения и спасибо Джону и Джоэлу за «заимствование» из их примеров.)

1 голос
/ 15 января 2009

Не уверен, что это лучше, но это проще сделать:

перебирает все значения и обычно добавляет \ n в буфер строк. Затем сделайте что-то вроде этого

sb.setLength(sb.length()-1); 
1 голос
/ 15 января 2009

Предполагая, что ваш цикл foreach проходит через файл, просто добавьте новую строку в каждую строку и удалите последнюю новую строку при выходе из цикла.

...