* Методы классов по умолчанию публичные.
* Поля классов по умолчанию приватные.
* Поля одного типа можно писать через запятую
* Groovy по-умолчанию импортирует основные(наиболее часто используемые) Java пакеты JDK, по этому импортировать нам приходится не часто.
* самовыполняемый скрипт
Например hello.groovy файл:
* чтобы Groovy не генерировал для нас гетеры и сетеры нам нужно указать область видимости явно для поля
* классы пакета groovy.transform - такой себе lombook от Groovy: @EqualsAndHashCode, @Immutable, @ToString и другие.
* Элвис-оператор. Возвращает обьект до, если он не налл, и обьект после, если первый null
- в Groovy число с плавающей точкой по-умолчанию BigDecimal. Чем это хорошо? Вот пример:
- деление интов. В Java Integer/Integer=Integer. Но в Groovy Integer/Integer=BigDecimal. Это чтобы 1/2 не равнялось 0.
Но можно сделать как и Java
Операторы живут org.codehaus.groovy.runtime.DefaultGroovyMethods
- Чтобы вырубить - сингквоут 'Value: ${value}', 'two: $(1+1)'
- Мультилайн по тому же принципу:
/a\b/ - если внутри только один слеш
$/C:/groovy/path/to/$ - ну и если много
match operator (==~) - отвечает булином, если происходит строгое соответствие указанной регулярке
pattern operator (~string) - создает java.util.regex.Pattern
Closures may have 1...N arguments, which may be statically typed or untyped. The first parameter is available via an implicit untyped argument named it if no explicit arguments are named. If the caller does not specify any arguments, the first parameter (and, by extension, it) will be null.
В замыканиях кроме ключевого слова this, можно еще использовать два поля объекта класса Closure:
this corresponds to the enclosing class where the closure is defined
owner corresponds to the enclosing object where the closure is defined, which may be either a class or a closure
delegate corresponds to a third party object where methods calls or properties are resolved whenever the receiver of the message is not defined
Делегирование для того, чтобы использовать в замыкании метод, который можно подменить контекстом. Для этого в поле delegate присваивается контекст. Но этого не достаточно, если с таким же именем существует метод в собственника замыкания(объект в котором замыкание объявлено), для этого нужно еще поменять и стратегию делегирования.
curry
rcurry
ncurry
- объекты, которые не null
- числовые значения, которые не 0
- строки, которые не пустые
- списки и мапы, которые не пустые
- если метчеру патерна подошел параметр.
* Поля классов по умолчанию приватные.
* Поля одного типа можно писать через запятую
* Groovy по-умолчанию импортирует основные(наиболее часто используемые) Java пакеты JDK, по этому импортировать нам приходится не часто.
* самовыполняемый скрипт
Например hello.groovy файл:
#!/usr/bin/env groovy println "Hello!"никакой магии, просто env это не просто посмотреть переменные среды а
$ man env
ENV(1) BSD General Commands Manual ENV(1)
NAME
env -- set environment and execute command, or print environment
...
* чтобы обойти гетер в бине, а достучаться напрямую к полю нужно применять оператор .@ * чтобы Groovy не генерировал для нас гетеры и сетеры нам нужно указать область видимости явно для поля
bean.@field* мы не можем назвать файл также, как назвали внутри класс, если кроме декларации класса там будут еще и строки скрипта - причина проста, тогда груви попытается создать класс расширяющий GDK-шный класс скрипт и зафейлится потому что он не может создать два класса с одинаковым именем.
* классы пакета groovy.transform - такой себе lombook от Groovy: @EqualsAndHashCode, @Immutable, @ToString и другие.
* Элвис-оператор. Возвращает обьект до, если он не налл, и обьект после, если первый null
def elvis = obj ?: "Default"* Оператор in в ренджах
def validAges = 18..35
def someAge = 19
assert someAge in validAges* в java 8 простых типов + 8 обверток вокруг них и один спецтип String, и того 17
* Groovy Numbers
- в Java float/float=float в Groovy float/float=Double- в Groovy число с плавающей точкой по-умолчанию BigDecimal. Чем это хорошо? Вот пример:
println 5.0d - 4.1d println 5.0 - 4.1
0.900000000000004 0.9Поэтому мы не паримся по поводу этого недочета с Double, а тупо не сталкиваемся с такой проблемой.
- деление интов. В Java Integer/Integer=Integer. Но в Groovy Integer/Integer=BigDecimal. Это чтобы 1/2 не равнялось 0.
Но можно сделать как и Java
println 1.intdiv(2)- другие GDK методы
assert 2 == 2.5.toInteger() //conversion
assert 2 == 2.5 as Integer //enforced coercion
assert 2 == (int) 2.5 // cast
assert '5.50'.isNumber()
assert 5 == '5'.toInteger()
20.times {
println '-'
}
1.upto(10) {num ->
println num
}
10.downto(1) {num ->
println num
}
0.step(1, 0.1) {num ->
println num
}
* перегрузка операторов. В груви есть таблица мапинга операторов языка на имена методов.
То есть если на обьект применяется оператор, то интепретатор поищет нет ли у класса этого обьекта метода с именем, которое мапится к этому оператору. Если есть, то будет вызван этот метод.Операторы живут org.codehaus.groovy.runtime.DefaultGroovyMethods
class Account {
BigDecimal balance = 0
String type
def deposit(BigDecimal sum) {
balance += sum
}
def withdraw(BigDecimal sum) {
balance -= sum
}
BigDecimal plus(Account account) {
balance + account.balance
}
}
Account checking = new Account(type: "Checking")
checking.deposit(100.00)
Account saving = new Account(type: "Saving")
saving.deposit(50.00)
BigDecimal total = checking + saving
println total
* Строки в GDK
- Под капотом с лету интерполяция "Value: ${value}", "two: $(1+1)"- Чтобы вырубить - сингквоут 'Value: ${value}', 'two: $(1+1)'
- Мультилайн по тому же принципу:
"""
Value: ${value}"
"two: $(1+1)"
"""
'''
Value: ${value}"
"two: $(1+1)"
'''
- Dollar slashy - спецвозможность для отказа от екранирования/a\b/ - если внутри только один слеш
$/C:/groovy/path/to/$ - ну и если много
* GDK RegExps
find operator (=~) - создает java.util.regex.Matchermatch operator (==~) - отвечает булином, если происходит строгое соответствие указанной регулярке
pattern operator (~string) - создает java.util.regex.Pattern
* Collections
Ranges
1..10 - groovy.lang.IntRange. Включительный диапазон ( 1 и 10 в нем)
1..<10 -="" 9="" div="">10>
[1,2,3,4,5,6] as LinkedList - java.util. LinkedList
[1,2,3].push(4) == [1,2,3,4]
[1,2,3].putAt(1, 4) == [1,4,2,3]
([1,2,3][0] = 4) == [4,2,3]
-----------
def nums = [1,2,3]
def extended = nums + 4
extended == [1,2,3,4]
nums == [1,2,3]
----------
def nums = [1,2,3]
nums << 4
nums == [1,2,3,4]
----------
def nums = [1,2,2,3,2]
def cutted = nums - 2
cutted == [1,3]
nums == [1,2,2,3,2]
----------
[1,2,3].pop() == [1,2]
[1,2,3].removeAt(0) == [2,3]
--------------
[1,2,3,4,5,6].getAt(0..3) == [1,2,3,4]
assert [1,2,3,4,5] == [1,[2,3],[[4]],[],5].flatten()
Lists
def nums = [1,2,3,4,5,6] - java.util.ArrayList[1,2,3,4,5,6] as LinkedList - java.util. LinkedList
[1,2,3].push(4) == [1,2,3,4]
[1,2,3].putAt(1, 4) == [1,4,2,3]
([1,2,3][0] = 4) == [4,2,3]
-----------
def nums = [1,2,3]
def extended = nums + 4
extended == [1,2,3,4]
nums == [1,2,3]
----------
def nums = [1,2,3]
nums << 4
nums == [1,2,3,4]
----------
def nums = [1,2,2,3,2]
def cutted = nums - 2
cutted == [1,3]
nums == [1,2,2,3,2]
----------
[1,2,3].pop() == [1,2]
[1,2,3].removeAt(0) == [2,3]
--------------
[1,2,3,4,5,6].getAt(0..3) == [1,2,3,4]
assert [1,2,3,4,5] == [1,[2,3],[[4]],[],5].flatten()
[1,2,3,4,4,5].unique() == [1,2,3,4,5]
--------------
[1,2,3,4,5] as Set - java.util.LinkedHashSet
[2,4,3,5,1] as SortedSet - java.util.TreeSet
Maps
def map = [:] - java.unit.LinkedHashMap
def creature = [weight: 200, mammal: true, predator: false, name: "pig"]
def complFieldNamesMap = ['Some spaced name': "value"]
def keyName = 'Some spaced name'
def complFieldNamesMap2 = [(keyName): "value"]
for( key in map.keySet() ) {
println "$key:${map[key]}"
}
* Closures
Где и для чего используются?
- Iterators
- Callbacks
- Higher-order functions
- Specialized Control Structure
- Builders
- Resource allocation
- Threads
- DSLs
- Fluent Interfaces
Если метод принимает последним аргументом замыкание, то мы можем его размещать не в скобках аргументов, а вне скобок:)
def timesTen(num, closure) {
closure(num * 10)
}
timesTen(10, {println it})
//but we can write as
timesTen(10) {println it}
//or more habitual form
timesTen(10) {
println it
}
Можно заметить "ключевое слово" itClosures may have 1...N arguments, which may be statically typed or untyped. The first parameter is available via an implicit untyped argument named it if no explicit arguments are named. If the caller does not specify any arguments, the first parameter (and, by extension, it) will be null.
{ item++ } 1
{ -> item++ } 2
{ println it } 3
{ it -> println it } 4
{ name -> println name } 5
{ String x, int y -> 6
println "hey ${x} the value is ${y}"
}
{ reader -> 7
def line = reader.readLine()
line.trim()
}
| 1 | A closure referencing a variable named item |
| 2 | It is possible to explicitly separate closure parameters from code by adding an arrow (->) |
| 3 | A closure using an implicit parameter (it) |
| 4 | An alternative version where it is an explicit parameter |
| 5 | In that case it is often better to use an explicit name for the parameter |
| 6 | A closure accepting two typed parameters |
| 7 | A closure can contain multiple statements |
В замыканиях кроме ключевого слова this, можно еще использовать два поля объекта класса Closure:
this corresponds to the enclosing class where the closure is defined
owner corresponds to the enclosing object where the closure is defined, which may be either a class or a closure
delegate corresponds to a third party object where methods calls or properties are resolved whenever the receiver of the message is not defined
Делегирование для того, чтобы использовать в замыкании метод, который можно подменить контекстом. Для этого в поле delegate присваивается контекст. Но этого не достаточно, если с таким же именем существует метод в собственника замыкания(объект в котором замыкание объявлено), для этого нужно еще поменять и стратегию делегирования.
def writer = {
append 'Dan'
append ' lives in Cleveland'
}
def append(String s) {//(1)
println "append() called with argument of $s"
}
StringBuffer sb = new StringBuffer()
writer.resolveStrategy = Closure.DELEGATE_FIRST//(2)
writer.delegate = sb//(3)
writer()//если не поменять стратегию по умолчанию OWNER_FIRST на указанную, то будет вызвана функция скрипта(вернее метод класса, который по умолчанию оборачивает скрипт груви и являет скрипт обьектом в jvm)
Кари в Groovy
Прелесть его в том, что можем мы предзаполнить не только последние параметры, но и первые, и даже средние по индексу, для этого есть три метода Closurecurry
rcurry
ncurry
def log = { String type, Date createdOn, String msg ->
println "$createdOn [$type] - $msg"
}
log("DEBUG",new Date(),"This is my first debug statement...")
def debugLog = log.curry("DEBUG")
debugLog(new Date(), "This is another debug statement...")
debugLog(new Date(), "This is one more...")
def todayDebugLog = log.curry("DEBUG",new Date())
todayDebugLog("This is today's debug msg")
// right curry
def crazyPersonLog = log.rcurry("Why am I logging this way")
crazyPersonLog("ERROR",new Date())
// index based currying
def typeMsgLog = log.ncurry(1,new Date())
typeMsgLog("ERROR","This is using ncurry...")
def errorLog = typeMsgLog.ncurry(0, "ERRORY")
errorLog("My nice try")
* Правда Groovy
В отличии от Java Groovy считает истиной и объекты, которые подходят следующим условиям:- объекты, которые не null
- числовые значения, которые не 0
- строки, которые не пустые
- списки и мапы, которые не пустые
- если метчеру патерна подошел параметр.
* Супер свитч в Groovy
В кейси подходят и классы, и списки, и ренджы и вообще все что ожидает фантазия(практически)
Ну и Groovy помогает достичь такого намного быстрее:
* Traits
Главное их отличие от default java 8 interfaces это возможность распространять и состояния, не не только функционал.* GroovyBeans
JavaBean - это стандарт, который говорит, чтобы обьект считался бином, он должен
1) Все поля свои тержать приватными.
2) Иметь коструктор без аргументом.
3) Иметь гетеры и сетеры для полей.
4) Реализовывать интерфейс Serializable(он пустой - без декларации каких-либо методов, JVM просто понимает что такой объект нужно если что засерилизировать и с указанного потока попытаться десерилизировать)
@groovy.transform.ToString
class Employee implements Serializable {
String first,last,email
}
И как говорится готово!
Комментариев нет:
Отправить комментарий