Скрытые черты Groovy?

Похоже, что Groovy был забыт в этом потоке, поэтому я просто задаю тот же вопрос для Groovy.

  • Попробуйте ограничить ответы на Groovy core
  • Одна функция для каждого ответа
  • Приведите пример и краткое описание функции, а не ссылку на документацию
  • Обозначьте эту функцию, используя полужирный заголовок в качестве первой строки

См. также:

Ответ 1

Использование оператора с расширенными точками

def animals = ['ant', 'buffalo', 'canary', 'dog']
assert animals.size() == 4
assert animals*.size() == [3, 7, 6, 3]

Это ярлык для animals.collect { it.size() }.

Ответ 2

Метод с позволяет это:

 myObj1.setValue(10)
 otherObj.setTitle(myObj1.getName())
 myObj1.setMode(Obj1.MODE_NORMAL)

в этот

 myObj1.with {
    value = 10
    otherObj.title = name
    mode = MODE_NORMAL
 }

Ответ 3

Использование хешей в качестве псевдообъектов.

def x = [foo:1, bar:{-> println "Hello, world!"}]
x.foo
x.bar()

В сочетании с утиным набором текста вы можете пройти долгий путь при таком подходе. Даже не нужно выталкивать оператора "как".

Ответ 4

Кто-нибудь знает о Elvis?

def d = "hello";
def obj = null;

def obj2 = obj ?: d;   // sets obj2 to default
obj = "world"

def obj3 = obj ?: d;  // sets obj3 to obj (since it non-null)

Ответ 5

Узнать, какие методы на объекте так же просто, как запросить metaClass:

"foo".metaClass.methods.name.sort().unique()

Отпечатки:

["charAt", "codePointAt", "codePointBefore", "codePointCount", "compareTo",
 "compareToIgnoreCase", "concat", "contains", "contentEquals", "copyValueOf", 
 "endsWith", "equals", "equalsIgnoreCase", "format", "getBytes", "getChars", 
 "getClass", "hashCode", "indexOf", "intern", "lastIndexOf", "length", "matches", 
 "notify", "notifyAll", "offsetByCodePoints", "regionMatches", "replace", 
 "replaceAll", "replaceFirst", "split", "startsWith", "subSequence", "substring", 
 "toCharArray", "toLowerCase", "toString", "toUpperCase", "trim", "valueOf", "wait"]

Ответ 6

Чтобы перехватить отсутствующие статические методы, используйте следующие

 Foo {
    static A() { println "I'm A"}

     static $static_methodMissing(String name, args) {
        println "Missing static $name"
     }
 }

Foo.A()  //prints "I'm A"
Foo.B()  //prints "Missing static B"

Кен

Ответ 7

деструктурирующие

Его можно назвать чем-то еще в Groovy; он назвал деструктурирование в clojure. Вы никогда не поверите, насколько это удобно.

def list = [1, 'bla', false]
def (num, str, bool) = list
assert num == 1
assert str == 'bla'
assert !bool

Ответ 8

Для тестирования java-кода с помощью groovy, построитель построения объектов потрясающий:

def company = builder.company( name: 'ACME' ) {
   address( id: 'a1', line1: '123 Groovy Rd', zip: 12345, state: 'JV' )
   employee(  name: 'Duke', employeeId: 1 ){
      address( refId: 'a1' )
   }
}

Стандартная функция, но все же очень хорошая.

ObjectGraphBuilder

(Вам нужно указать какие-либо свойства вашего POJO, которые List имеют значение по умолчанию для пустого списка, а не null для поддержки конструктора.)

Ответ 9

println 
"""
Groovy has "multi-line" strings.
Hooray!
"""

Ответ 10

В отличие от Java, в Groovy все может использоваться в операторе switch, а не только в примитивных типах. В типичном случаеPerformed method

switch(event.source) {
   case object1:
        // do something
        break
   case object2:
        // do something
        break
}

Ответ 11

В groovy 1.6 регулярные выражения работают со всеми итераторами закрытия (например, каждый, собирать, вводить и т.д.) и позволяют вам легко работать с группами захвата:

def filePaths = """
/tmp/file.txt
/usr/bin/dummy.txt
"""

assert (filePaths =~ /(.*)\/(.*)/).collect { full, path, file -> 
        "$file -> $path"
    } ==  ["file.txt -> /tmp", "dummy.txt -> /usr/bin"]

Ответ 12

Использование оператора Spaceship

Мне нравится оператор Spaceship, полезный для всех видов пользовательских сценариев сортировки. Вот некоторые примеры использования здесь. Одна из ситуаций, в которой это особенно полезно, заключается в создании компаратора "на лету" объекта с использованием нескольких полей. например.

def list = [
    [ id:0, first: 'Michael', last: 'Smith', age: 23 ],
    [ id:1, first: 'John', last: 'Smith', age: 30 ],
    [ id:2, first: 'Michael', last: 'Smith', age: 15 ],    
    [ id:3, first: 'Michael', last: 'Jones', age: 15 ],   
]

// sort list by last name, then first name, then by descending age
assert (list.sort { a,b -> a.last <=> b.last ?: a.first <=> b.first ?: b.age <=> a.age })*.id == [ 3,1,0,2 ]

Ответ 13

Закрытие может привести к тому, что все старые игры-решения по управлению ресурсами исчезнут. Файловый поток автоматически закрывается в конце блока:

new File("/etc/profile").withReader { r ->
    System.out << r
}

Ответ 14

Функции, предоставляемые преобразованиями внутри пакета GDK groovy.transform, такие как:

  • @Immutable: @Immutable аннотация указывает компилятору выполнить преобразование AST, которое добавляет необходимые геттеры, конструкторы, equals, hashCode и другие вспомогательные методы, которые обычно создаются при создании неизменяемых классов с определенными свойствами.
  • @CompileStatic: это позволит компилятору Groovy использовать проверку времени компиляции в стиле Java, а затем выполнить статическую компиляцию, минуя Groovy meta объектного протокола.
  • @Canonical: @Canonical annotation предписывает компилятору выполнить преобразование AST, которое добавляет позиционные конструкторы, equals, hashCode и довольно печатать toString в ваш класс.

Другие:

  • @Slf4j Это локальное преобразование добавляет возможность ведения журнала для вашей программы, используя LogBack logging. Каждый вызов метода для несвязанной переменной с именем log будет сопоставлен с вызовом регистратора.
  • Groovy XML Slurper: простой анализ XML. Функция Killer!

Ответ 15

Внедрение интерфейса на основе Closure

Если у вас есть типизированная ссылка, например:

MyInterface foo

Вы можете реализовать весь интерфейс, используя:

foo = {Object[] args -> println "This closure will be called by ALL methods"} as MyInterface

В качестве альтернативы, если вы хотите реализовать каждый метод отдельно, вы можете использовать:

foo = [bar: {-> println "bar invoked"}, 
    baz: {param1 -> println "baz invoked with param $param1"}] as MyInterface

Ответ 16

Вы можете преобразовать список в карту с помощью функции toSpreadMap(), удобной в тех случаях, когда порядка в списке достаточно, чтобы определить ключи и связанные с ними значения. См. Пример ниже.

def list = ['key', 'value', 'foo', 'bar'] as Object[]
def map = list.toSpreadMap()

assert 2 == map.size()
assert 'value' == map.key
assert 'bar' == map['foo']

Ответ 17

Удалите null значения из списка

def list = [obj1, obj2, null, obj4, null, obj6]
list -= null
assert list == [obj1, obj2, obj4, obj6]

Ответ 18

@Делегат

class Foo {
    def footest() { return "footest"}   
}

class Bar {
    @Delegate Foo foo = new Foo()     
}

def bar = new Bar()

assert "footest" == bar.footest()

Ответ 19

Я знаю, что немного опаздываю, но я думаю, что здесь есть некоторые интересные функции:

Операторы коллекции плюс/минус

def l = [1, 2, 3] + [4, 5, 6] - [2, 5] - 3 + (7..9)
assert l == [1, 4, 6, 7, 8, 9]

def m = [a: 1, b: 2] + [c: 3] - [a: 1]
assert m == [b: 2, c: 3]

Оператор switch

switch (42) {
  case 0: .. break
  case 1..9: .. break
  case Float: .. break
  case { it % 4 == 0 }: .. break
  case ~/\d+/: .. break
}

Диапазоны и индексирование

assert (1..10).step(2) == [1, 3, 5, 7, 9]
assert (1..10)[1, 4..8] == [2, 5, 6, 7, 8, 9]
assert ('a'..'g')[-4..-2] == ['d', 'e', 'f']

Имена переменных Unicode

def α = 123
def β = 456
def Ω = α * β
assert Ω == 56088

Ответ 20

Подчеркивание в литералах

При написании длинных литеральных номеров, его сложнее на глазу выяснить, как некоторые числа группируются вместе, например, группами тысяч, словами и т.д. Позволяя вам помещать подчеркивание в числовые литералы, его легче определить эти группы:

long creditCardNumber = 1234_5678_9012_3456L
long socialSecurityNumbers = 999_99_9999L
double monetaryAmount = 12_345_132.12
long hexBytes = 0xFF_EC_DE_5E
long hexWords = 0xFFEC_DE5E
long maxLong = 0x7fff_ffff_ffff_ffffL
long alsoMaxLong = 9_223_372_036_854_775_807L
long bytes = 0b11010010_01101001_10010100_10010010

Ответ 21

Переупорядочение аргумента с неявными аргументами является еще одним приятным.

Этот код:

def foo(Map m=[:], String msg, int val, Closure c={}) {
  [...]
}

Создает все эти различные методы:

foo("msg", 2, x:1, y:2)
foo(x:1, y:2, "blah", 2)
foo("blah", x:1, 2, y:2) { [...] }
foo("blah", 2) { [...] }

И еще. Невозможно испортить, поставив именованные и порядковые аргументы в неправильном порядке/позиции.

Конечно, в определении "foo" вы можете оставить "String" и "int" из "String msg" и "int val" - я оставил их только для ясности.

Ответ 22

Я думаю, что это комбинация замыканий как параметр и значения по умолчанию-параметра:

public void buyItems(Collection list, Closure except={it > 0}){
  list.findAll(){except(it)}.each(){print it}
}
buyItems([1,2,3]){it > 2}
buyItems([0,1,2])

Отпечатки: "312"

Ответ 23

Использование оператора спреда в параметрах метода

Это отличная помощь при преобразовании кода в данные:

def exec(operand1,operand2,Closure op) {
    op.call(operand1,operand2)
}

def addition = {a,b->a+b}
def multiplication = {a,b->a*b}

def instructions = [
     [1,2,addition],
     [2,2,multiplication]
]

instructions.each{instr->
    println exec(*instr)
}

Также полезно использовать это:

String locale="en_GB"

//this invokes new Locale('en','GB')
def enGB=new Locale(*locale.split('_'))

Ответ 24

запоминание

Memoization - это метод оптимизации, который заключается в сохранении результатов дорогих вызовов функций и возвращении кэшированного результата всякий раз, когда функция вызывается снова с теми же аргументами.

Существует неограниченная версия, которая будет кэшировать любую пару (входные аргументы, возвращаемое значение), которые она когда-либо увидит; и ограниченную версию, которая будет кэшировать последние N входных аргументов и их результаты, используя кеш LRU.

Запоминание методов:

import groovy.transform.Memoized

@Memoized
Number factorial(Number n) {
    n == 0 ? 1 : factorial(n - 1)
}

@Memoized(maxCacheSize=1000)
Map fooDetails(Foo foo) {
    // call expensive service here
}

Запоминание замыканий:

def factorial = {Number n ->
    n == 0 ? 1 : factorial(n - 1)
}.memoize()

fooDetails = {Foo foo ->
    // call expensive service here
}.memoizeAtMost(1000)

Страница Wikipedia содержит обширную информацию об использовании Memoization in Computer Science. Я просто укажу одно простое практическое применение.

Отложить инициализацию константы до последнего возможного момента

Иногда у вас есть постоянное значение, которое невозможно инициализировать при определении класса или времени создания. Например, константное выражение может использовать другую константу или метод из другого класса, который после инициализации вашего класса будет подключен чем-то другим (Spring или таким).

В этом случае вы можете преобразовать свою константу в getter и украсить ее с помощью @Memoized. Он будет вычисляться только один раз, при первом обращении к нему, а затем значение, кэшированное и повторно используемое:

import groovy.transform.Memoized

@Memoized
def getMY_CONSTANT() {
    // compute the constant value using any external services needed
}

Ответ 25

Groovy может работать как Javascript. У вас могут быть частные вары и функции через закрытие. Вы также можете выполнять функции с закрытием.

class FunctionTests {

def privateAccessWithClosure = {

    def privVar = 'foo'

    def privateFunc = { x -> println "${privVar} ${x}"}

    return {x -> privateFunc(x) } 
}


def addTogether = { x, y ->
    return x + y
}

def curryAdd = { x ->
    return { y-> addTogether(x,y)}
}

public static void main(String[] args) {
    def test = new FunctionTests()

    test.privateAccessWithClosure()('bar')

    def curried = test.curryAdd(5)

    println curried(5)
}
}

выход:

foo bar 10

Ответ 26

Вызов динамического метода

Вы можете вызвать метод, используя строку с ее именем

class Dynamic {
    def one() { println "method one()" }
    def two() { println "method two()" }
}

def callMethod( obj, methodName ) {
    obj."$methodName"()
}

def dyn = new Dynamic()

callMethod( dyn, "one" )               //prints 'method one()'
callMethod( dyn, "two" )               //prints 'method two()'
dyn."one"()                            //prints 'method one()'

Ответ 27

Как построить дерево JSON в нескольких строках в groovy?

1) определите свое дерево с помощью self-referential withDefault закрытия

def tree // declare  first before using a self reference
tree = { ->  [:].withDefault{ tree() } }

2) Создайте собственное дерево JSON

frameworks = tree()
frameworks.grails.language.name = 'groovy'
frameworks.node.language.name = 'js'

def result =  new groovy.json.JsonBuilder(frameworks)

Что дает: {"grails":{"language":{"name":"groovy"}},"node":{"language":{"name":"js"}}}

Ответ 28

Безопасный навигационный оператор

Оператор Safe Navigation используется для исключения исключения NullPointerException. Обычно, когда у вас есть ссылка на объект, вам может потребоваться проверить, что он не имеет значения null перед доступом к методам или свойствам объекта. Чтобы этого избежать, безопасный оператор навигации просто возвращает null вместо того, чтобы выбрасывать исключение, например:

def person = Person.find { it.id == 123 }        // find will return a null instance    
def name = person?.name                          // use of the null-safe operator prevents from a NullPointerException, result is null

Ответ 29

Множественное замедление переменных

1) Объявление нескольких переменных в одной строке

def (a,b,c) = [1,2,3]

2) Использование объявлений различного типа.

def (String a, int b) = ['Groovy', 1]

Ответ 30

Оператор Элвиса

"Оператор Элвиса" является сокращением тернарного оператора. Одним из примеров того, где это удобно, является возврат значения "разумного значения по умолчанию", если выражение разрешает false (как в Groovy правде). Простой пример может выглядеть так:

с тернарным оператором, вам нужно повторить значение, которое вы хотите назначить

displayCity = user.city ? user.city: 'UnKnown City'

с помощью оператора Элвиса, проверенное значение используется, если оно не является ложным

displayCity = user.city ?: 'UnKnown City'