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

516

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

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

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

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

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

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

skiphoppy
источник
12
StringBuilder.append () предпочтительнее плюса при многократном добавлении в строку, потому что каждый раз, когда вы делаете string1 + string2это, вы выделяете новый строковый объект и копируете символы из обеих входных строк. Если вы добавляете n строк вместе, вы будете делать n-1 выделения и примерно (n ^ 2) / 2 символа копий. StringBuilder, с другой стороны, копирует и перераспределяет реже (хотя он все равно делает оба, когда вы превышаете размер его внутреннего буфера). Теоретически, бывают случаи, когда компилятор может конвертировать + в StringBuilder, но на практике кто знает.
Лоуренс Гонсалвес
5
Каждый раз, когда я запускаю отладчик, + преобразуется в вызов StringBuilder.append () в Java 1.5. Мои коллеги смущенно говорят мне, что в StringBuilder есть ошибка, поскольку они отлаживают код, который, кажется, не вызывает его и не оказывается там.
skiphoppy
4
Смотрите также: stackoverflow.com/questions/782810/…
Майкл Майерс
61
Обратите внимание, что строковый литерал, состоящий из «abc \ n» + «def \ n» и т. Д., Не использует StringBuilder: компилятор склеивает их вместе и помещает их в файл .class как один литерал, как и в других типах постоянное складывание.
Аракнид
6
Большинство IDE поддерживают ввод многострочных строк. то есть. Вы просто набираете или вставляете то, что хотите, в строку "", и он добавляет \ n и "+", как требуется. Например, я могу вставить 40 строк текста в строку и IDE разберется с вами.
Питер Лоури

Ответы:

118

Стивен Колебурн создал предложение о добавлении многострочных строк в Java 7.

Кроме того, в Groovy уже есть поддержка многострочных строк .

Paul Morie
источник
14
Процесс Project Coin для улучшений Java включал многострочные строки mail.openjdk.java.net/pipermail/coin-dev/2009-Feb February/… . Это было отклонено Oracle blogs.sun.com/darcy/entry/project_coin_final_five .
JodaStephen
8
Любые изменения в 2012 году?
Илья Г
13
К сожалению, это, похоже, не вошло в спецификацию.
namuol
3
Ссылка на blogs.sun.com не работает, но я думаю, что содержимое теперь находится по адресу blogs.oracle.com/darcy/entry/project_coin_final_five .
Donal Fellows
8
Кажется, по состоянию на январь 2018 года сообщество пересматривает многострочные строки. openjdk.java.net/jeps/326
Шейн Гэннон
485

Звучит так, как будто вы хотите создать многострочный литерал, которого нет в Java.

Ваша лучшая альтернатива - это струны, которые просто были +вместе. Некоторые другие опции, о которых упоминали люди (StringBuilder, String.format, 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();

По сравнению с 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.lineSeparator(), или вы можете использовать %nв String.format.

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

кип
источник
246
Кроме того, первая версия будет автоматически объединена компилятором, поскольку все строки известны во время компиляции. Даже если строки не известны во время компиляции, они не медленнее, чем StringBuilder или String.format (). Единственная причина, по которой следует избегать объединения с +, заключается в том, что вы делаете это в цикле.
Майкл Майерс
23
Проблема с String.formatверсией заключается в том, что вы должны синхронизировать формат с количеством строк.
Барт ван Хейкелом
4
String.format не эффективен по сравнению с двумя другими примерами
cmcginty
10
Этот ответ является очень неуместным решением поставленного вопроса. У нас есть 2000 строковых макросов SAS или наборы 200 строковых SQL-запросов, которые мы хотим скопировать и вставить. Предполагать, что мы используем + "" concat для преобразования многострочного текста в присоединения StringBuffer, просто смешно.
Благословенный Компьютерщик
21
@BlessedGeek: под рукой был вопрос о том, какие опции были доступны на языке Java. Ничего не сказано о типе данных, поступающих в строку. Если есть лучшее решение, вы можете опубликовать его как ответ. Похоже , решение Джоша Валкуса будет лучше для вашей ситуации. Если вы просто расстроены тем, что язык не поддерживает многострочные литералы, тогда это не то место, чтобы жаловаться на это.
Кип
188

В Eclipse, если вы включите опцию «Избегать текста при вставке в строковый литерал» (в «Предпочтения»> «Java»> «Редактор»> «Ввод») и вставите многострочную строку в кавычки, она автоматически добавится "и \n" +для всех ваших строк.

String str = "paste your text here";
Monir
источник
15
Intelij также делает это по умолчанию, когда вы вставляете в ""
Боб Б
Вы обычно оставляете в том, \rчто Eclipse вставляет в Windows?
Ноумен
99

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

Проверьте : http://www.adrianwalker.org/2011/12/java-multiline-string.html

Проект, вдохновленный этой работой, размещен на GitHub:

https://github.com/benelog/multiline

Пример кода Java:

import org.adrianwalker.multilinestring.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);
  }
}

Недостатки

  1. что вы должны активировать соответствующий (предоставленный) процессор аннотаций.
  2. эта строковая переменная не может быть определена как локальная переменная Проверьте проект Raw String Literals, где вы можете определить переменные как локальные переменные
  3. эта строка не может содержать другие переменные, как в Visual Basic .Net с XML literal ( <%= variable %>) :-)
  4. этот строковый литерал ограничен комментарием JavaDoc (/ **)

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

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

SRG
источник
Требует ли это, чтобы класс, использующий многострочную строку, был финальным? Кроме того, требуются ли какие-либо настройки при разработке и выполнении кода из Eclipse? Ссылочный URL-адрес упоминает требования к настройке Maven для обработки аннотаций. Я не могу понять, что может понадобиться, если таковые имеются в Eclipse.
Дэвид
Аннотация пригодна для жизни - но, похоже, также существовала жесткая зависимость от maven? Эта часть отнимает большую часть значения heredoc, которое должно упростить управление небольшими фрагментами текста.
Джавадба
3
Вы можете сделать это полностью в затмении. Ссылка, размещенная выше @SRG, указывает на эту ссылку . Если вы используете Eclipse, то минута настройки, и она работает.
Майкл Плаутц
4
Это, наверное, самый большой взлом, который я когда-либо видел. РЕДАКТИРОВАТЬ: Неважно ... см. Ответ Боб Олбрайтс.
Ллев Валлис
1
Я сделал расширение этого проекта и создал новый, в котором поддерживаются локальные переменные, взгляните на проект
deFreitas
62

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

Джош Валун
источник
13
Точно. Большие объемы текста не принадлежат источнику Java; вместо этого используйте файл ресурсов соответствующего формата, загруженный с помощью вызова Class.getResource (String).
Эриксон
5
Правильно! Вы также можете использовать Locale + ResourceBundle, чтобы легко загрузить текст I18N, а затем вызов String.format () проанализирует "\ n" как символы новой строки :) Пример: String readyStr = String.parse (resourceBundle.getString (" введение"));
ATorras
62
Вам не нужно выводить строку только потому, что она многострочная. Что если у меня есть регулярное выражение, которое я хочу разбить на несколько строк с комментариями? Это выглядит некрасиво в Java. @Синтаксис C # гораздо чище.
Джереми Стейн
8
Skiphoppy не хочет беспокоиться о работе с файлами, просто используя строковую константу длины абзаца. Я все время использую многострочные строки в C ++, встроенные в мой исходный код, где я хочу их.
Тим Купер
9
Ух ты. Я не могу поверить, что C ++ на самом деле лучше, чем Java, в этом вопросе! Я люблю многострочные строковые константы, и в некоторых случаях они действительно принадлежат источнику.
User1
59

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

Пример:

    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();
}
Боб Олбрайт
источник
15
Требуется доставка кода Java для класса с окончательным двоичным кодом. Хм.
Турбьерн Равн Андерсен
23
я могу представить себе реакцию моих коллег, когда я пытаюсь проверить что-то подобное в ...
Лэндон Кун
15
+1. Некоторая нехватка воображения людьми, голосующими вниз. Это полезная конструкция для написания небольших утилит, тестовых случаев и даже в контролируемых средах разработки. Это разница между выпуском java в ruby ​​/ python / etc или пребыванием здесь.
Джавадба
1
Отличное решение, но, к сожалению, не будет работать на Android, так как он будет выполняться на эмуляторе или реальном устройстве, и там нет исходного кода.
евгений.мясищев
Может быть, это проба Java 8 или что-то еще, но classLoader в примере не существует. Я пытался использовать MyClass.class.getResourceAsStream (...), но он всегда возвращает ноль. Было бы отличным быстрым решением для тестирования!
Ник
54

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!"
);
icza
источник
5
Аккуратное и чистое решение! Нет зависимости от IDE и препроцессора! Руководство "\n"не требуется, и он знает о портативности!
Сиу Чинг Понг-Асука Кэндзи -
1
Я понимаю, что мой комментарий бесполезен, но он настолько отсталый, что ищет хаки для такой простой вещи, как многострочный строковый литерал. Почему, черт возьми, Java не может добавить это в спецификации?
Дмитрий
22

JEP 355. Текстовые блоки (предварительный просмотр) предназначены для охвата этой функциональности, в настоящее время он нацелен на JDK 13 в качестве функции предварительного просмотра. Позволяет написать что-то вроде:

String s = """
    text
    text
    text
  """;

До этого JEP, в JDK12, JEP 326: сырые строковые литералы стремились реализовать подобную функцию, но она была окончательно отозвана.

оборота алостале
источник
2
Они отбросили эту поддержку
deFreitas
2
Текстовые блоки теперь являются частью Java 13.
Жека Козлов
19

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

string:text\u000atext\u000atext\u000a

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

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

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

final String text = join("\r\n"
    ,"text"
    ,"text"
    ,"text"
);
Том Хотин - Tackline
источник
17

Плюсы преобразуются в StringBuilder.append, за исключением случаев, когда обе строки являются константами, поэтому компилятор может объединять их во время компиляции. По крайней мере, так оно и есть в компиляторе 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";

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

сойка
источник
4
чтобы быть техническим, в вашем первом примере он генерирует нечто более похожее на: String c = new StringBuilder (). append (a) .append (b) .toString (); Разница в том, что временный компоновщик строк находится вне области видимости и может собирать мусор сразу после строки String c = ..., тогда как компоновщик строк «temp» будет оставаться немного дольше.
Кип
Правда. Моя цель, конечно, состоит в том, чтобы различать, когда функция вызывается во время выполнения, и когда работа может быть выполнена во время компиляции. Но вы правы.
Джей
15

В IntelliJ IDE вам просто нужно набрать:

""

Затем поместите курсор в кавычки и вставьте строку. Среда IDE развернет ее на несколько объединенных строк.

Нуреттин
источник
11

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

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

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

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

Еще одно неудобство заключается в том, что в Java нет стандартного метода «читать весь текст из этого Reader в String». Это довольно легко написать, хотя:

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();
}
Лоуренс Гонсалвес
источник
Я делаю то же самое. Вы можете использовать commons-io для более удобного чтения содержимого файла (с помощью «FileUtils.readFileToString (File file)»).
SRG
Уже не верно, что в Java нет стандартного метода чтения всего текста ... - начиная с Java 7 вы можете использовать Files.readAllLines (Path)
ccpizza
10
String newline = System.getProperty ("line.separator");
string1 + newline + string2 + newline + string3

Но лучшая альтернатива - использовать String.format

String multilineString = String.format("%s\n%s\n%s\n",line1,line2,line3);
Том
источник
Мое мнение таково, что он удаляет знаки плюс и кавычки, делая его более читабельным, особенно если в нем более 3 строк. Не так хорошо, как String.format.
Том
2
Пример Stringbuilder по крайней мере так же нечитаем. Кроме того, не забывайте, что «\ n» не всегда является новой строкой, но это хорошо для компьютеров с Linux и Unix.
Стефан Тиберг
Плюс просто хотел упомянуть о существовании StringBuilder.
Том
4
Замена одного знака плюс на имя метода из шести символов и круглые скобки не выглядит для меня более читабельным, хотя, очевидно, вы не единственный, кто так думает. Это не удаляет кавычки, все же. Они все еще там.
skiphoppy
9

Поскольку 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

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

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

scorpiodawg
источник
9

Вы можете использовать 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-String, например так:

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

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

пользователь неизвестен
источник
8

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

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

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

user54579
источник
5
Почему я предпочитаю StringBuilder для обозначения «плюс»?
skiphoppy
10
Эффективность, или, скорее, часто ошибочная попытка сделать это.
Майкл Майерс
2
Я полагаю, что попытка повышения эффективности основана на том факте, что компилятор Java реализует оператор конкатенации строк с использованием StringBuilder (StringBuffer в компиляторах до версии 1.5). Существует старая, но хорошо известная статья, в которой говорится, что в некоторых ситуациях есть преимущества в производительности при использовании StringBuffer (или StringBuilder, сейчас). Вот ссылка: java.sun.com/developer/JDCTechTips/2002/tt0305.html
Пол Мори
4
Только когда компилятор не может этого сделать. Для литералов и констант, если вы используете знак плюс, конкатенация выполняется во время компиляции. Использование StringBuilder заставляет это происходить во время выполнения, так что это не только больше работы, но и медленнее.
Джонсип
7

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

/**
  <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

Надеюсь, это поможет!

Родни П. Барбати
источник
Этот процессор аннотаций нуждается в более надежной проверке,
Tripp Kinetics,
Мне это нравится.
Испытывать
7

Смотрите Java Stringfier . Превращает ваш текст в Java-блок StringBuilder, экранирующий при необходимости.

Лев
источник
1
Да, потому что я могу посвятить свою жизнь копированию и вставке на этот сайт. Я мог бы также просто сохранить их в файле и загрузить их, но это тоже не идеальное решение.
ммм
7
    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");
оборота Михаил Адамович
источник
6

Альтернативой, которую я пока не видел в качестве ответа, является 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()метод, не упомянут.

BalusC
источник
5

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

String out = Joiner.on(newline).join(ImmutableList.of(
    "line1",
    "line2",
    "line3"));
Дэн Ло Бьянко
источник
5

Использование 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..."


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

jpfreire
источник
Да, это то, что я тоже использую, отличное решение! Переместите SQL или XML во внешний файл свойств XML. Это не портит код. :)
Ласло Лугоши
Это не отвечает на вопрос. heredoc по определению в файле . Дело в том, чтобы держать его в одном месте.
Джавадба
5

С JDK / 12 раннего доступа build # 12 , теперь можно использовать многострочные строки в Java следующим образом:

String multiLine = `First line
    Second line with indentation
Third line
and so on...`; // the formatting as desired
System.out.println(multiLine);

и это приводит к следующему выводу:

First line
    Second line with indentation
Third line
and so on...

Редактировать: Отложено на Java 13

Naman
источник
2
Как сказал cybersoft в другом комментарии, необработанные строковые литералы (JEP326) были удалены из окончательного JDK12, но был создан еще один JEP для добавления «текстовых блоков», которые можно выполнить в качестве предварительного просмотра в JDK 13
Мануэль Ромейро,
4

Довольно эффективное и независимое от платформы решение будет использовать системное свойство для разделителей строк и класс 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();
Andreas_D
источник
4

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

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);
        }

    }
Бруно Ли
источник
4

Это очень распространенный вопрос, поэтому я решил превратить этот ответ в статью .

Java 13 и выше

Многострочные строки теперь поддерживаются в Java с помощью текстовых блоков . В Java 13 и 14 эта функция требует, чтобы вы установили ––enable–previewопцию при сборке и запуске вашего проекта. Проверьте эту документацию Java для более подробной информации.

Теперь, до Java 13, вот как бы вы написали запрос:

List<Tuple> posts = entityManager
.createNativeQuery(
    "SELECT *\n" +
    "FROM (\n" +
    "    SELECT *,\n" +
    "           dense_rank() OVER (\n" +
    "               ORDER BY \"p.created_on\", \"p.id\"\n" +
    "           ) rank\n" +
    "    FROM (\n" +
    "        SELECT p.id AS \"p.id\",\n" +
    "               p.created_on AS \"p.created_on\",\n" +
    "               p.title AS \"p.title\",\n" +
    "               pc.id as \"pc.id\",\n" +
    "               pc.created_on AS \"pc.created_on\",\n" +
    "               pc.review AS \"pc.review\",\n" +
    "               pc.post_id AS \"pc.post_id\"\n" +
    "        FROM post p\n" +
    "        LEFT JOIN post_comment pc ON p.id = pc.post_id\n" +
    "        WHERE p.title LIKE :titlePattern\n" +
    "        ORDER BY p.created_on\n" +
    "    ) p_pc\n" +
    ") p_pc_r\n" +
    "WHERE p_pc_r.rank <= :rank\n",
    Tuple.class)
.setParameter("titlePattern", "High-Performance Java Persistence %")
.setParameter("rank", 5)
.getResultList();

Благодаря Java 13 Text Blocks вы можете переписать этот запрос следующим образом:

List<Tuple> posts = entityManager
.createNativeQuery("""
    SELECT *
    FROM (
        SELECT *,
               dense_rank() OVER (
                   ORDER BY "p.created_on", "p.id"
               ) rank
        FROM (
            SELECT p.id AS "p.id",
                   p.created_on AS "p.created_on",
                   p.title AS "p.title",
                   pc.id as "pc.id",
                   pc.created_on AS "pc.created_on",
                   pc.review AS "pc.review",
                   pc.post_id AS "pc.post_id"
            FROM post p
            LEFT JOIN post_comment pc ON p.id = pc.post_id
            WHERE p.title LIKE :titlePattern
            ORDER BY p.created_on
        ) p_pc
    ) p_pc_r
    WHERE p_pc_r.rank <= :rank
    """,
    Tuple.class)
.setParameter("titlePattern", "High-Performance Java Persistence %")
.setParameter("rank", 5)
.getResultList();

Гораздо более читабельно, верно?

Поддержка IDE

IntelliJ IDEA поддерживает преобразование устаревших Stringблоков сцепления в новый многострочный Stringформат:

Поддержка текстовых блоков IntelliJ IDEA

JSON, HTML, XML

Многострочный Stringособенно полезен при написании JSON, HTML или XML.

Рассмотрим этот пример с использованием Stringконкатенации для построения строкового литерала JSON:

entityManager.persist(
    new Book()
    .setId(1L)
    .setIsbn("978-9730228236")
    .setProperties(
        "{" +
        "   \"title\": \"High-Performance Java Persistence\"," +
        "   \"author\": \"Vlad Mihalcea\"," +
        "   \"publisher\": \"Amazon\"," +
        "   \"price\": 44.99," +
        "   \"reviews\": [" +
        "       {" +
        "           \"reviewer\": \"Cristiano\", " +
        "           \"review\": \"Excellent book to understand Java Persistence\", " +
        "           \"date\": \"2017-11-14\", " +
        "           \"rating\": 5" +
        "       }," +
        "       {" +
        "           \"reviewer\": \"T.W\", " +
        "           \"review\": \"The best JPA ORM book out there\", " +
        "           \"date\": \"2019-01-27\", " +
        "           \"rating\": 5" +
        "       }," +
        "       {" +
        "           \"reviewer\": \"Shaikh\", " +
        "           \"review\": \"The most informative book\", " +
        "           \"date\": \"2016-12-24\", " +
        "           \"rating\": 4" +
        "       }" +
        "   ]" +
        "}"
    )
);

Вы едва можете прочитать JSON из-за экранирующих символов и обилия двойных кавычек и знаков плюс.

С помощью текстовых блоков Java объект JSON можно записать так:

entityManager.persist(
    new Book()
    .setId(1L)
    .setIsbn("978-9730228236")
    .setProperties("""
        {
           "title": "High-Performance Java Persistence",
           "author": "Vlad Mihalcea",
           "publisher": "Amazon",
           "price": 44.99,
           "reviews": [
               {
                   "reviewer": "Cristiano",
                   "review": "Excellent book to understand Java Persistence",
                   "date": "2017-11-14",
                   "rating": 5
               },
               {
                   "reviewer": "T.W",
                   "review": "The best JPA ORM book out there",
                   "date": "2019-01-27",
                   "rating": 5
               },
               {
                   "reviewer": "Shaikh",
                   "review": "The most informative book",
                   "date": "2016-12-24",
                   "rating": 4
               }
           ]
        }
        """
    )
);

С тех пор, как я использовал C # в 2004 году, я хотел иметь эту функцию на Java, и теперь мы наконец-то ее получили.

Влад Михалча
источник
3

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

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

койка
источник
Значение в файле свойств может занимать несколько строк: просто завершите все строки, кроме последней, обратной косой чертой. Это оставляет проблему с тем, что вы используете в качестве разделителя строк, поскольку это зависит от платформы. Я полагаю, что вы можете использовать простой \ n, а затем в своем коде после прочтения свойства выполнить поиск и замену \ n в line.separator. Это кажется немного хитрым, но я думаю, вы могли бы написать функцию, которая извлекает свойство и выполняет эту манипуляцию одновременно. Ну, все это предполагает, что вы будете записывать эти строки в файл, что является большим предположением.
Джей
3

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

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

Мортеза Ади
источник
нет. но , наконец, сделал это для Java 13. Что мои команды, вероятно, примут примерно через пол десятилетия.
Джавадба
3

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

  1. Создайте утилиту 'textfile to java code' и проверьте контроль версий
  2. В каждой сборке запускайте утилиту для файла ресурсов, чтобы создать исправленный исходный код Java
  3. Исходный код Java содержит заголовок class TextBlock {... статической строке, которая автоматически генерируется из файла ресурсов.
  4. Создайте сгенерированный файл Java с остальным кодом
Гораций
источник
2

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

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

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

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

Сделайте это как можно более понятным и простым.

Питер Лори
источник