자바 멀티 라인 문자열


516

펄에서 왔을 때, 소스 코드에서 여러 줄로 된 문자열을 만드는 "여기 문서"라는 수단이 빠져 있습니다.

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

Java에서는 여러 줄 문자열을 처음부터 연결할 때 모든 줄에 번거로운 따옴표와 더하기 부호가 있어야합니다.

더 나은 대안은 무엇입니까? 속성 파일에서 문자열을 정의 하시겠습니까?

편집 : 두 답변은 StringBuilder.append ()가 더하기 표기법보다 바람직하다고 말합니다. 왜 그렇게 생각하는지 궁금해 할 수 있습니까? 그것은 나에게 더 바람직하지 않습니다. 여러 줄 문자열이 일류 언어 구성이 아니라는 사실을 피할 수있는 방법을 찾고 있습니다. 즉, 일차 언어 구성 (문자열 연결 플러스)을 메서드 호출로 바꾸고 싶지 않습니다.

편집 : 내 질문을 더 명확히하기 위해 성능에 전혀 관심이 없습니다. 유지 관리 및 디자인 문제가 걱정됩니다.


12
StringBuilder.append ()는 문자열을 반복해서 추가 할 때마다 string1 + string2새 문자열 객체를 할당하고 두 입력 문자열 모두에서 문자를 복사 하기 때문에 더하기를 선호합니다 . n 개의 문자열을 함께 추가하는 경우 n-1 할당 및 약 (n ^ 2) / 2 문자 복사를 수행합니다. 반면에 StringBuilder는 복사 및 재 할당 횟수를 줄입니다 (내부 버퍼의 크기를 초과해도 여전히 두 가지 모두 수행됨). 이론적으로 컴파일러가 +를 변환하여 StringBuilder를 사용할 수 있지만 실제로는 알고있는 경우가 있습니다.
Laurence Gonsalves

5
디버거로 이동할 때마다 +는 Java 1.5에서 StringBuilder.append () 호출로 변환됩니다. 동료들에게 StringBuilder가 코드를 디버그하고 호출하지 않는 것처럼 디버그하기 때문에 버그가 있다고 혼란스럽게 이야기했습니다.
skiphoppy


61
"abc \ n"+ "def \ n"등으로 구성된 문자열 리터럴은 StringBuilder를 사용하지 않습니다. 컴파일러는이를 결합하여 다른 유형의 것과 마찬가지로 단일 리터럴로 .class 파일에 넣습니다. 일정한 접는.
araqnid

6
대부분의 IDE는 여러 줄 문자열 입력을 지원합니다. 즉. 원하는 것을 ""문자열에 입력하거나 붙여 넣기 만하면 필요에 따라 \ n 및 "+"가 추가됩니다. 예를 들어 문자열에 40 줄의 텍스트를 붙여 넣을 수 있으며 IDE가 텍스트를 정렬합니다.
Peter Lawrey

답변:


118

Stephen Colebourne은 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

3
blogs.sun.com 링크가 끊어졌지만 내용이 blogs.oracle.com/darcy/entry/project_coin_final_five에 있다고 생각합니다 .
Donal Fellows

8
2018 년 1 월 현재 커뮤니티는 여러 줄 문자열을 다시 고려하고 있습니다. openjdk.java.net/jeps/326
Shane Gannon

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은 다른 두 가지 예와 비교할 때 효율적이지 않습니다
cmcginty

10
이 답변은 당면한 질문에 매우 부적절한 솔루션입니다. 복사 및 붙여 넣기하려는 2000 개의 라인 SAS 매크로 또는 200 개의 라인 SQL 쿼리 묶음이 있습니다. 우리가 + ""concat을 사용하여 여러 줄의 텍스트를 StringBuffer 추가로 변환하는 것은 말도 안됩니다.
축복받은 Geek

21
@BlessedGeek : 당면한 문제는 Java에서 어떤 옵션을 사용할 수 있는지에 관한 것이 었습니다. 문자열에 들어가는 데이터 유형에 대해서는 언급하지 않았습니다. 더 나은 솔루션이 있으면 답변으로 게시 할 수 있습니다. Josh Curren의 솔루션 이 귀하의 상황에 더 좋을 것 같습니다 . 언어가 여러 줄 리터럴을 지원하지 않는다고 화를 내면 불만을 제기하기에 잘못된 곳입니다.
Kip

188

따옴표 이내에서 여러 줄을 문자열 (환경 설정> 자바> 편집기> 입력) "문자열 리터럴에 붙여 넣을 때 탈출 텍스트"및 붙여 넣기 이클립스에서는이 옵션을 설정하면, 자동으로 추가됩니다 "\n" +모두를위한 당신의 라인.

String str = "paste your text here";

15
intelij는 ""s에 붙여 넣을 때 기본적으로이 작업을 수행합니다
Bob B

일반적으로 \rEclipse가 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. 해당 문자열 변수를 로컬 변수로 정의 할 수 없음 변수를 로컬 변수로 정의 할 수있는 원시 문자열 리터럴 프로젝트 확인
  3. 해당 문자열에는 Visual Basic .Net에서와 같이 XML 리터럴 ( <%= variable %>) 이있는 다른 변수를 포함 할 수 없습니다.
  4. 해당 문자열 리터럴은 JavaDoc 주석 (/ **)으로 구분됩니다.

그리고 Javadoc 주석을 자동으로 다시 포맷하지 않도록 Eclipse / Intellij-Idea를 구성해야합니다.

이 이상한 것을 발견 할 수도 있습니다 (Javadoc 주석은 주석 이외의 것을 포함하도록 설계되지 않았습니다). 그러나 Java에 여러 줄 문자열이 부족하기 때문에 결국 성가 시므로 이것이 최악의 해결책이라고 생각합니다.


여러 줄 문자열을 사용하는 클래스가 최종이어야합니까? 또한 Eclipse에서 코드를 개발하고 실행할 때 필요한 설정이 있습니까? 참조 URL에는 주석 처리를위한 Maven의 설정 요구 사항이 언급되어 있습니다. Eclipse에서 필요한 것이 무엇인지 파악할 수 없습니다.
David

주석은 살 수 있지만 maven에 대한 의존성이 높지 않은 것 같습니다. 이 부분은 작은 텍스트 조각의 관리를 단순화하는 heredoc의 가치를 상당 부분 제거합니다.
javadba

3
당신은 완전히 일식으로 할 수 있습니다. @SRG가 점 이상을 게시하는 링크 이 링크 . 일식을 사용하는 경우 1 분의 설정으로 작동합니다.
Michael Plautz

4
이것은 아마도 내가 본 것 중 가장 큰 핵일 것입니다. 편집 : 신경 쓰지 마라 ... Bob Albrights 답변을 참조하십시오.
Llew Vallis

1
이 프로젝트를 확장하여 지역 변수가 지원되는 새로운 프로젝트를 만들었습니다 . 프로젝트를 살펴보십시오
deFreitas

62

다른 옵션은 긴 문자열을 외부 파일에 저장하고 파일을 문자열로 읽는 것입니다.


13
바로 그거죠. 많은 양의 텍스트가 Java 소스에 속하지 않습니다. 대신 적절한 형식의 자원 파일을 사용하고 Class.getResource (String) 호출을 통해로드하십시오.
erickson

5
권리! Locale + ResourceBundle을 사용하여 I18N 텍스트를 쉽게로드 할 수 있으며 String.format () 호출은 "\ n"을 줄 바꿈으로 구문 분석합니다 :) 예 : String readyStr = String.parse (resourceBundle.getString ( " 소개"));
ATorras

62
문자열이 여러 줄이기 때문에 문자열을 외부화 할 필요가 없습니다. 주석이 포함 된 여러 줄로 나누고 싶은 정규식이 있으면 어떻게합니까? Java에서는보기 흉하다. @C # 의 구문이 훨씬 깨끗합니다.
Jeremy Stein

8
Skiphoppy는 단락 길이 문자열 상수를 사용하기 위해 파일을 처리하는 오버 헤드를 귀찮게하고 싶지 않습니다. 나는 소스 코드에 포함 된 C ++로 항상 여러 줄 문자열을 사용합니다.
Tim Cooper

9
와. 이 문제에서 C ++이 실제로 Java보다 낫다는 것을 믿을 수 없습니다! 여러 줄 문자열 상수를 좋아하고 경우에 따라 소스에 속합니다.
사용자

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 코드를 제공해야합니다. 흠.
Thorbjørn Ravn Andersen

23
내가 이런 것을 확인하려고 할 때 동료의 반응을 상상할 수 있습니다 ...
Landon Kuhn

15
+1. 투표에 참여한 사람들의 상상력 부족. 이것은 작은 유틸리티, 테스트 케이스를 작성하고 제어 된 제품 환경에서 유용한 구성입니다. 이것은 자바에서 루비 / 파이썬 등으로 떨어 뜨리거나 여기에 머무르는 것의 차이점입니다.
javadba

1
훌륭한 솔루션이지만 불행히도 안드로이드에서는 에뮬레이터 또는 실제 장치에서 실행되며 소스 코드가 없기 때문에 안드로이드에서는 작동하지 않습니다.
evgeny.myasishchev

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-아스카 켄지-1

1
내 의견은 쓸모가 없다는 것을 이해하지만 여러 줄 문자열 리터럴과 같은 기본 사항에 대한 해킹을 추구하는 것은 지체되어 있습니다. 도대체 왜 자바가 이것을 스펙에 추가 할 수 없습니까?
dmitry

22

JEP 355 : 텍스트 블록 (미리보기) 은이 기능을 다루는 것을 목표로하며 현재 JDK 13 을 미리보기 기능으로 대상 으로합니다. 다음과 같이 쓸 수 있습니다 :

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

이 JEP 이전의 JDK12에서 JEP 326 : Raw String Literals 는 유사한 기능을 구현하는 것을 목표로했지만 결국 철회되었습니다.


2
그들은이 지원을 중단했습니다
deFreitas

2
텍스트 블록은 이제 Java 13의 일부입니다.
ZhekaKozlov 1

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"문자열 빌더는 조금 더 오래 머무르는 것입니다.
Kip

진실. 물론 요점은 함수가 런타임에 호출되는 시점과 컴파일 타임에 작업을 수행 할 수있는 시점을 구별하는 것입니다. 그러나 당신은 맞습니다.
Jay

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의 모든 텍스트를 문자열로 읽는"방법이 없다는 것입니다. 그래도 작성하기가 쉽습니다.

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

아니 사실 더 이상에 대해 자바 표준은 모든 텍스트 읽기 방법이 없습니다 ... - 자바 7부터 사용할 수 Files.readAllLines (경로)
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만큼 좋지 않습니다.
Tom

2
Stringbuilder 예제는 적어도 읽을 수 없습니다. 또한 "\ n"이 항상 줄 바꿈 인 것은 아니라는 점을 잊지 마십시오. 그러나 리눅스와 유닉스 머신에는 적합합니다.
Stefan Thyberg

또한 StringBuilder의 존재를 언급하고 싶었습니다.
Tom

4
하나의 더하기 기호를 6 자로 된 메소드 이름과 괄호로 바꾸는 것이 더 읽기 쉽지는 않지만 분명히 그렇게 생각하는 사람은 아닙니다. 그러나 따옴표는 제거하지 않습니다. 그들은 여전히 ​​거기에 있습니다.
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

그런 다음 출력을 복사하여 편집기에 붙여 넣을 수 있습니다.

특별한 경우를 처리하기 위해 필요에 따라 이것을 수정하지만 이것은 내 필요에 따라 작동합니다. 도움이 되었기를 바랍니다!


9

java와 호환되며 "" "로 묶인 여러 줄 문자열을 허용하는 스칼라 코드를 사용할 수 있습니다.

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

(문자열 안의 따옴표를 참고하십시오) 및 java :

String s2 = foobar.SWrap.bar ();

이것이 더 편안한 지 ...?

소스 코드에 배치 해야하는 긴 텍스트를 자주 처리하는 경우 외부 파일에서 텍스트를 가져 와서 다음과 같이 여러 줄 Java 문자열로 래핑하는 스크립트 일 수 있습니다.

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

소스에 쉽게 잘라 붙여 넣을 수 있습니다.


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를 선호합니까?
skiphoppy

10
효율성 또는 오히려 오해의 소지가있는 시도입니다.
마이클 마이어스

2
효율성에 대한 시도는 Java 컴파일러가 StringBuilder (1.5 이전 컴파일러의 StringBuffer)를 사용하여 문자열 연결 연산자를 구현한다는 사실에 기반합니다. StringBuffer (또는 현재 StringBuilder)를 사용하면 특정 상황에서 성능 이점이 있음을 나타내는 오래되었지만 잘 알려진 기사가 있습니다. 링크는 다음과 같습니다. java.sun.com/developer/JDCTechTips/2002/tt0305.html
Paul Morie 2016 년

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

나는 이것을 좋아한다. 시도해보기
javadba

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.BufferedWriternewLine()방법은 언급되지 않은 것입니다.


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>

추신 : XML과 같은 문자열에 <![CDATA["... "]]>를 사용할 수 있습니다 .


예, 이것이 제가 사용하는 훌륭한 솔루션입니다! SQL 또는 XML을 외부 XML 특성 파일로 이동하십시오. 코드가 엉망이되지 않습니다. :)
Laszlo Lugosi

이것은 질문에 대답하지 않습니다. heredoc 은 파일 내에 정의 되어 있습니다 . 요점은 한 곳에 보관하는 것입니다.
javadba

5

으로 JDK / 12 초기 액세스 빌드 # 12는 다음과 같이, 하나는 지금 자바에서 여러 줄 문자열을 사용할 수 있습니다 :

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...

편집 : 자바 13으로 연기



2
다른 의견에서 사이버 소프트가 말한 것처럼, 원시 문자열 리터럴 (JEP326)은 최종 JDK12에서 제거되었지만 JDK 13에서 미리 볼 수있는 "텍스트 블록"을 추가하기 위해 또 다른 JEP가 작성되었습니다
Manuel 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

하나의 좋은 옵션입니다.

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

이것은 매우 일반적인 질문이므로이 답변을 기사로 전환하기로 결정했습니다 .

자바 13 이상

여러 줄 문자열은 이제 텍스트 블록을 통해 Java에서 지원됩니다 . Java 13 및 14에서이 기능을 사용하려면 ––enable–preview프로젝트를 빌드하고 실행할 때 옵션 을 설정해야합니다 . 확인 이 자바 문서를 자세한 내용은.

이제 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 Text Blocks를 사용하면 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을 사용하고 코드에서 속성을 읽은 후 line.separator로 \ n을 검색하고 바꿉니다. 약간 멍청한 것 같지만 속성을 검색하고 동시에이 조작을 수행하는 함수를 작성할 수 있다고 생각합니다. 글쎄,이 문자열을 파일에 쓸 것이라고 가정하는 것은 큰 가정입니다.
Jay


3

ThomasP가 제안한 유틸리티를 사용하여 빌드 프로세스에 연결하는 것이 좋습니다. 텍스트를 포함하기 위해 외부 파일이 여전히 존재하지만 런타임에 파일을 읽지 못합니다. 워크 플로우는 다음과 같습니다.

  1. '텍스트 파일에서 Java 코드로'유틸리티를 빌드하고 버전 제어를 확인하십시오.
  2. 각 빌드에서 자원 파일에 대해 유틸리티를 실행하여 개정 된 Java 소스를 작성하십시오.
  3. Java 소스는 ​​다음과 같은 헤더를 포함합니다. class TextBlock {... 자원 파일에서 자동 생성되는 정적 문자열 됩니다.
  4. 나머지 코드로 생성 된 Java 파일을 빌드하십시오.

2

긴 일련의 +를 사용하는 경우 컴파일 시간에 String이 결정되지 않으면 StringBuilder가 사용되지 않는 한 하나의 StringBuilder 만 작성됩니다!

StringBuilder가 더 효율적인 유일한 시간은 여러 명령문을 사용하여 문자열을 구성하는 경우입니다.

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

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

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

참고 : 하나의 StringBuilder 만 작성됩니다.

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

내 질문을 더 명확히하기 위해 성능에 전혀 관심이 없습니다. 유지 관리 및 디자인 문제가 걱정됩니다.

최대한 명확하고 간단하게 만드십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.