Перейти к основному содержимому

Синтаксис и пунктуация в Groovy

Разработчику Архитектору

Названия знаков по-английски и по-русски: Знаки препинания и символы в IT.

Синтаксис и пунктуация в Groovy

Groovy наследует пунктуацию Java, но добавляет правила для строк, замыканий и DSL. Ниже — то, что чаще всего путают при переходе с Java.

Сводка отличий от Java: Groovy и Java: совместимость. Операторы (?., ?:, ..<): операторы.


Кавычки и строки

ФормаИнтерполяцияПример
'...'Нет'Hello, $name' → буквально $name
"..."Да (GString)"Hello, $name"
'''...'''Нет, многострочноSQL, XML-шаблон
"""..."""Да, многострочноОтчёты, heredoc
/.../Regex (slashy)/\d+/
$/.../$Regex + интерполяция$/id=${id}/$

В синтаксисе языка не используются типографские апострофы — только ASCII ' и ".

def name = 'Alice'
println "Hello, $name" // Hello, Alice
println 'Hello, $name' // Hello, $name

Разбор:

  • def name = 'Alice' — переменная со строкой в одинарных кавычках: интерполяция отключена.
  • println "Hello, $name"GString в двойных кавычках: $name заменяется на Alice → вывод Hello, Alice.
  • println 'Hello, $name' — одинарные кавычки: символы $name печатаются как текст → Hello, $name.
  • Разница критична в логах и SQL: шаблоны с подстановкой — только "..." или """...""".
  • Комментарии // в конце строки поясняют ожидаемый вывод при обучении.

Пример — вложенные GString и многострочный текст:

def javaStyleString = 'java String style'
def gStringStyle = "${javaStyleString}"
def literalDollar = '${javaStyleString}'
def bigGroovyString = """
${javaStyleString}
${gStringStyle}
"""
println bigGroovyString

Разбор:

  • 'java String style' — обычный Java-совместимый String без интерполяции.
  • "${javaStyleString}"GString с подстановкой значения переменной.
  • '${javaStyleString}' в одинарных кавычках — символы $ и { остаются буквально.
  • Тройные двойные кавычки """...""" — многострочный GString с интерполяцией в каждой строке.
  • println bigGroovyString выведет три строки с текстом java String style.

Точка, запятая, скобки

  • Точка . — доступ к свойству или методу; у одноаргументных методов скобки часто опускают: println 'hi'.
  • Запятая , — элементы списка, аргументы, именованные параметры: createUser name: 'Ann', age: 30.
  • Точка с запятой ; — разделитель на одной строке; в обычном Groovy-коде не обязательна.
def list = [1, 2, 3]
println list.size()

def x = 5; def y = 10; println x + y // допустимо, но редко

Разбор:

  • Фрагмент на groovy показывает рабочий пример — начинается с def list = [1, 2, 3] и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы методов и объявления функций задают основной шаг логики: входные значения передаются в метод и сразу обрабатываются.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Замыкания (closures)

Блок { ... } — значение первого класса: его можно передать в метод.

def greet = { name -> "Hello, $name" }
assert greet('Bob') == 'Hello, Bob'

[1, 2, 3].each { println it } // it — неявный параметр

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с def greet = { name -> "Hello, $name" } и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы методов и объявления функций задают основной шаг логики: входные значения передаются в метод и сразу обрабатываются.
  • Поток выполнения строится на итерации: код последовательно применяет одну и ту же операцию к набору значений.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Скобки у вызова с замыканием последним аргументом можно опустить:

list.findAll { it > 0 }
// то же: list.findAll({ it > 0 })

Параметры в методы, замыкания и функции можно передавать без скобок у одноаргументных и некоторых многоаргументных вызовов:

def closureFunction = { a, b -> a + b }
println closureFunction 1, 2 // 3
// то же: closureFunction(1, 2)

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с list.findAll { it > 0 } и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения строится на итерации: код последовательно применяет одну и ту же операцию к набору значений.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Именованные аргументы

Пары ключ — значение без скобок — идиома Groovy (конструкторы, билдеры, Gradle):

def p = new Person(name: 'Alice', age: 30)
task copyDocs(type: Copy) {
from 'docs'
into 'build/docs'
}

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с def p = new Person(name: 'Alice', age: 30) и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы методов и объявления функций задают основной шаг логики: входные значения передаются в метод и сразу обрабатываются.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

switch

В Groovy switch принимает не только примитивы — классы, списки, регулярные выражения, замыкания (в зависимости от версии и стиля).

def status = 200
switch (status) {
case 200:
case 201:
println 'OK'
break
case 400..499:
println 'Client error'
break
default:
println 'Other'
}

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с def status = 200 и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы методов и объявления функций задают основной шаг логики: входные значения передаются в метод и сразу обрабатываются.
  • Поток выполнения контролируется условиями: при разных состояниях кода выбирается соответствующая ветка и результат.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Регулярные выражения

def text = 'Order ID: 42'
assert text ==~ /Order ID: \d+/ // полное совпадение
def matcher = text =~ /(\d+)/
if (matcher) {
println matcher[0][1] // 42
}

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с def text = 'Order ID: 42' и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы методов и объявления функций задают основной шаг логики: входные значения передаются в метод и сразу обрабатываются.
  • Поток выполнения контролируется условиями: при разных состояниях кода выбирается соответствующая ветка и результат.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Подробнее: операторы.


Truthiness в условиях

В if и Elvis ?: "ложными" считаются — null, false, число 0, пустая строка '', пустые [] и [:].

def items = []
if (items) {
println 'has items' // не выполнится
}
def label = '' ?: 'default' // 'default'

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с def items = [] и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы методов и объявления функций задают основной шаг логики: входные значения передаются в метод и сразу обрабатываются.
  • Поток выполнения контролируется условиями: при разных состояниях кода выбирается соответствующая ветка и результат.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Подчёркивание _

Как в Java/Kotlin:

  • в числах: 1_000_000;
  • в циклах — "игнорируемый" параметр: (1..5).each { _ -> println 'tick' }.
def million = 1_000_000
(1..3).each { _ -> println 'tick' }

Разбор:

  • 1_000_000 — литерал с разделителями разрядов (как в Java 7+); значение то же, что 1000000.
  • (1..3)диапазон Groovy: включительно от 1 до 3; на каждой итерации closure получает номер, но _ его игнорирует.
  • println 'tick' выполнится три раза подряд.
  • Подчёркивание в параметре closure — соглашение "этот аргумент не нужен".
  • Диапазоны часто используют в switch (case 400..499) и в циклах вместо for (int i = 0; ...).

Многострочные строки и Elvis

def sql = '''
SELECT id, title
FROM books
WHERE active = true
'''
def title = null
def label = title ?: 'Без названия'
println label

Разбор:

  • '''...''' — многострочная строка без интерполяции — удобно для SQL, XML, шаблонов.
  • Переносы и отступы внутри кавычек сохраняются в значении sql.
  • title ? — 'Без названия' — оператор Elvis — если title "ложный" (null, '', 0, false), берётся правая часть.
  • println label выведет Без названия, потому что title был null.
  • Для интерполяции в многострочнике используют """...""" с $переменные.

| и ||

ОператорСмыслКороткое замыкание
|Побитовое OR; в условии — логическое OR без short-circuitНет — оба операнда вычисляются
||Логическое ORДа
& / &&Аналогично для AND&& с short-circuit
if (a() | b()) { } // вызовутся оба метода
if (a() || b()) { } // b() только если a() == false

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с if (a() | b()) { } // вызовутся оба метода и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения контролируется условиями: при разных состояниях кода выбирается соответствующая ветка и результат.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Словесные формы — and, or, not — то же, что &&, ||, !.


Связанные материалы