String multiline Java

516

Berasal dari Perl, saya benar-benar kehilangan sarana "di sini-dokumen" untuk membuat string multi-line dalam kode sumber:

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

Di Jawa, saya harus memiliki tanda kutip yang rumit dan tanda plus di setiap baris saat saya menggabungkan string multiline saya dari awal.

Apa saja alternatif yang lebih baik? Tentukan string saya di file properti?

Sunting : Dua jawaban mengatakan StringBuilder.append () lebih disukai daripada notasi plus. Adakah yang bisa menjelaskan mengapa mereka berpikir demikian? Sama sekali tidak terlihat lebih disukai bagi saya. Saya sedang mencari cara mengatasi kenyataan bahwa string multiline bukan merupakan konstruksi bahasa kelas satu, yang berarti saya pasti tidak ingin mengganti konstruksi bahasa kelas satu (rangkaian string dengan plus) dengan pemanggilan metode.

Edit : Untuk memperjelas pertanyaan saya lebih lanjut, saya sama sekali tidak peduli dengan kinerja. Saya khawatir tentang rawatan dan masalah desain.

skiphoppy
sumber
12
StringBuilder.append () lebih disukai daripada plus ketika berulang kali menambahkan ke string karena setiap kali Anda melakukannya string1 + string2Anda mengalokasikan objek string baru dan menyalin karakter dari kedua string input. Jika Anda menambahkan n String bersama-sama Anda akan melakukan alokasi n-1 dan sekitar (n ^ 2) / 2 salinan karakter. StringBuilder, di sisi lain, menyalin dan merealokasi lebih jarang (meskipun masih melakukan keduanya ketika Anda melebihi ukuran buffer internal). Secara teoritis, ada beberapa kasus di mana kompiler dapat mengonversi + untuk menggunakan StringBuilder tetapi dalam praktiknya siapa tahu.
Laurence Gonsalves
5
Setiap kali saya beralih ke debugger, + dikonversi menjadi panggilan StringBuilder.append (), di Java 1.5. Saya punya kolega yang salah memberi tahu saya bahwa StringBuilder memiliki bug karena mereka melakukan debug ke kode yang tampaknya tidak memanggilnya dan berakhir di sana.
skiphoppy
4
Lihat juga: stackoverflow.com/questions/782810/…
Michael Myers
61
Perhatikan bahwa string literal yang terdiri dari "abc \ n" + "def \ n" dll. Tidak menggunakan StringBuilder: kompilator menempelkannya bersama-sama dan menempatkannya ke dalam file .class sebagai literal tunggal, sama seperti jenis-jenis lain dari lipat konstan.
araqnid
6
Sebagian besar IDE mendukung memasuki string multi-line. yaitu. Anda cukup ketik atau rekatkan apa yang Anda inginkan ke dalam string "" dan itu akan menambahkan \ n dan "+" sesuai kebutuhan. misalnya saya bisa menempelkan 40 baris teks ke dalam sebuah String dan IDE mengatasinya untuk Anda.
Peter Lawrey

Jawaban:

118

Stephen Colebourne telah membuat proposal untuk menambahkan string multi-line di Java 7.

Juga, Groovy sudah memiliki dukungan untuk string multi-line .

Paul Morie
sumber
14
Proses Koin Proyek untuk peningkatan ke Jawa termasuk string multi-line mail.openjdk.java.net/pipermail/coin-dev/2009-February/… . Itu ditolak oleh Oracle blogs.sun.com/darcy/entry/project_coin_final_five .
JodaStephen
8
ada perubahan di 2012?
Ilia G
13
Sayangnya ini tampaknya tidak berhasil masuk spesifikasi.
namuol
3
Tautan blogs.sun.com rusak, tetapi saya pikir isinya ada di blogs.oracle.com/darcy/entry/project_coin_final_five sekarang.
Donal Fellows
8
Tampaknya, pada Januari 2018, komunitas ini mempertimbangkan kembali string multi-line. openjdk.java.net/jeps/326
Shane Gannon
485

Sepertinya Anda ingin melakukan multiline literal, yang tidak ada di Jawa.

Alternatif terbaik Anda akan menjadi string yang hanya +bersama. Beberapa opsi lain yang telah disebutkan orang (StringBuilder, String.format, String.join) hanya akan lebih disukai jika Anda mulai dengan array string.

Pertimbangkan ini:

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

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

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

Jika Anda ingin baris baru untuk sistem tertentu, Anda baik perlu digunakan System.lineSeparator(), atau Anda dapat menggunakan %ndi String.format.

Pilihan lain adalah menempatkan sumber daya dalam file teks, dan cukup membaca konten file itu. Ini lebih disukai untuk string yang sangat besar untuk menghindari kembung yang tidak perlu file kelas Anda.

Kip
sumber
246
Selanjutnya, versi pertama akan secara otomatis digabungkan oleh kompiler, karena semua string diketahui pada waktu kompilasi. Bahkan jika string tidak dikenal pada waktu kompilasi, itu tidak lebih lambat dari StringBuilder atau String.format (). Satu-satunya alasan untuk menghindari penggabungan dengan + adalah jika Anda melakukannya dalam satu lingkaran.
Michael Myers
23
Masalah dengan String.formatversi ini adalah Anda harus menjaga format tetap sinkron dengan jumlah baris.
Bart van Heukelom
4
String.format tidak efisien dibandingkan dengan dua contoh lainnya
cmcginty
10
Jawaban ini adalah solusi yang sangat tidak sesuai untuk pertanyaan yang ada. Kami memiliki 2000 baris makro SAS atau kumpulan 200 query SQL baris yang ingin kami salin dan tempel. Untuk menyarankan bahwa kami menggunakan + "" concat untuk mengubah teks multiline itu menjadi menambahkan StringBuffer adalah konyol.
Blessed Geek
21
@BlessedGeek: pertanyaan yang ada adalah tentang opsi apa yang tersedia dalam bahasa Java. Itu tidak menyebutkan apa pun tentang tipe data yang masuk ke string. Jika ada solusi yang lebih baik maka Anda dapat mempostingnya sebagai jawaban. Sepertinya solusi Josh Curren akan lebih baik untuk situasi Anda. Jika Anda hanya kesal karena bahasa tersebut tidak mendukung literal multiline maka ini adalah tempat yang salah untuk mengeluh tentang itu.
Kip
188

Dalam Eclipse jika Anda mengaktifkan opsi "Teks melarikan diri ketika menempelkan ke string literal" (dalam Preferensi> Java> Editor> Mengetik) dan tempel string multi- baris mengutip kutipan, itu akan secara otomatis menambah "dan \n" +untuk semua baris Anda.

String str = "paste your text here";
Monir
sumber
15
intelij juga melakukan ini secara default ketika Anda menempelkan ke "" s
Bob B
Apakah Anda biasanya meninggalkan \rs yang Eclipse masukkan pada Windows?
Noumenon
99

Ini adalah utas lama, tetapi solusi baru yang cukup elegan (dengan hanya 4 mungkin 3 kekurangan kecil) adalah menggunakan anotasi khusus.

Periksa: http://www.adrianwalker.org/2011/12/java-multiline-string.html

Sebuah proyek yang terinspirasi dari pekerjaan itu diselenggarakan di GitHub:

https://github.com/benelog/multiline

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

Kekurangannya adalah

  1. Anda harus mengaktifkan prosesor penjelasan yang sesuai (disediakan).
  2. bahwa variabel String tidak dapat didefinisikan sebagai variabel lokal Periksa proyek Raw String Literals mana Anda dapat mendefinisikan variabel sebagai variabel lokal
  3. String itu tidak dapat berisi variabel lain seperti dalam Visual Basic .Net dengan XML literal (<%= variable %> ) :-)
  4. String literal dibatasi oleh komentar JavaDoc (/ **)

Dan Anda mungkin harus mengkonfigurasi Eclipse / Intellij-Idea untuk tidak memformat ulang komentar Javadoc Anda secara otomatis.

Orang mungkin menemukan ini aneh (komentar Javadoc tidak dirancang untuk menanamkan apa pun selain komentar), tetapi karena kurangnya string multiline di Jawa pada akhirnya benar-benar menjengkelkan, saya menemukan ini menjadi solusi yang paling tidak terburuk.

SRG
sumber
Apakah itu mengharuskan kelas menggunakan string multiline menjadi final? Juga, apakah ada pengaturan yang diperlukan saat mengembangkan dan menjalankan kode dari Eclipse? URL referensi menyebutkan persyaratan penyiapan untuk Maven untuk pemrosesan anotasi. Saya tidak tahu apa yang mungkin dibutuhkan, jika ada di Eclipse.
David
Anotasi itu dapat ditinggali - tetapi tampaknya ada juga ketergantungan yang kuat pada pakar? Bagian itu menghilangkan banyak nilai heredoc yang menyederhanakan pengelolaan potongan-potongan kecil teks.
javadba
3
Anda dapat melakukan ini sepenuhnya dalam gerhana. Tautan yang diposting @SRG di atas menunjukkan Anda ke tautan ini . Jika Anda menggunakan gerhana, maka satu menit setup dan berfungsi.
Michael Plautz
4
Ini mungkin hack terbesar yang pernah saya lihat. EDIT: Nevermind ... lihat jawaban Bob Albrights.
Llew Vallis
1
Saya membuat perpanjangan dari proyek ini dan membuat yang baru yang variabel lokal didukung, lihat proyek
deFreitas
62

Opsi lain mungkin untuk menyimpan string panjang dalam file eksternal dan membaca file menjadi string.

Josh Curren
sumber
13
Persis. Sejumlah besar teks tidak termasuk dalam sumber Java; sebagai gantinya gunakan file sumber daya dari format yang sesuai, dimuat melalui panggilan ke Class.getResource (String).
erickson
5
Baik! Anda dapat menggunakan Lokal + ResourceBundle juga untuk dengan mudah memuat teks I18N, dan kemudian panggilan String.format () akan menguraikan "\ n" sebagai baris baru :) Contoh: String readyStr = String.parse (resourceBundle.getString (" pengantar"));
ATorras
62
Anda tidak harus mengeksternalisasi sebuah String hanya karena multi-line. Bagaimana jika saya memiliki regex yang ingin saya bagi menjadi beberapa baris dengan komentar? Terlihat jelek di Jawa. The @sintaks untuk C # jauh lebih bersih.
Jeremy Stein
8
Skiphoppy tidak ingin repot dengan biaya overhead berurusan dengan file hanya dengan menggunakan konstanta panjang paragraf. Saya menggunakan string multiline sepanjang waktu di C ++, tertanam dalam kode sumber saya, di mana saya menginginkannya.
Tim Cooper
9
Wow. Saya tidak percaya C ++ sebenarnya lebih baik daripada Java dalam masalah ini! Saya suka konstanta string multi-line dan mereka DO dalam sumber dalam beberapa kasus.
Pengguna1
59

Ini adalah sesuatu yang seharusnya tidak pernah Anda miliki gunakan tanpa memikirkan apa yang dilakukannya. Tetapi untuk skrip satu kali, saya telah menggunakan ini dengan sangat sukses:

Contoh:

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

Kode:

// 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();
}
Bob Albright
sumber
15
Membutuhkan pengiriman kode Java untuk kelas dengan biner terakhir. Hmm.
Thorbjørn Ravn Andersen
23
saya bisa membayangkan reaksi rekan kerja saya ketika saya mencoba memeriksa sesuatu seperti ini di ...
Landon Kuhn
15
+1. Beberapa kurangnya imajinasi oleh orang-orang yang memilih. Ini adalah konstruksi yang berguna untuk menulis utilitas kecil, uji kasus, dan bahkan dalam lingkungan prod terkendali. Ini adalah pembuat perbedaan antara keluar dari java ke ruby ​​/ python / etc atau tinggal di sini.
javadba
1
Solusi hebat, tetapi sayangnya tidak akan berfungsi untuk android karena akan dijalankan pada emulator atau perangkat nyata dan tidak ada kode sumber di sana.
evgeny.myasishchev
Mungkin dengan Java 8 prob, atau yang lain, tetapi classLoader pada contoh tidak ada. Saya mencoba menggunakan MyClass.class.getResourceAsStream (...), tetapi selalu mengembalikan null. Akan menjadi solusi cepat yang bagus untuk pengujian!
Nick
54

String.join

Java 8 menambahkan metode statis baru java.lang.Stringyang menawarkan alternatif yang sedikit lebih baik:

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

Menggunakannya:

String s = String.join(
    System.getProperty("line.separator"),
    "First line.",
    "Second line.",
    "The rest.",
    "And the last!"
);
icza
sumber
5
Solusi rapi dan bersih! Tidak ada ketergantungan pada IDE dan preprosesor! Tidak "\n"diperlukan manual , dan menyadari portabilitas!
Siu Ching Pong -Asuka Kenji-
1
Saya mengerti bahwa komentar saya tidak berguna, tetapi begitu retarted untuk mencari peretasan untuk hal mendasar seperti multiline string literal. Kenapa sih tidak bisa java masih menambahkan ini ke dalam spec?
dmitry
22

JEP 355: Blok Teks (Pratinjau) bertujuan untuk mencakup fungsi ini, saat ini menargetkan JDK 13 sebagai fitur pratinjau. Mengizinkan untuk menulis sesuatu seperti:

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

Sebelum JEP ini, di JDK12, JEP 326: Raw String Literals bertujuan untuk mengimplementasikan fitur yang serupa, tetapi akhirnya ditarik.

alostale
sumber
2
Mereka menjatuhkan dukungan ini
deFreitas
2
Blok teks sekarang menjadi bagian dari Java 13.
ZhekaKozlov
19

Jika Anda mendefinisikan string dalam file properti, itu akan terlihat jauh lebih buruk. IIRC, akan terlihat seperti:

string:text\u000atext\u000atext\u000a

Biasanya ide yang masuk akal untuk tidak menanamkan string besar ke sumber. Anda mungkin ingin memuatnya sebagai sumber daya, mungkin dalam XML atau format teks yang dapat dibaca. File teks dapat dibaca pada saat runtime atau dikompilasi ke sumber Java. Jika Anda akhirnya menempatkannya di sumber, saya sarankan meletakkannya +di depan dan menghilangkan baris baru yang tidak perlu:

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

Jika Anda memiliki baris baru, Anda mungkin ingin beberapa metode bergabung atau memformat:

final String text = join("\r\n"
    ,"text"
    ,"text"
    ,"text"
);
Tom Hawtin - tackline
sumber
17

Plus dikonversi menjadi StringBuilder.append, kecuali jika kedua string adalah konstanta sehingga kompiler dapat menggabungkannya pada waktu kompilasi. Setidaknya, begitulah dalam kompiler Sun, dan saya akan curiga jika tidak semua kompiler lain akan melakukan hal yang sama.

Begitu:

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

biasanya menghasilkan kode yang persis sama dengan:

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

Di samping itu:

String c="Hello"+"Goodbye";

sama dengan:

String c="HelloGoodbye";

Artinya, tidak ada penalti dalam memutus string string Anda di beberapa baris dengan tanda plus untuk dibaca.

Jay
sumber
4
untuk menjadi teknis, dalam contoh pertama Anda menghasilkan sesuatu yang lebih seperti: String c = new StringBuilder (). append (a) .append (b) .toString (); Perbedaannya adalah bahwa pembuat string sementara berada di luar ruang lingkup dan memenuhi syarat untuk pengumpulan sampah segera setelah baris String c = ..., sedangkan pembuat string "temp" akan tetap ada sedikit lebih lama.
Kip
Benar. Maksud saya, tentu saja, adalah untuk membedakan kapan suatu fungsi dipanggil pada saat run-time versus ketika pekerjaan dapat dilakukan pada waktu kompilasi. Tapi kamu benar.
Jay
15

Di IntelliJ IDE, Anda hanya perlu mengetik:

""

Lalu posisikan kursor Anda di dalam tanda kutip dan tempelkan string Anda. IDE akan mengembangkannya menjadi beberapa baris gabungan.

nurettin
sumber
11

Sayangnya, Java tidak memiliki string multi-line literal. Anda harus menggabungkan string literal (menggunakan + atau StringBuilder menjadi dua pendekatan paling umum untuk ini) atau membaca string dalam dari file terpisah.

Untuk multi-line string literal besar saya cenderung menggunakan file terpisah dan membacanya menggunakan getResourceAsStream() (metodeClass kelas). Ini membuatnya mudah untuk menemukan file karena Anda tidak perlu khawatir tentang direktori saat ini versus di mana kode Anda diinstal. Ini juga membuat pengemasan lebih mudah, karena Anda sebenarnya dapat menyimpan file dalam file jar Anda.

Misalkan Anda berada di kelas yang disebut Foo. Lakukan sesuatu seperti ini:

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

Satu gangguan lain adalah bahwa Java tidak memiliki standar "baca semua teks dari Pembaca ini menjadi metode". Sangat mudah untuk menulis:

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();
}
Laurence Gonsalves
sumber
Saya melakukan hal yang sama. Anda dapat menggunakan commons-io untuk lebih mudah membaca konten file (dengan "FileUtils.readFileToString (File file)").
SRG
Tidak benar lagi tentang java tidak memiliki standar membaca semua metode teks ... - karena Java 7 Anda dapat menggunakan Files.readAllLines (Path)
ccpizza
10
String newline = System.getProperty ("line.separator");
string1 + newline + string2 + newline + string3

Tapi, alternatif terbaik adalah menggunakan String.format

String multilineString = String.format("%s\n%s\n%s\n",line1,line2,line3);
Tom
sumber
Pendapat saya adalah menghilangkan tanda plus dan tanda kutip, membuatnya lebih mudah dibaca, khususnya ketika ada lebih dari 3 baris. Tidak sebagus String.format.
Tom
2
Contoh Stringbuilder setidaknya sama tidak terbaca. Juga, jangan lupa bahwa "\ n" tidak selalu merupakan baris baru, tetapi tidak masalah untuk linux dan mesin unix.
Stefan Thyberg
Plus, hanya ingin menyebutkan keberadaan StringBuilder.
Tom
4
Mengganti satu tanda tambah dengan nama metode enam karakter dan tanda kurung tidak terlihat lebih mudah dibaca oleh saya, meskipun tampaknya Anda bukan satu-satunya yang berpikir seperti itu. Itu tidak menghapus tanda kutip. Mereka masih di sana.
skiphoppy
9

Karena Java belum (belum) mendukung string multi-line, satu-satunya cara untuk sekarang adalah meretasnya menggunakan salah satu teknik yang disebutkan di atas. Saya membuat skrip Python berikut menggunakan beberapa trik yang disebutkan di atas:

import sys
import string
import os

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

Masukkan itu ke dalam file bernama javastringify.py dan string Anda di file mystring.txt dan jalankan sebagai berikut:

cat mystring.txt | python javastringify.py

Anda kemudian dapat menyalin output dan menempelkannya ke editor Anda.

Ubah ini sesuai kebutuhan untuk menangani setiap kasus khusus tetapi ini sesuai dengan kebutuhan saya. Semoga ini membantu!

scorpiodawg
sumber
9

Anda dapat menggunakan scala-code, yang kompatibel dengan java, dan memungkinkan multiline-Strings terlampir dengan "" ":

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

(perhatikan kutipan di dalam string) dan dari java:

String s2 = foobar.SWrap.bar ();

Apakah ini lebih nyaman ...?

Pendekatan lain, jika Anda sering menangani teks panjang, yang harus ditempatkan dalam kode sumber Anda, mungkin berupa skrip, yang mengambil teks dari file eksternal, dan membungkusnya sebagai multiline-java-String seperti ini:

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

sehingga Anda dapat memotong dan menempelkannya dengan mudah ke sumber Anda.

pengguna tidak diketahui
sumber
8

Anda dapat menggabungkan pelengkap Anda dengan metode terpisah seperti:

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

Either way, lebih suka StringBuildernotasi plus.

pengguna54579
sumber
5
Mengapa saya lebih suka StringBuilder daripada notasi plus?
skiphoppy
10
Efisiensi, atau lebih tepatnya upaya yang sering salah arah.
Michael Myers
2
Upaya efisiensi didasarkan, saya pikir, pada kenyataan bahwa Java compiler mengimplementasikan operator rangkaian string menggunakan StringBuilder (StringBuffer dalam kompiler pra-1.5). Ada artikel lama, tetapi terkenal yang menyatakan bahwa ada manfaat kinerja dalam situasi tertentu untuk menggunakan StringBuffer (atau StringBuilder, sekarang). Berikut tautannya: java.sun.com/developer/JDCTechTips/2002/tt0305.html
Paul Morie
4
Hanya ketika kompiler tidak dapat melakukannya. Untuk literal dan konstanta, jika Anda menggunakan tanda plus, penggabungan dilakukan pada waktu kompilasi. Menggunakan StringBuilder memaksa hal itu terjadi saat runtime, jadi ini bukan hanya pekerjaan, lebih lambat.
johncip
7

Sebenarnya, berikut ini adalah implementasi terbersih yang saya lihat sejauh ini. Ini menggunakan anotasi untuk mengubah komentar menjadi variabel string ...

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

Jadi, hasil akhirnya adalah bahwa variabel html berisi string multiline. Tidak ada kutipan, tidak ada plus, tidak ada koma, hanya string murni.

Solusi ini tersedia di URL berikut ... http://www.adrianwalker.org/2011/12/java-multiline-string.html

Semoga itu bisa membantu!

Rodney P. Barbati
sumber
Prosesor anotasi itu perlu pengecekan yang lebih kuat,
Tripp Kinetics
saya suka ini. Mencoba keluar
javadba
7

Lihat Java Stringfier . Mengubah teks Anda menjadi blok java StringBuilder keluar jika diperlukan.

Leo
sumber
1
Ya, karena saya bisa menghabiskan salinan hidup saya dan menempelkannya ke situs itu. Saya juga bisa menyimpannya dalam file dan memuatnya, tetapi itu juga bukan solusi yang ideal.
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");
Mykhaylo Adamovych
sumber
6

Alternatif yang belum saya lihat sebagai jawabannya adalah 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();

Juga fakta yang java.io.BufferedWritermemiliki newLine()metode tidak disebutkan.

BalusC
sumber
5

Jika Anda menyukai jambu google sebanyak yang saya lakukan, itu dapat memberikan representasi yang cukup bersih dan cara yang bagus dan mudah untuk tidak membuat hardcode karakter baris baru Anda juga:

String out = Joiner.on(newline).join(ImmutableList.of(
    "line1",
    "line2",
    "line3"));
Dan Lo Bianco
sumber
5

Gunakan Properties.loadFromXML(InputStream). Tidak perlu untuk lib eksternal.

Lebih baik daripada kode yang berantakan (karena perawatan dan desain menjadi perhatian Anda), lebih disukai untuk tidak menggunakan string panjang.

Mulailah dengan membaca properti xml:

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


maka Anda dapat menggunakan string multiline dengan cara yang lebih mudah dikelola ...

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


MultiLine.xml` terletak di folder YourClass yang sama:

<?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 .: Anda dapat menggunakan <![CDATA["... "]]>untuk string seperti xml.

jpfreire
sumber
Ya, ini yang saya gunakan juga, solusi hebat! Pindahkan SQL atau XML ke file properti XML eksternal. Itu tidak mengacaukan kode. :)
Laszlo Lugosi
Ini tidak menjawab pertanyaan. heredoc menurut definisi dalam file . Intinya adalah menyimpannya di satu tempat.
javadba
5

Dengan JDK / 12 akses awal build # 12 , seseorang sekarang dapat menggunakan string multiline di Jawa sebagai berikut:

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

dan ini menghasilkan output sebagai berikut:

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

Sunting: Ditunda ke java 13

Naman
sumber
1
Ini adalah cara untuk mencobanya menggunakan pakar
Naman
2
Seperti yang dikatakan cybersoft di komentar lain, literal string mentah (JEP326) telah dihapus dari JDK12 final, tetapi JEP lain telah dibuat untuk menambahkan "Blok teks" yang dapat dilakukan sebagai pratinjau di JDK 13
Manuel Romeiro
4

Solusi independen yang cukup efisien dan platform akan menggunakan properti sistem untuk pemisah baris dan kelas StringBuilder untuk membangun string:

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
sumber
4

Satu pilihan bagus.

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

    }
Bruno Lee
sumber
4

Ini adalah pertanyaan yang sangat umum, jadi saya memutuskan untuk mengubah jawaban ini menjadi artikel juga .

Java 13 dan selanjutnya

Multiline Strings sekarang didukung di Jawa melalui Blok Teks . Di Java 13 dan 14, fitur ini mengharuskan Anda untuk mengatur ––enable–previewopsi saat membangun dan menjalankan proyek Anda. Lihat dokumentasi Java ini untuk lebih jelasnya.

Sekarang, sebelum Java 13, ini adalah bagaimana Anda akan menulis kueri:

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

Berkat Blok Teks Java 13, Anda dapat menulis ulang kueri ini sebagai berikut:

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

Jauh lebih mudah dibaca, bukan?

Dukungan IDE

IntelliJ IDEA menyediakan dukungan untuk mengubah Stringblok gabungan legacy ke Stringformat multiline baru :

IntelliJ IDEA mendukung Blok Teks

JSON, HTML, XML

Multiline Stringsangat berguna saat menulis JSON, HTML, atau XML.

Pertimbangkan contoh ini menggunakan Stringpenggabungan untuk membangun string literal 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" +
        "       }" +
        "   ]" +
        "}"
    )
);

Anda hampir tidak dapat membaca JSON karena karakter yang melarikan diri dan banyaknya tanda kutip ganda dan tanda plus.

Dengan Blok Teks Java, objek JSON dapat ditulis seperti ini:

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

Sejak saya menggunakan C # pada tahun 2004, saya ingin memiliki fitur ini di Java, dan sekarang akhirnya kita memilikinya.

Vlad Mihalcea
sumber
3

Tentukan string saya di file properti?

String multiline tidak diizinkan dalam file properti. Anda dapat menggunakan \ n dalam file properti, tetapi saya rasa itu bukan solusi dalam kasus Anda.

Tidur
sumber
Nilai dalam file properti dapat menjangkau beberapa baris: Cukup akhiri semua baris tetapi yang terakhir dengan backslash. Ini memang meninggalkan masalah apa yang Anda gunakan sebagai pemisah garis, karena ini adalah platform khusus. Saya kira Anda dapat menggunakan \ n sederhana dan kemudian dalam kode Anda, setelah membaca properti, lakukan pencarian-dan-ganti \ n ke line.separator. Tampaknya agak kludgey, tapi saya kira Anda bisa menulis fungsi yang mengambil properti dan melakukan manipulasi ini pada saat yang sama. Nah, semua itu mengasumsikan bahwa Anda akan menulis string ini ke file, yang merupakan asumsi besar.
Jay
3

Saya menyarankan menggunakan utilitas seperti yang disarankan oleh ThomasP, dan kemudian menautkannya ke proses build Anda. File eksternal masih ada berisi teks, tetapi file tersebut tidak dibaca saat runtime. Alur kerjanya adalah:

  1. Bangun utilitas 'textfile to java code' & periksa kontrol versi
  2. Pada setiap build, jalankan utilitas terhadap file sumber daya untuk membuat sumber java yang direvisi
  3. Sumber Java berisi header seperti class TextBlock {... diikuti oleh string statis yang dihasilkan secara otomatis dari file sumber daya
  4. Bangun file java yang dihasilkan dengan sisa kode Anda
horace
sumber
2

Ketika serangkaian panjang + digunakan, hanya satu StringBuilder dibuat, kecuali String ditentukan pada waktu kompilasi dalam hal ini tidak ada StringBuilder digunakan!

Satu-satunya waktu StringBuilder lebih efisien adalah ketika banyak pernyataan digunakan untuk membangun 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);

Catatan: Hanya satu StringBuilder yang dibuat.

  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

Untuk memperjelas pertanyaan saya lebih lanjut, saya sama sekali tidak peduli dengan kinerja. Saya khawatir tentang rawatan dan masalah desain.

Buat sejelas dan sesederhana mungkin.

Peter Lawrey
sumber