Многострочная строка Java

исходя из Perl, я уверен, что отсутствует средство "здесь-документ" для создания многострочной строки в исходном коде:

$string = <<"EOF"  # create a three-line string
text
text
text
EOF

в Java у меня должны быть громоздкие кавычки и знаки плюса на каждой строке, когда я объединяю свою многострочную строку с нуля.

какие-то лучшие альтернативы? Определите мою строку в файле свойств?

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

редактировать: уточнить мой вопрос, я не беспокоюсь о производительности вообще. Я обеспокоен ремонтопригодностью и проблемами дизайна.

30 ответов


Стивен Коулборн создал предложение для добавления нескольких строк в Java 7.

кроме того, Groovy уже имеет поддержку многострочные строки.


похоже, вы хотите сделать многострочный литерал, который не существует в Java.

вашей лучшей альтернативой будут строки, которые просто +'D вместе. Некоторые другие параметры, упомянутые людьми (StringBuilder, String.строка формата.join) было бы предпочтительнее, если бы вы начали с массива строк.

рассмотрим следующий пример:

String s = "It was the best of times, it was the worst of times,\n"
         + "it was the age of wisdom, it was the age of foolishness,\n"
         + "it was the epoch of belief, it was the epoch of incredulity,\n"
         + "it was the season of Light, it was the season of Darkness,\n"
         + "it was the spring of hope, it was the winter of despair,\n"
         + "we had everything before us, we had nothing before us";

и StringBuilder:

String s = new StringBuilder()
           .append("It was the best of times, it was the worst of times,\n")
           .append("it was the age of wisdom, it was the age of foolishness,\n")
           .append("it was the epoch of belief, it was the epoch of incredulity,\n")
           .append("it was the season of Light, it was the season of Darkness,\n")
           .append("it was the spring of hope, it was the winter of despair,\n")
           .append("we had everything before us, we had nothing before us")
           .toString();

Versus String.format():

String s = String.format("%s\n%s\n%s\n%s\n%s\n%s"
         , "It was the best of times, it was the worst of times,"
         , "it was the age of wisdom, it was the age of foolishness,"
         , "it was the epoch of belief, it was the epoch of incredulity,"
         , "it was the season of Light, it was the season of Darkness,"
         , "it was the spring of hope, it was the winter of despair,"
         , "we had everything before us, we had nothing before us"
);

Против Java8 String.join():

String s = String.join("\n"
         , "It was the best of times, it was the worst of times,"
         , "it was the age of wisdom, it was the age of foolishness,"
         , "it was the epoch of belief, it was the epoch of incredulity,"
         , "it was the season of Light, it was the season of Darkness,"
         , "it was the spring of hope, it was the winter of despair,"
         , "we had everything before us, we had nothing before us"
);

если вы хотите новую строку для вашей конкретной системы, вам либо нужно использовать System.getProperty("line.separator"), или вы можете использовать %n на String.format.

другой вариант-поставить ресурс в текстовый файл, и просто прочитать содержимое этого файла. Это было бы предпочтительнее для очень больших строк, чтобы избежать вздутия файлы классов.


в Eclipse если вы включите опцию "Escape text при вставке в строковый литерал" (в настройках > Java > Editor > Typing) и вставьте многострочную строку с кавычками, она автоматически добавит " и \n" + для всех ваших линий.

String str = "paste your text here";

Это старый поток, но новое довольно элегантное решение (с одним недостатком) - использовать пользовательскую аннотацию.

проверка:http://www.adrianwalker.org/2011/12/java-multiline-string.html

Edit: вышеуказанный URL, кажется, сломан. Проект, вдохновленный этой работой, размещен на GitHub:

https://github.com/benelog/multiline

public final class MultilineStringUsage {

  /**
  <html>
    <head/>
    <body>
      <p>
        Hello<br/>
        Multiline<br/>
        World<br/>
      </p>
    </body>
  </html>
  */
  @Multiline
  private static String html;

  public static void main(final String[] args) {
    System.out.println(html);
  }
}

недостатком является то, что вам нужно активировать соответствующий (предоставленный) процессор аннотаций.

и вам, вероятно, придется настроить Eclipse, чтобы не переформатировать автоматически ваши комментарии Javadoc.

Это может показаться странным (комментарии Javadoc не предназначены для встраивания ничего, кроме комментариев), но поскольку это отсутствие многострочной строки в Java действительно раздражает в конце концов, я считаю это наименее худшим решением.


другим вариантом может быть сохранение длинных строк во внешнем файле и чтение файла в строку.


это то, что вы должны никогда использовать, не думая о том, что он делает. Но для одноразовых скриптов я использовал это с большим успехом:

пример:

    System.out.println(S(/*
This is a CRAZY " ' ' " multiline string with all sorts of strange 
   characters!
*/));

код:

// From: http://blog.efftinge.de/2008/10/multi-line-string-literals-in-java.html
// Takes a comment (/**/) and turns everything inside the comment to a string that is returned from S()
public static String S() {
    StackTraceElement element = new RuntimeException().getStackTrace()[1];
    String name = element.getClassName().replace('.', '/') + ".java";
    StringBuilder sb = new StringBuilder();
    String line = null;
    InputStream in = classLoader.getResourceAsStream(name);
    String s = convertStreamToString(in, element.getLineNumber());
    return s.substring(s.indexOf("/*")+2, s.indexOf("*/"));
}

// From http://www.kodejava.org/examples/266.html
private static String convertStreamToString(InputStream is, int lineNum) {
    /*
     * To convert the InputStream to String we use the BufferedReader.readLine()
     * method. We iterate until the BufferedReader return null which means
     * there's no more data to read. Each line will appended to a StringBuilder
     * and returned as String.
     */
    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    StringBuilder sb = new StringBuilder();

    String line = null; int i = 1;
    try {
        while ((line = reader.readLine()) != null) {
            if (i++ >= lineNum) {
                sb.append(line + "\n");
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    return sb.toString();
}

String.join

Java 8 добавил новый статический метод в java.lang.String, который предлагает немного лучший вариант:

String.join( CharSequence delimiter , CharSequence... elements )

используя это:

String s = String.join(
    System.getProperty("line.separator"),
    "First line.",
    "Second line.",
    "The rest.",
    "And the last!"
);

если вы определяете свои строки в файле свойств, это будет выглядеть намного хуже. IIRC, это будет выглядеть так:

string:text\u000atext\u000atext\u000a

как правило, разумно не вставлять большие строки в источник. Вы можете загрузить их в качестве ресурсов, возможно, в формате XML или удобочитаемом текстовом формате. Текстовые файлы могут быть прочитаны во время выполнения или скомпилированы в источник Java. Если вы в конечном итоге размещаете их в источнике, я предлагаю поместить + на фронте и опуская ненужные новые строки:

final String text = ""
    +"text "
    +"text "
    +"text"
;

если у вас есть новые строки, вы можете захотеть присоединиться или форматировать метод:

final String text = join("\r\n"
    ,"text"
    ,"text"
    ,"text"
);

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

так:

String a="Hello";
String b="Goodbye";
String c=a+b;

как правило, генерирует точно такой же код, как:

String a="Hello";
String b="Goodbye":
StringBuilder temp=new StringBuilder();
temp.append(a).append(b);
String c=temp.toString();

С другой стороны:

String c="Hello"+"Goodbye";

- это то же, что:

String c="HelloGoodbye";

то есть, нет никакого наказания при разбиении строковых литералов на несколько строк со знаками плюса для удобства чтения.


в IntelliJ IDE вам просто нужно ввести:

""

затем поместите курсор внутри кавычек и вставьте строку. IDE развернет его в несколько связанных строк.


String newline = System.getProperty ("line.separator");
string1 + newline + string2 + newline + string3

но лучшей альтернативой является использование строку.формат

String multilineString = String.format("%s\n%s\n%s\n",line1,line2,line3);

к сожалению, Java не имеет многострочных строковых литералов. Вам нужно либо объединить строковые литералы (используя + или StringBuilder-два наиболее распространенных подхода к этому), либо прочитать строку из отдельного файла.

для больших многострочных строковых литералов я был бы склонен использовать отдельный файл и прочитать его с помощью getResourceAsStream() (метод Class класс). Это позволяет легко найти файл, так как вам не нужно беспокоиться о текущем каталоге по сравнению с тем, где ваш код был установлен. Это также упрощает упаковку, потому что вы можете хранить этот файл в jar-файл.

Предположим, вы в классе под названием Foo. Просто сделайте что-нибудь вроде этого:

Reader r = new InputStreamReader(Foo.class.getResourceAsStream("filename"), "UTF-8");
String s = Utils.readAll(r);

еще одна неприятность заключается в том, что Java не имеет стандартного метода "прочитать весь текст из этого считывателя в строку". Это довольно легко написать, хотя:

public static String readAll(Reader input) {
    StringBuilder sb = new StringBuilder();
    char[] buffer = new char[4096];
    int charsRead;
    while ((charsRead = input.read(buffer)) >= 0) {
        sb.append(buffer, 0, charsRead);
    }
    input.close();
    return sb.toString();
}

поскольку Java не поддерживает (пока) собственные многострочные строки, единственный способ сейчас-взломать его, используя один из вышеупомянутых методов. Я построил следующий скрипт Python, используя некоторые из трюков, упомянутых выше:

import sys
import string
import os

print 'new String('
for line in sys.stdin:
    one = string.replace(line, '"', '\"').rstrip(os.linesep)
    print '  + "' + one + ' "'
print ')'

поместите это в файл с именем javastringify.py и ваша строка в файле mystring.txt и запустите его следующим образом:

cat mystring.txt | python javastringify.py

затем вы можете скопировать вывод и вставить его в ваш редактор.

изменить это по мере необходимости, чтобы обращайтесь с любыми специальными случаями, но это работает для моих нужд. Надеюсь, это поможет!


вы можете использовать scala-код, который совместим с java, и позволяет многострочные строки, заключенные с"":

package foobar
object SWrap {
  def bar = """John said: "This is
  a test
  a bloody test,
  my dear." and closed the door.""" 
}

(обратите внимание на кавычки внутри строки) и с Java:

String s2 = foobar.SWrap.bar ();

ли это более удобно ...?

другой подход, если вы часто обрабатываете длинный текст, который должен быть помещен в ваш исходный код, может быть скриптом, который берет текст из внешнего файла и обертывает его как многострочную java-строку, как это:

sed '1s/^/String s = \"/;2,$s/^/\t+ "/;2,$s/$/"/' file > file.java

чтобы вы могли легко вырезать и вставить его в свой источник.


на самом деле, следующее-самая чистая реализация, которую я видел до сих пор. Он использует аннотацию для преобразования комментария в строковую переменную...

/**
  <html>
    <head/>
    <body>
      <p>
        Hello<br/>
        Multiline<br/>
        World<br/>
      </p>
    </body>
  </html>
  */
  @Multiline
  private static String html;

таким образом, конечный результат заключается в том, что переменная html содержит многострочную строку. Никаких кавычек, никаких плюсов, никаких запятых, только чистая строка.

это решение доступно по следующему URL-адресу... http://www.adrianwalker.org/2011/12/java-multiline-string.html

надеюсь, что помогает!


    import org.apache.commons.lang3.StringUtils;

    String multiline = StringUtils.join(new String[] {
        "It was the best of times, it was the worst of times ", 
        "it was the age of wisdom, it was the age of foolishness",
        "it was the epoch of belief, it was the epoch of incredulity",
        "it was the season of Light, it was the season of Darkness",
        "it was the spring of hope, it was the winter of despair",
        "we had everything before us, we had nothing before us"
    }, "\n");

вы можете объединить свои добавления в отдельном методе, например:

public static String multilineString(String... lines){
   StringBuilder sb = new StringBuilder();
   for(String s : lines){
     sb.append(s);
     sb.append ('\n');
   }
   return sb.toStirng();
}

в любом случае, предпочитаю StringBuilder с пометкой плюс.


посмотреть Java Stringfier. Превращает ваш текст в StringBuilder java блок экранирования, если это необходимо.


альтернативой, которую я еще не видел в качестве ответа, является java.io.PrintWriter.

StringWriter stringWriter = new StringWriter();
PrintWriter writer = new PrintWriter(stringWriter);
writer.println("It was the best of times, it was the worst of times");
writer.println("it was the age of wisdom, it was the age of foolishness,");
writer.println("it was the epoch of belief, it was the epoch of incredulity,");
writer.println("it was the season of Light, it was the season of Darkness,");
writer.println("it was the spring of hope, it was the winter of despair,");
writer.println("we had everything before us, we had nothing before us");
String string = stringWriter.toString();

также тот факт, что java.io.BufferedWriter есть newLine() метод не указан.


Если вам нравится гуава google так же, как и я, это может дать довольно чистое представление и хороший, простой способ не hardcode ваши символы новой строки тоже:

String out = Joiner.on(newline).join(ImmutableList.of(
    "line1",
    "line2",
    "line3"));

довольно эффективным и независимым от платформы решением будет использование системного свойства для разделителей строк и класса StringBuilder для построения строк:

String separator = System.getProperty("line.separator");
String[] lines = {"Line 1", "Line 2" /*, ... */};

StringBuilder builder = new StringBuilder(lines[0]);
for (int i = 1; i < lines.length(); i++) {
    builder.append(separator).append(lines[i]);
}
String multiLine = builder.toString();

JEP 326: необработанные строковые литералы будет реализовывать многострочные строки, поэтому вы сможете написать что-то вроде:

String s = `
    text
    text
    text
  `;

планируется предварительный просмотр в JDK 12.


определите мою строку в файле свойств?

многострочные строки не допускаются в файлах свойств. Вы можете использовать \n в файлах свойств, но я не думаю, что это большое решение в вашем случае.


один хороший вариант.

import static some.Util.*;

    public class Java {

        public static void main(String[] args) {

            String sql = $(
              "Select * from java",
              "join some on ",
              "group by"        
            );

            System.out.println(sql);
        }

    }


    public class Util {

        public static String $(String ...sql){
            return String.join(System.getProperty("line.separator"),sql);
        }

    }

когда используется длинный ряд+, создается только один StringBuilder, если строка не определена во время компиляции, и в этом случае StringBuilder не используется!

единственное время StringBuilder является более эффективным, когда несколько операторов используются для построения строки.

String a = "a\n";
String b = "b\n";
String c = "c\n";
String d = "d\n";

String abcd = a + b + c + d;
System.out.println(abcd);

String abcd2 = "a\n" +
        "b\n" +
        "c\n" +
        "d\n";
System.out.println(abcd2);

Примечание: создается только один StringBuilder.

  Code:
   0:   ldc     #2; //String a\n
   2:   astore_1
   3:   ldc     #3; //String b\n
   5:   astore_2
   6:   ldc     #4; //String c\n
   8:   astore_3
   9:   ldc     #5; //String d\n
   11:  astore  4
   13:  new     #6; //class java/lang/StringBuilder
   16:  dup
   17:  invokespecial   #7; //Method java/lang/StringBuilder."<init>":()V
   20:  aload_1
   21:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   24:  aload_2
   25:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   28:  aload_3
   29:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   32:  aload   4
   34:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   37:  invokevirtual   #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   40:  astore  5
   42:  getstatic       #10; //Field java/lang/System.out:Ljava/io/PrintStream;
   45:  aload   5
   47:  invokevirtual   #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   50:  ldc     #12; //String a\nb\nc\nd\n
   52:  astore  6
   54:  getstatic       #10; //Field java/lang/System.out:Ljava/io/PrintStream;
   57:  aload   6
   59:  invokevirtual   #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   62:  return

дополнительно прояснить мой вопрос, я не беспокоюсь о производительности. Я беспокоюсь о ремонтопригодность и вопросы дизайна.

сделать это так ясно и просто, как вы можете.


один маленький трюк. Используя это, я ввожу javascritp в динамически созданную HTML-страницу

StringBuilder builder = new StringBuilder();

public String getString()
{
    return builder.toString();
}
private DropdownContent _(String a)
{
    builder.append(a);
    return this;
}

public String funct_showhide()
{
   return
    _("function slidedown_showHide(boxId)").
    _("{").
    _("if(!slidedown_direction[boxId])slidedown_direction[boxId] = 1;").
    _("if(!slideDownInitHeight[boxId])slideDownInitHeight[boxId] = 0;").
    _("if(slideDownInitHeight[boxId]==0)slidedown_direction[boxId]=slidedownSpeed; ").
    _("else slidedown_direction[boxId] = slidedownSpeed*-1;").
    _("slidedownContentBox = document.getElementById(boxId);").
    _("var subDivs = slidedownContentBox.getElementsByTagName('DIV');").
    _("for(var no=0;no<subDivs.length;no++){").
    _(" if(subDivs[no].className=='dhtmlgoodies_content')slidedownContent = subDivs[no];").
    _("}").
    _("contentHeight = slidedownContent.offsetHeight;").
    _("slidedownContentBox.style.visibility='visible';").
    _("slidedownActive = true;").
    _("slidedown_showHide_start(slidedownContentBox,slidedownContent);").
    _("}").getString();

}

поздняя модель JAVA имеет оптимизацию для + с постоянными строками, использует StringBuffer за кулисами, поэтому вы не хотите загромождать свой код.

это указывает на надзор JAVA, что он не похож на ANSI C в автоматической конкатенации строк с двойными кавычками только с пробелом между ними, например:

const char usage = "\n"
"Usage: xxxx <options>\n"
"\n"
"Removes your options as designated by the required parameter <options>,\n"
"which must be one of the following strings:\n"
"  love\n"
"  sex\n"
"  drugs\n"
"  rockandroll\n"
"\n" ;

Я хотел бы иметь константу многострочного массива символов, в которой используются встроенные потоки строк, поэтому я могу представить блок без всякого беспорядка, например:

String Query = "
SELECT
    some_column,
    another column
  FROM
      one_table a
    JOIN
      another_table b
    ON    a.id = b.id
      AND a.role_code = b.role_code
  WHERE a.dept = 'sales'
    AND b.sales_quote > 1000
  Order BY 1, 2
" ;

чтобы получить это, нужно бить по богам JAVA.


использовать Properties.loadFromXML(InputStream). Нет необходимости во внешней свободе.

лучше, чем грязный код (поскольку ремонтопригодность и дизайн-ваша забота), предпочтительнее не использовать длинные строки.

Начните с чтения свойств XML:

 InputStream fileIS = YourClass.class.getResourceAsStream("MultiLine.xml");
 Properties prop = new Properies();
 prop.loadFromXML(fileIS);


затем вы можете использовать многострочную строку в более ремонтопригодны путь...

static final String UNIQUE_MEANINGFUL_KEY = "Super Duper UNIQUE Key";
prop.getProperty(UNIQUE_MEANINGFUL_KEY) // "\n    MEGA\n   LONG\n..."


многострочный.xml ' находится в той же папке YourClass:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">

<properties>
    <entry key="Super Duper UNIQUE Key">
       MEGA
       LONG
       MULTILINE
    </entry>
</properties>

PS.: Вы может использовать <![CDATA[" ... "]]> для xml-подобной строки.


Я знаю, что это старый вопрос, однако для intersted разработчиков многострочные литералы будут в #Java12

http://mail.openjdk.java.net/pipermail/amber-dev/2018-July/003254.html


Я предлагаю использовать утилиту, предложенную ThomasP, а затем связать ее с процессом сборки. Внешний файл по-прежнему присутствует, чтобы содержать текст, но файл не читается во время выполнения. Рабочий процесс тогда:

  1. создайте утилиту "textfile to java code" и проверьте контроль версий
  2. в каждой сборке запустите утилиту против файла ресурсов, чтобы создать пересмотренный источник java
  3. источник Java содержит заголовок типа class TextBlock {... затем статическая строка, которая автоматически генерируется из файла ресурсов
  4. создайте сгенерированный файл java с остальной частью вашего кода