155

Groovy scripts raises an error:

def a = "test"
  + "test"
  + "test"

Error:

No signature of method: java.lang.String.positive() is 
applicable for argument types: () values: []

While this script works fine:

def a = new String(
  "test"
  + "test"
  + "test"
)

Why?

lospejos
  • 1,976
  • 3
  • 19
  • 35
yegor256
  • 102,010
  • 123
  • 446
  • 597

3 Answers3

295

As groovy doesn't have EOL marker (such as ;) it gets confused if you put the operator on the following line

This would work instead:

def a = "test" +
  "test" +
  "test"

as the Groovy parser knows to expect something on the following line

Groovy sees your original def as three separate statements. The first assigns test to a, the second two try to make "test" positive (and this is where it fails)

With the new String constructor method, the Groovy parser is still in the constructor (as the brace hasn't yet closed), so it can logically join the three lines together into a single statement

For true multi-line Strings, you can also use the triple quote:

def a = """test
test
test"""

Will create a String with test on three lines

Also, you can make it neater by:

def a = """test
          |test
          |test""".stripMargin()

the stripMargin method will trim the left (up to and including the | char) from each line

tim_yates
  • 167,322
  • 27
  • 342
  • 338
  • 12
    Or simply use [stripIndent()](http://docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/CharSequence.html#stripIndent%28%29) instead of `stripMargin()`. – sschuberth Sep 17 '15 at 07:35
  • Yeah, and omit the `|` chars on the extra lines – tim_yates Sep 17 '15 at 07:57
  • In my case i cannot use " " " because i have something like a JSON i mean with many double quotes inside so i use single quotes to avoid the need of escape all those double quotes and make the code cleaner. But i also want to split the string in seveal files ... is there a different approach? – Rafael Nov 13 '15 at 09:13
  • 5
    You can use double quotes inside `"""` strings – tim_yates Nov 13 '15 at 10:12
  • @sschuberth does the stripIndent() actually work here, since the documentation states: "The line with the least number of leading spaces determines the number to remove." In this case that would be the first line with zero leading spaces. – Petri Sirkkala Jul 25 '17 at 11:05
  • 3
    Right, I've edited the answer to show how you would need to slightly reformat the code to make `stripIndent()` work. – sschuberth Jul 25 '17 at 11:18
  • @sschuberth why? Post it as a separate answer – tim_yates Jul 25 '17 at 13:50
  • 2
    Because a) I had already posted it as a comment, and b) it's not much different from this answer. – sschuberth Jul 25 '17 at 14:05
  • 1
    Anyway, as I just saw you undid my edit, I've posted it as an [answer](https://stackoverflow.com/a/45305802/1127485) now. – sschuberth Jul 25 '17 at 14:10
  • 1
    Why was the `stripIndent()` edit rolled back? It made this answer stronger, IMO. – jr. Dec 06 '17 at 05:29
43

Similar to stripMargin(), you could also use stripIndent() like

def a = """\
        test
        test
        test""".stripIndent()

Because of

The line with the least number of leading spaces determines the number to remove.

you need to also indent the first "test" and not put it directly after the inital """ (the \ ensures the multi-line string does not start with a newline).

sschuberth
  • 28,386
  • 6
  • 101
  • 146
26

You can tell Groovy that the statement should evaluate past the line ending by adding a pair of parentheses ( ... )

def a = ("test"
  + "test"
  + "test")

A second option is to use a backslash, \, at the end of each line:

def a = "test" \
  + "test" \
  + "test"

FWIW, this is identical to how Python multi-line statements work.

cmcginty
  • 113,384
  • 42
  • 163
  • 163