티스토리 뷰

텍스트 블록 기능이 자바 15에 정식으로 추가 되었다. 기능 추가가 아닌 언어적인 변화로 자바에서 XML, SQL 등 멀티라인으로 문자열을 사용하는 개발자들에게 희소식이다. 자바 13, 14에서 프리뷰로 추가되었고 15에 정식으로 발표되었다. 텍스트 블록에 대한 정의는 다음과 같이 내리고 있다.

 

A text block is a multi-line string literal that avoids the need for most escape sequences, automatically formats the string in a predictable way, and gives the developer control over the format when desired.

 

여기서 중요한 점은 멀티라인을 작성하기 위해 이스케이프 시퀀스가 필요없다는 것이다. 이 블로그 포스팅은  https://openjdk.java.net/jeps/378 에 기술되어 있는 JEP 378 내용을 참고하였다.

 

텍스트 블록은 자바 프로그램에서 멀티 라인의 문자열을 에스케이프 시퀀스 없이 사용함으로 소스 코드 작성을 편리하게 하고 코드의 가독성을 높이는데 주된 목적을 가지고 있다. 하지만, String 클래스 (혹은 객체)와 문자열 조합을 위한 '+' 연산을 대체하는 것은 아니다.

 

그럼 이제부터 예제를 통해서 텍스트 블록이 어떤 것인지 알아보겠다.

 

1. HTML 작성시 예제

- 기존 문자열 조합 방식

// 문자열 조합
String html1 = "<html>\n" +
          "    <body>\n" +
          "        <p>Hello, world</p>\n" +
          "    </body>\n" +
          "</html>\n";

- 텍스트 블록 방식

// 텍스트 블록
String html2 = """
          <html>
              <body>
                  <p>Hello, world</p>
              </body>
          </html>
          """;

 

2. SQL 작성시 예제

- 기존 문자열 조합 방식

String query1 = "SELECT \"EMP_ID\", \"LAST_NAME\" FROM \"EMPLOYEE_TB\"\n" +
           "WHERE \"CITY\" = 'INDIANAPOLIS'\n" +
           "ORDER BY \"EMP_ID\", \"LAST_NAME\";\n";

- 텍스트 블록 방식

String query = """
           SELECT "EMP_ID", "LAST_NAME" FROM "EMPLOYEE_TB"
           WHERE "CITY" = 'INDIANAPOLIS'
           ORDER BY "EMP_ID", "LAST_NAME";
           """;

 

2개의 예제를 통해서 확인할 수 있듯이 텍스트 블록은 """ ~ """ 코드 사이에 있는 문자열을 특별히 이스케이프 문자나 스트링 조합 연산 없이 그대로 String 객체로 인식 시킬 수 있다. 특히 문자열 내에 " 가 필요할 경우 기존에는 \"로 표시해야 하는 번거로움이 있었지만 텍스트 블록에서는 바로 인식한다. 또한 문자열 내에서 라인을 분리할 경우 개행 문자인 \n을 문자열 사이에 포함시켜야 했지만 텍스트 블록에서는 바로 엔터 값을 인식한다.

여기서 주의할 점은 블록을 시작하는 """ 뒤에는 문자열이 바로 나오면 컴파일 에러가 발생한다. 위의 예제와 같이 """ 후에 한 라인을 띈후 문자열을 작성해야 텍스트 블록으로 인식 하고 컴파일에 성공한다. 기존 문자열 (String literal)과 구분하기 위한 것이다.

 

3. 개행 처리 관련 주의 사항

SQL이나 XML 등을 작성할 때 마지막 개행과 관련해서 존재 여부에 따라 특별히 문제가 없지만 좀더 정확한 문자열 처리가 필요한 경우를 위해 이를 명확히 이해할 필요가 있다. 텍스트 블록은 """ ~ """ 사이에 있는 모든 엔터값을 개행 문자로 인식한다. (""" 다음에 오는 첫번째 개행은 제외)

예를 들어 아래와 같은 텍스트 블록은

"""

line 1

line 2

line 3

"""

 

다음과 같은 문자열과 동일하다

"line 1\nline 2\nline 3\n" // "\nline 1\nline 2\nline 3\n" 이 아님에 주의해야 한다.

 

만일 텍스트 블록을 다음과 같이 작성하였다면

"""

line 1

line 2

line 3"""

 

다음과 같은 문자열로 인식된다.

"line 1\nline 2\nline 3" // 마지막에 \n 이 붙지 않았다.

 

이외에도 몇가지 텍스트 블록 관련해서 잘못된 코딩은 다음과 같다.

// 잘못된 예제 - 컴파일 에러가 발생한다.
String ill1 = """ """;
String ill2 = """""";
String ill3 = """
				
		";
String ill4 = """
		abc \ def
		""";

위의 예제에서 사용한 텍스트 블록 4가지는 모두 컴파일 에러가 난다. 문법적으로 """ ~ """ 블록 사이에는 반드시 하나 이상의 엔터 값이 있어야 한다. 엔터 값 없이 블록 사이에 문자열만 포함시켜 놓으면 컴파일 에러가 발생한다.

이 중 특이한 것은 텍스트 블록 내에 \ 문자는 컴파일 에러가 발생한다는 점이다. 텍스트 블록의 특성상 문자 그대로 인식할 것 같지만 유일하게 \는 이스케이프 시퀀스로 인식되기 때문이며 해당 값을 반영하길 원하면 기존처럼 \\로 작성해야 한다.

 

4. 들여쓰기 규칙

별로 신경 쓰지 않는 개발자들도 있겠지만 SQL, XML 문장 등을 작성할 때는 들여쓰기가 코드의 가독성을 높이는데 매우 중요하다. 그러므로 텍스트 블록을 사용할 때 이러한 들여쓰기를 문자열에 반영하기 위해서 여러가지 배려를 해 놓았으며 이러한 규칙을 이해할 필요가 있다.

텍스트 블록에서 들여쓰기 규칙은 블록을 종료하는 """의 위치에 의해 결정된다. 예제를 통해 결과를 확인해 보자.

// 들여쓰기 예제
String html2 = """
          <html>
              <body>
                  <p>Hello, world</p>
              </body>
          </html>
          """;

System.out.println(html2);

String html3 = """
          <html>
              <body>
                  <p>Hello, world</p>
              </body>
          </html>
""";

System.out.println(html3);

위의 예제에서 첫번째 html2의 출력 결과는 다음과 같다.

 

<html>
    <body>
        <p>Hello, world</p>
    </body>
</html>

 

두번째 html3의 출력 결과는 다음과 같다.

 


          <html>
              <body>
                  <p>Hello, world</p>
              </body>
          </html>

 

차이점은 텍스트 블록을 닫는 """ 위치를 기준으로 한다. 그러므로 시작 """ 보다는 들여쓰기 입장에서는 종료 """가 중요하다.

 

5. 텍스트 블록과 문자열 + 연산

자바에서 유일하게 연산자 오버라이드 된것은 + 으로 두개의 문자열을 합치는 역할을 한다. 그리고 이 연산자를 이용해서 개발자가 문자열을 합치고, 특정 변수 값과 합치는 작업을 수행한다. 당연히 텍스트 블록을 사용하고 싶어하는 개발자는 + 연산을 이용해서 기존과 동일하게 문자열을 처리하는 것에 관심이 있을 것이다.

결론적으로 말하면 문자열과 텍스트 블록은 + 연산으로 합치는 작업이 가능하다. 하지만 안타깝게도 텍스트 블록내에서 + 연산을 이용해 특정 값을 합치거나 변수 처리하는 것은 불가능하다. 왜냐하면 텍스트 블록 내에서는 + 도 특수 문자가 아니라 하나의 값으로 인식하기 때문이다.

몇가지 예제를 통해 살펴보도록 하겠다.

String code1 = "public void print(Object o) {" +
          """
              System.out.println(Objects.toString(o));
          }
          """;

System.out.println(code1);

String type = "Object";
String code2 = """
          public void print(""" + type + """
           o) {
              System.out.println(Objects.toString(o));
          }
          """;

System.out.println(code2);

 

위의 예제에서 code1 은 문자열과 텍스트 블록을 합친 것으로 정상적으로 컴파일 되고 실행된다. code2 역시 문자열과 변수와 텍스트 블록을 + 연산으로 합치는 작업을 한 것이다.

하지만 텍스트 블록의 특성상 개행 문자, 들여쓰기 등으로 인해 원하는 결과가 안나올 수도 있고, 나오더라도 이러한 특성을 잘 이해하고 코딩을 해야 한다.

그래서 이러한 기존 방식의 + 를 이용한 연산 보다는 다음 예제와 같이 String::replace나 String::format 메소드를 이용하는 것이 훨씬 깔금하며 + 연산을 줄일 수 있는 장점을 가진다.

// Strnig::repalce 예제
String code = """
              public void print($type o) {
                  System.out.println(Objects.toString(o));
              }
              """.replace("$type", type);
              
// String.format 예제
String code = String.format("""
              public void print(%s o) {
                  System.out.println(Objects.toString(o));
              }
              """, type);

첫번째 예제는 텍스트 블록내에 자신만의 특별한 패턴으로 값을 작성하고 repalce 메소드를 이용해서 이를 치환하는 것이다. 두번째 예제는 %s 문자와 format 메소드를 조합하는 것이다. 텍스트 블록내에서도 %s는 특별한 포맷팅 값으로 인식하기 때문에 이를 응용하는 것이 코드 상으로 더 깔끔할 수 있다.

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함