Java複数行ストリング


516

Perlから来ているので、ソースコードに複数行の文字列を作成する「ヒアドキュメント」という手段が欠けているのは確かです。

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

Javaでは、複数行の文字列を最初から連結するため、面倒な引用符とプラス記号をすべての行に付ける必要があります。

より良い代替手段は何ですか?プロパティファイルで文字列を定義しますか?

編集:2つの答えは、StringBuilder.append()がプラス表記よりも望ましいと言います。彼らがそう思う理由について誰かが詳しく説明できますか?それは私には全然好ましいようには見えません。複数行の文字列がファーストクラスの言語構成要素ではないという事実を回避する方法を探しています。つまり、ファーストクラスの言語構成要素(文字列連結とプラス)をメソッド呼び出しで置き換えたくはありません。

編集:私の質問をさらに明確にするために、私はパフォーマンスについてまったく気にしません。保守性と設計の問題が心配です。


12
StringBuilder.append()は、文字列に繰り返し追加するときにプラスするよりも望ましいstring1 + string2です。なぜなら、毎回新しい文字列オブジェクトを割り当て、両方の入力文字列から文字をコピーするからです。n個の文字列を一緒に追加する場合は、n-1個の割り当てと約(n ^ 2)/ 2文字のコピーを行うことになります。一方、StringBuilderは、コピーと再割り当ての頻度が低くなります(ただし、内部バッファーのサイズを超えた場合でも両方が行われます)。理論的には、コンパイラーがStringBuilderを使用するように+を変換できる場合がありますが、実際には誰もが知っています。
ローレンスゴンサルベス

5
+は、デバッガーにジャンプするたびに、Java 1.5ではStringBuilder.append()呼び出しに変換されます。私は同僚に、StringBuilderにバグがあり、それを呼び出してそこに巻き込まれていないようにデバッグするのでバグがあると混乱させていました。
スキップホッピー2009年


61
「abc \ n」+「def \ n」などで構成される文字列リテラルは、StringBuilderを使用しないことに注意してください。コンパイラは、それらを一緒に接着し、それらを.classファイルに単一のリテラルとして配置します。一定の折りたたみ。
araqnid 2009年

6
ほとんどのIDEは、複数行の文字列の入力をサポートしています。すなわち。必要なものを「」文字列に入力するか貼り付けるだけで、必要に応じて\ nと「+」が追加されます。たとえば、40行のテキストを文字列に貼り付けることができ、IDEがそれを分類してくれます。
Peter Lawrey、

回答:


118

スティーブン・コールボーンが提案を作成しました、Java 7で複数行の文字列を追加するためを。

また、Groovyはすでに複数行の文字列をサポートしています


14
Javaを拡張するためのProject Coinプロセスには、複数行の文字列mail.openjdk.java.net/pipermail/coin-dev/2009-February/…が含まれていました。Oracle blogs.sun.com/darcy/entry/project_coin_final_fiveによって拒否されました。
JodaStephen

8
2012年に何か変化はありますか?
Ilia G

13
残念ながら、これは仕様に反映されていないようです。
namuol 2013年

3
blogs.sun.comリンクは壊れていますが、コンテンツは現在blogs.oracle.com/darcy/entry/project_coin_final_fiveにあると思います。
ドナルフェロー

8
2018年1月の時点で、コミュニティは複数行の文字列を再検討しているようです。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バージョンの問題は、フォーマットを行数と同期させる必要があることです。
Bart van Heukelom、

4
String.formatは、他の2つの例と比較して効率的ではありません
cmcginty

10
この回答は、現在の質問に対する非常に不適切な解決策です。コピーして貼り付けたい2000行のSASマクロまたは200行のSQLクエリの束があります。+ ""連結を使用してこれらの複数行テキストをStringBufferに変換することを提案することは、ばかげています。
Blessed Geek

21
@BlessedGeek:手元にある質問は、Java言語で利用可能なオプションについてでした。文字列に入るデータのタイプについては何も触れられていません。より良い解決策がある場合は、それを回答として投稿できます。ように聞こえるジョシュ・カレンのソリューションは、あなたの状況のために良いだろう。言語が複数行リテラルをサポートしていないことに単に気が動転しているなら、これはそれについて不平を言うには間違った場所です。
2012

188

Eclipseで[文字列リテラルに貼り付けるときにテキストをエスケープする]オプションをオンにして([設定]> [Java]> [エディター]> [入力])、複数行の文字列を引用符で貼り付ける"\n" +、すべての行に自動的に追加されます。

String str = "paste your text here";

15
intelijは、 ""に貼り付けるときにもデフォルトでこれを行います
Bob B

一般的に、\rEclipseがWindowsに配置するs に残しますか?
Noumenon 2017年

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. その文字列には、XMLリテラル(<%= variable %>)を使用したVisual Basic .Netのように他の変数を含めることはできません:-)
  4. その文字列リテラルはJavaDocコメント(/ **)で区切られています

また、Javadocコメントが自動的に再フォーマットされないように、Eclipse / Intellij-Ideaを構成する必要があります。

この奇妙なことに気付くかもしれませんが(Javadocコメントはコメント以外を埋め込むようには設計されていません)、Javaでのこの複数行の文字列の欠如は結局厄介なので、これが最も悪い解決策であることがわかりました。


そのためには、複数行文字列を使用するクラスが最終である必要がありますか?また、Eclipseからコードを開発して実行する場合、セットアップは必要ですか?参照URLには、注釈処理のためのMavenのセットアップ要件が記載されています。Eclipseに必要なものがあれば、何が必要かわかりません。
デビッド

アノテーションは住みやすいですが、mavenへの強い依存もあったようですか?この部分は、小さなテキストの管理を簡素化することである、ヒアドキュメントの価値の多くを取り除きます。
javadba 2013年

3
あなたはこれを完全に日食で行うことができます。@SRGが上記に投稿したリンクは、このリンクへのリンクです。Eclipseを使用している場合は、1分間のセットアップで機能します。
Michael Plautz 2014

4
これはおそらく私が今まで見た中で最大のハックです。編集:ネバーマインド...ボブ・オルブライツの回答を参照してください。
Llew Vallis

1
私はこのプロジェクトの拡張を行い、ローカル変数をサポートする新しいプロジェクトを作成しました。プロジェクトを見てください
deFreitas

62

別のオプションは、外部ファイルに長い文字列を格納し、ファイルを文字列に読み取ることです。


13
丁度。大量のテキストはJavaソースに属しません。代わりに、Class.getResource(String)の呼び出しを介して読み込まれる適切な形式のリソースファイルを使用してください。
エリクソン2009年

5
正しい!Locale + ResourceBundleも使用して、I18Nテキストを簡単にロードできます。次に、String.format()呼び出しは、「\ n」を改行として解析します:)例:文字列readyStr = String.parse(resourceBundle.getString( "前書き"));
ATorras、2009年

62
文字列が複数行であるため、文字列を外部化する必要はありません。コメント付きの複数行に分割したい正規表現がある場合はどうなりますか?Javaでは見栄えが悪いです。@C#の構文はより明確です。
ジェレミースタイン

8
Skiphoppyは、段落長の文字列定数を使用するためだけにファイルを処理するオーバーヘッドに煩わされたくありません。C ++では常に複数行の文字列を使用し、ソースコードに埋め込んで、必要な場所に配置しています。
Tim Cooper、

9
ワオ。この問題については、C ++がJavaよりも実際には優れているとは思えません!複数行の文字列定数が大好きで、場合によってはソースに属しています。
User1、2011年

59

これは、何をしているのかを考えずに使用してはならないものです。しかし、1回限りのスクリプトでは、これを使用して大きな成功を収めています。

例:

    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コードを出荷する必要があります。うーん。
するThorbjörnRavnアンデルセン

23
このようなものをチェックしようとすると、同僚の反応を想像できます...
ランドンクーン

15
+1。投票する人による想像力の欠如。これは、小さなユーティリティ、テストケース、さらには制御されたprod環境での記述に役立つ構成です。これは、Javaをruby / python / etcにドロップするか、ここにとどまるかの違いです。
javadba 2013年

1
素晴らしい解決策ですが、残念ながらAndroidでは機能しません。エミュレーターまたは実際のデバイスで実行され、そこにソースコードがないためです。
evgeny.myasishchev 2015

多分それはJava 8の確率かもしれませんが、例のclassLoaderは存在しません。MyClass.class.getResourceAsStream(...)を使用しようとしましたが、常にnullを返します。テストのための素晴らしい迅速なソリューションでした!
Nick

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!"
);

5
清楚なソリューション!IDEとプリプロセッサに依存しない!マニュアル"\n"は不要であり、移植性を認識しています!
Siu Ching Pong -Asuka Kenji- 2017

1
私のコメントは役に立たないことは理解していますが、複数行の文字列リテラルなどの基本的なことをハックすることは非常に遅れています。なぜJavaはまだこれを仕様に追加できないのですか?
ドミトリー

22

JEP 355:テキストブロック(プレビュー)は、この機能をカバーすることを目的としています。現在、プレビュー機能としてJDK 13を対象としています。次のようなものを書くことができます:

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

このJEPの前のJDK12では、JEP 326:Raw String Literalsは同様の機能を実装することを目的としていましたが、最終的に撤回されました。


2
彼らはこのサポートを落としました
deFreitas '23 / 02/23

2
テキストブロックはJava 13の一部になりました
。– ZhekaKozlov、

19

プロパティファイルで文字列を定義すると、はるかに悪くなります。IIRC、それは次のようになります:

string:text\u000atext\u000atext\u000a

一般的に、大きな文字列をソースに埋め込まないことは理にかなっています。それらをリソースとして、おそらくXMLまたは読みやすいテキスト形式でロードすることができます。テキストファイルは、実行時に読み取るか、Javaソースにコンパイルできます。ソースにそれらを配置することになった場合+は、を先頭に配置し、不要な新しい行を省略することをお勧めします。

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

新しい行がある場合は、結合またはフォーマットの方法が必要になる場合があります。

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

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(); 違いは、一時的な文字列ビルダーはスコープ外にあり、文字列c = ...行の直後にガベージコレクションの対象になるのに対し、「temp」文字列ビルダーは少し長くとどまるということです。
キップ

そうだね。もちろん、私のポイントは、関数が実行時に呼び出されるときと、コンパイル時に作業が実行されるときを区別することです。しかし、あなたは正しいです。
ジェイ

15

IntelliJ IDEでは、次のように入力するだけです。

""

次に、引用符の内側にカーソルを置き、文字列を貼り付けます。IDEはそれを複数の連結された行に展開します。


11

残念ながら、Javaには複数行の文字列リテラルがありません。文字列リテラルを連結する(+またはStringBuilderを使用する2つの最も一般的な方法です)か、別のファイルから文字列を読み込む必要があります。

大きな複数行の文字列リテラルの場合、別のファイルを使用し、それを使用してそれを読み取る傾向がありますgetResourceAsStream()(メソッドClassクラスの。これにより、現在のディレクトリとコードがインストールされている場所を気にする必要がないため、ファイルを簡単に見つけることができます。また、jarファイルに実際にファイルを格納できるため、パッケージ化も簡単になります。

Fooというクラスにいるとします。次のようなことをしてください:

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

もう1つの問題は、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 2012年

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マシンでは問題ありません。
Stefan Thyberg、2009年

さらに、StringBuilderの存在について言及したかっただけです。
トム、

4
1つのプラス記号を6文字のメソッド名と括弧で置き換えることは、私には読みやすく見えませんが、そのように考えるのはあなただけではないようです。ただし、引用符は削除されません。彼らはまだそこにいます。
スキップホッピー2009年

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

次に、出力をコピーしてエディターに貼り付けます。

特別なケースを処理するために必要に応じてこれを変更しますが、これは私のニーズに対応しています。お役に立てれば!


9

javaと互換性があり、 "" "で囲まれたmultiline-Stringsを許可するscala-codeを使用できます。

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

これはもっと快適か...?

ソースコードに配置する必要がある長いテキストを頻繁に処理する場合の別のアプローチは、外部ファイルからテキストを取得し、それを次のようにmultiline-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、プラス表記を優先してください。


5
プラス表記よりもStringBuilderを選ぶのはなぜですか?
スキップホッピー2009年

10
効率、またはむしろそれでしばしば見当違いの試み。
マイケル・マイヤーズ

2
効率化の試みは、JavaコンパイラがStringBuilder(1.5より前のコンパイラのStringBuffer)を使用して文字列連結演算子を実装しているという事実に基づいていると思います。StringBuffer(またはStringBuilder、現在)を使用すると、特定の状況でパフォーマンスが向上するという、古くはありますがよく知られている記事があります。リンクは次のとおり
Paul

4
コンパイラーがそれを実行できない場合のみ。リテラルと定数の場合、プラス記号を使用すると、コンパイル時に連結が行われます。StringBuilderを使用すると、実行時に強制的に実行されるため、作業量が増えるだけでなく、速度が低下します。
johncip

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 '26

私はこれが好き。試して
みる

7

Java Stringfierを参照してください。必要に応じて、テキストをエスケープするStringBuilder Javaブロックに変換します。


1
はい、私は自分の人生をコピーしてそのサイトに貼り付けることができるので。ファイルに保存して読み込むこともできますが、これも理想的な解決策ではありません。
mmm

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()ことも記載されていません。


5

私と同じくらいグーグルのグアバが好きなら、それはかなりきれいな表現を与え、改行文字をハードコードしないようにする素晴らしい、簡単な方法を与えることができます:

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のような文字列に使用できます。


はい、これは私が使用するものでもあり、素晴らしい解決策です!SQLまたはXMLを外部のXMLプロパティファイルに移動します。コードを台無しにすることはありません。:)
Laszlo Lugosi 2016年

これは質問の答えにはなりません。ヒアドキュメントは定義上、ファイル内にあります。ポイントは、1か所に保管することです。
javadba 2016

5

JDK / 12アーリーアクセスビルド#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に延期



2
サイバーソフトは、他のコメントで言うように、生の文字列リテラル(JEP326)最終JDK12から削除されていますが、別のJEPはJDK 13にプレビューとして行うことができる「テキストブロック」を追加するために作成されました
マヌエル・Romeiro

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

4

1つの良いオプション。

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テキストブロックのおかげで、このクエリを次のように書き換えることができます。

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

2004年にC#を使用してからずっと、この機能をJavaで使用したいと思っていましたが、ついにそれが手に入りました。


3

プロパティファイルで文字列を定義しますか?

プロパティファイルでは複数行の文字列を使用できません。プロパティファイルで\ nを使用できますが、それはあなたの場合の解決策の多くではないと思います。


プロパティファイルの値は複数の行にまたがることがあります。最後の行を除くすべての行をバックスラッシュで終了するだけです。これはプラットフォーム固有であるため、行区切り文字として何を使用するかという問題は残ります。単純な\ nを使用して、コードでプロパティを読み取った後、検索して\ nをline.separatorに置き換えることができると思います。これは少し厄介に思えますが、プロパティを取得すると同時にこの操作を行う関数を記述できると思います。さて、これらすべては、これらの文字列をファイルに書き込むことを前提としていますが、これは大きな前提です。
ジェイ


3

ThomasPで提案されているユーティリティを使用して、それをビルドプロセスにリンクすることをお勧めします。テキストを含む外部ファイルはまだ存在しますが、実行時にファイルは読み取られません。ワークフローは次のとおりです。

  1. 'textfile to java code'ユーティリティをビルドしてバージョン管理にチェックインする
  2. 各ビルドで、リソースファイルに対してユーティリティを実行して、改訂されたJavaソースを作成します。
  3. Javaソースには次のようなヘッダーが含まれています class TextBlock {...、リソースファイルから自動生成される静的文字列が後に続くます
  4. 残りのコードで生成されたJavaファイルをビルドします

2

一連の+が使用される場合、StringBuilderは使用されません。コンパイル時にStringが決定されない限り、作成されるStringBuilderは1つだけです。

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は1つだけです。

  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

私の質問をさらに明確にするために、私はパフォーマンスについてまったく心配していません。保守性と設計の問題が心配です。

できる限り明確かつシンプルにしてください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.