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


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

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

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

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

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

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

30 419

30 ответов:

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

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

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

ваша лучшая альтернатива будет строки, которые просто +будем вместе. Некоторые другие параметры, которые люди упомянули (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-текст при вставке в строковый литерал" (в настройках > Java > редактор > ввод) и вставьте многострочную строку в кавычки, она автоматически добавит " и \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();
}
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 так же, как и я, он может дать довольно чистое представление и хороший, простой способ не жестко кодировать ваши символы новой строки:

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-подобной строки.

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

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

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

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