Введение в Groovy язык
1. обзор
Groovy is a dynamic, scripting language for the JVM. Он компилируется в байт-код и легко сочетается с Java-кодом и библиотеками.
В этой статье мы рассмотрим некоторые из основных функцийGroovy, включая базовый синтаксис, управляющие структуры и коллекции.
Затем мы рассмотрим некоторые из основных функций, которые делают его привлекательным языком, включая нулевую безопасность, неявную правду, операторы и строки.
2. Среда
3. Основные характеристики
В Groovy есть много полезных функций. Теперь давайте посмотрим на основные строительные блоки языка и на то, чем он отличается от Java.
Теперь давайте посмотрим на основные строительные блоки языка и на то, чем он отличается от Java.
3.1. Динамический набор текста
Одна из наиболее важных особенностей Groovy - поддержка динамической типизации.
Определения типов являются необязательными, а фактические типы определяются во время выполнения. Давайте посмотрим на эти два класса:
class Duck {
String getName() {
'Duck'
}
}
class Cat {
String getName() {
'Cat'
}
}
Эти два класса определяют один и тот же методgetName, но он не определяется явно в контракте.
Теперь представьте, что у нас есть список объектов, содержащих уток и кошек, у которых есть методgetName. С Groovy мы можем сделать следующее:
Duck duck = new Duck()
Cat cat = new Cat()
def list = [duck, cat]
list.each { obj ->
println obj.getName()
}
Код скомпилируется, и результат кода выше будет:
Duck
Cat
3.2. Неявное истинное преобразование
Как и в JavaScript, Groovy при необходимости оценивает каждый объект как логическое значение, например, при использовании внутри оператораif или при отрицании значения:
if("hello") {...}
if(15) {...}
if(someObject) {...}
Есть несколько простых правил, чтобы помнить об этом преобразовании:
-
Непустые массивыCollections,, сопоставления оцениваются вtrue
-
Matcher с хотя бы одним совпадением оценивается какtrue
-
Iterators иEnumerations с другими элементами приводятся кtrue
-
НепустыеStrings,GStrings иCharSequences приводятся кtrue
-
Ненулевые числа оцениваются какtrue
-
Ненулевые ссылки на объекты приводятся кtrue
Если мы хотим настроить неявное правдивое преобразование, мы можем определить наш методasBoolean().
3.3. импорт
Некоторые пакеты импортируются по умолчанию, и нам не нужно импортировать их явно:
import java.lang.*
import java.util.*
import java.io.*
import java.net.*
import groovy.lang.*
import groovy.util.*
import java.math.BigInteger
import java.math.BigDecimal
4. Преобразования AST
Преобразования AST (Abstract Syntax Tree) позволяют нам подключиться к процессу компиляции Groovy и настроить его в соответствии с нашими потребностями. Это делается во время компиляции, поэтому при запуске приложения не снижается производительность. Мы можем создавать наши преобразования AST, но мы также можем использовать встроенные.
Мы можем создавать наши преобразования, или мы можем извлечь выгоду из встроенных.
Давайте взглянем на некоторые аннотации, которые стоит знать.
4.1. АннотацияTypeChecked
Эта аннотация используется для принудительного выполнения компилятором строгой проверки типов аннотированных фрагментов кода. Механизм проверки типов является расширяемым, поэтому мы можем даже обеспечить более строгую проверку типов, чем доступно в Java, когда это необходимо.
Давайте посмотрим на пример ниже:
class Universe {
@TypeChecked
int answer() { "forty two" }
}
Если мы попытаемся скомпилировать этот код, мы увидим следующую ошибку:
[Static type checking] - Cannot return value of type java.lang.String on method returning type int
Аннотация@TypeChecked может применяться к классам и методам.
4.2. АннотацияCompileStatic
Эта аннотация позволяет компилятору выполнять проверки во время компиляции, как это делается с кодом Java. После этого компилятор выполняет статическую компиляцию, минуя протокол метаобъекта Groovy.
Когда класс аннотирован, все методы, свойства, файлы, внутренние классы и т. Д. аннотированного класса будет проверен на тип. Когда метод аннотирован, статическая компиляция применяется только к тем элементам (замыканиям и анонимным внутренним классам), которые заключены в этот метод.
5. свойства
В Groovy мы можем создавать POGO (простые старые объекты Groovy), которые работают так же, как POJO в Java, хотя они более компактны, потому чтоgetters and setters are automatically generated for public properties во время компиляции. Важно помнить, что они будут созданы, только если они еще не определены.
Это дает нам гибкость определения атрибутов как открытых полей, сохраняя при этом возможность переопределять поведение при установке или получении значений.
Рассмотрим этот объект:
class Person {
String name
String lastName
}
Поскольку область действия по умолчанию для классов, полей и методов -public –, это открытый класс, и два поля являются общедоступными.
Компилятор преобразует их в частные поля и добавит методыgetName(),setName(),getLastName() иsetLasfName(). Если мы определимsetter иgetter для определенного поля, компилятор не создаст общедоступный метод.
5.1. Обозначения быстрого доступа
Groovy предлагает сокращенную запись для получения и установки свойств. Вместо Java-способа вызова методов получения и установки мы можем использовать полевую нотацию доступа:
resourceGroup.getResourcePrototype().getName() == SERVER_TYPE_NAME
resourceGroup.resourcePrototype.name == SERVER_TYPE_NAME
resourcePrototype.setName("something")
resourcePrototype.name = "something"
6. операторы
Теперь давайте посмотрим на новые операторы, добавленные к операторам, известным из простой Java.
6.1. Нулево-безопасное разыменование
Самым популярным из них является нулевой безопасный оператор разыменования“?”, который позволяет нам избежатьNullPointerException при вызове метода или доступе к свойству объектаnull. Это особенно полезно в связанных вызовах, когда значениеnull может встречаться в некоторой точке цепочки.
Например, мы можем смело звонить:
String name = person?.organization?.parent?.name
В приведенном выше примере, еслиperson,person.organization илиorganization.parent равныnull, то возвращаетсяnull.
6.2. Элвис Оператор
Оператор Элвиса“?: ”позволяет нам сокращать троичные выражения. Эти два эквивалентны:
String name = person.name ?: defaultName
and
String name = person.name ? person.name : defaultName
Оба они присваивают значениеperson.name переменной name, если она равнаGroovy true (в данном случае неnull и имеет длинуnon-zero).
6.3. Оператор космического корабля
Оператор космического корабля“<⇒” - это оператор отношения, который работает какcompareTo() в Java, который сравнивает два объекта и возвращает -1, 0 или +1 в зависимости от значений обоих аргументов.
Если левый аргумент больше правого, оператор возвращает 1. Если левый аргумент меньше правого, оператор возвращает -1. Если аргументы равны, возвращается 0.
Самым большим преимуществом использования операторов сравнения является плавная обработкаnulls, так чтоx <⇒ y никогда не выдастNullPointerException:
println 5 <=> null
Приведенный выше пример напечатает 1 в результате.
7. Струны
Есть несколько способов выражения строковых литералов. Подход, используемый в Java (строки в двойных кавычках), поддерживается, но также допускается использование одинарных кавычек, когда это предпочтительно.
Многострочные строки, иногда называемые heredocs на других языках, также поддерживаются с использованием тройных кавычек (одинарных или двойных).
Многострочные строки, иногда называемые heredocs на других языках, также поддерживаются с использованием тройных кавычек (одинарных или двойных).
Строки, определенные в двойных кавычках, поддерживают интерполяцию с использованием синтаксиса$\{}:
def name = "Bill Gates"
def greeting = "Hello, ${name}"
Фактически, любое выражение можно поместить внутри$\{}:
def name = "Bill Gates"
def greeting = "Hello, ${name.toUpperCase()}"
Строка с двойными кавычками называется GString, если она содержит выражение$\{}, в противном случае это простой объектString.
Приведенный ниже код будет работать без сбоев теста:
def a = "hello"
assert a.class.name == 'java.lang.String'
def b = 'hello'
assert b.class.name == 'java.lang.String'
def c = "${b}"
assert c.class.name == 'org.codehaus.groovy.runtime.GStringImpl'
8. Коллекции и Карты
Давайте посмотрим, как обрабатываются некоторые базовые структуры данных.
8.1. Listsс
Вот код для добавления нескольких элементов в новый экземплярArrayList в Java:
List list = new ArrayList<>();
list.add("Hello");
list.add("World");
И вот та же операция в Groovy:
List list = ['Hello', 'World']
Списки по умолчанию имеют типjava.util.ArrayList и также могут быть объявлены явно путем вызова соответствующего конструктора.
ДляSet не существует отдельного синтаксиса, но мы можем использовать для этого типcoercion. Либо использовать:
Set greeting = ['Hello', 'World']
or:
def greeting = ['Hello', 'World'] as Set
8.2. Mapс
Синтаксис дляMap аналогичен, хотя и немного более подробен, потому что нам нужно указать ключи и значения, разделенные двоеточиями:
def key = 'Key3'
def aMap = [
'Key1': 'Value 1',
Key2: 'Value 2',
(key): 'Another value'
]
После этой инициализации мы получим новыйLinkedHashMap с записями:Key1 → Value1, Key2 → Value 2, Key3 → Another Value.
Мы можем получить доступ к записям на карте разными способами:
println aMap['Key1']
println aMap[key]
println aMap.Key1
9. Управляющие структуры
9.1. Условия:if-else
Groovy, как и ожидалось, поддерживает условный синтаксисif/else:
if (...) {
// ...
} else if (...) {
// ...
} else {
// ...
}
9.2. Условия:switch-case
Операторswitch обратно совместим с кодом Java, поэтому мы можем избежать случаев, когда один и тот же код используется для нескольких совпадений.
Наиболее важным отличием является то, чтоswitch может выполнять сопоставление с несколькими разными типами значений:
def x = 1.23
def result = ""
switch ( x ) {
case "foo":
result = "found foo"
break
case "bar":
result += "bar"
break
case [4, 5, 6, 'inList']:
result = "list"
break
case 12..30:
result = "range"
break
case Number:
result = "number"
break
case ~/fo*/:
result = "foo regex"
break
case { it < 0 }: // or { x < 0 }
result = "negative"
break
default:
result = "default"
}
println(result)
В приведенном выше примере будет напечатаноnumber.
9.3. Циклы:while
Groovy поддерживает обычные циклыwhile, как это делает Java:
def x = 0
def y = 5
while ( y-- > 0 ) {
x++
}
9.4. Циклы:for
Groovy принимает эту простоту и настоятельно рекомендует цикламfor следовать этой структуре:
for (variable in iterable) { body }
Циклfor повторяется поiterable. Часто используемыми итерациями являются диапазоны, коллекции, карты, массивы, итераторы и перечисления. Фактически, любой объект может быть повторяемым.
Брекеты вокруг тела являются необязательными, если они состоят только из одного утверждения. Ниже приведены примеры перебораrange,list,array,map иstrings:
def x = 0
for ( i in 0..9 ) {
x += i
}
x = 0
for ( i in [0, 1, 2, 3, 4] ) {
x += i
}
def array = (0..4).toArray()
x = 0
for ( i in array ) {
x += i
}
def map = ['abc':1, 'def':2, 'xyz':3]
x = 0
for ( e in map ) {
x += e.value
}
x = 0
for ( v in map.values() ) {
x += v
}
def text = "abc"
def list = []
for (c in text) {
list.add(c)
}
Итерация объекта делает шлюп Groovyfor-сложной структурой управления. Это действительный аналог использования методов, которые перебирают объект с замыканиями, например, используя методCollection’s each.
Основное отличие состоит в том, что тело циклаfor не является закрытием, это означает, что это тело является блоком:
for (x in 0..9) { println x }
тогда как это тело закрыто:
(0..9).each { println it }
Несмотря на то, что они похожи, они очень разные по конструкции.
Закрытие является самостоятельным объектом и имеет разные особенности. Его можно построить в другом месте и передать методуeach. Однако тело шлюпаfor-создается непосредственно какbytecode в точке его появления. Не применяются специальные правила определения объема.
10. Обработка исключений
Большая разница в том, что проверенные исключения не применяются.
Для обработки общих исключений мы можем поместить код, потенциально вызывающий исключение, в блокtry/catch:
try {
someActionThatWillThrowAnException()
} catch (e)
// log the error message, and/or handle in some way
}
Не объявляя тип исключения, которое мы ловим, любое исключение будет поймано здесь.
11. Затворы
Проще говоря, замыкание - это анонимный блок исполняемого кода, который может быть передан в переменные и имеет доступ к данным в контексте, где он был определен.
Они также похожи на анонимные внутренние классы, хотя они не реализуют интерфейс или не расширяют базовый класс. Они похожи на лямбды в Java.
Интересно, что Groovy может в полной мере использовать преимущества JDK, которые были введены для поддержки лямбда-сообщений, особенно потокового API. Мы всегда можем использовать замыкания там, где ожидаются лямбда-выражения.
Давайте рассмотрим пример ниже:
def helloWorld = {
println "Hello World"
}
ПеременнаяhelloWorld теперь содержит ссылку на закрытие, и мы можем выполнить ее, вызвав ее методcall:
helloWorld.call()
Groovy позволяет нам использовать более естественный синтаксис вызова методов - он вызывает для нас методcall:
helloWorld()
11.1. параметры
Как и методы, у замыканий могут быть параметры. Есть три варианта.
В последнем примере, поскольку нет ничего declpersistence_startared, есть только один параметр с именем по умолчаниюit. Модифицированное закрытие, которое печатает то, что отправлено, будет:
def printTheParam = { println it }
Мы могли бы назвать это так:
printTheParam('hello')
printTheParam 'hello'
Мы также можем ожидать параметры в замыканиях и передавать их при вызове:
def power = { int x, int y ->
return Math.pow(x, y)
}
println power(2, 3)
Определение типа параметров совпадает с определением переменных. Если мы определяем тип, мы можем использовать только этот тип, но также можем и передавать все, что захотим:
def say = { what ->
println what
}
say "Hello World"
11.2. Дополнительный возврат
Последний оператор замыкания может быть возвращен неявно без необходимости написания оператора возврата. Это может быть использовано для уменьшения кода шаблона до минимума. Таким образом, замыкание, которое вычисляет квадрат числа, может быть сокращено следующим образом:
def square = { it * it }
println square(4)
Это закрытие использует неявный параметрit и необязательный оператор return.
12. Заключение
В этой статье было дано краткое введение в язык Groovy и его основные функции. Мы начали с введения простых понятий, таких как базовый синтаксис, условные операторы и операторы. Мы также продемонстрировали некоторые более продвинутые функции, такие как операторы и замыкания.
Если вы хотите получить дополнительную информацию о языке и его семантике, вы можете перейти непосредственно кofficial site.