Groovy의 숨겨진 기능?


78

이 스레드에서 Groovy가 잊혀진 것 같아서 Groovy에 대해 동일한 질문을 할 것입니다.

  • Groovy 코어에 대한 답변을 제한하십시오.
  • 답변 당 하나의 기능
  • 문서에 대한 링크뿐만 아니라 기능의 예와 간단한 설명을 제공합니다.
  • 첫 번째 줄로 굵은 제목을 사용하여 지형지 물에 레이블 지정

또한보십시오:

  1. Python의 숨겨진 기능
  2. Ruby의 숨겨진 기능
  3. Perl의 숨겨진 기능
  4. 자바의 숨겨진 기능

답변:


56

확산 점 연산자 사용

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

이것은의 바로 가기입니다 animals.collect { it.size() }.


세 번째 줄은 무엇을 의미합니까?
ripper234

7
컨텍스트에서 이는 각 배열 요소에 대해 size 메서드를 호출하고 결과 배열을 반환하는 것을 의미합니다. 실제로 꽤 멋진 :-)
Michael Rutherfurd

39

방법은이를 끌 수 있습니다 :

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

이것으로

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

3
그것은 나에게 객체 파스칼에 대한 오래된 기억을 가져다줍니다 :-)
fortran

1
이것이 Groovy라는 점을 감안할 때 myObj1.value = 10setter 메서드를 호출 할 필요가 없기 때문에 (등)과 후자 사이에 더 일반적인 비교 가되지 않을까요?
필립

37

해시를 의사 객체로 사용.

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

덕 타이핑과 결합하면이 접근 방식으로 먼 길을 갈 수 있습니다. "as"연산자를 쓸 필요도 없습니다.


2
Groovy의 새로운 기능-정말 좋습니다.
Steve B.

37

엘비스 에 대해 아는 사람 있나요?

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's non-null)

1
이것은 C #의 null 통합 연산자 (??)와 동일합니까?
Alex Baranosky

C # op를 찾아야했지만 그래도 그렇게 보일 것입니다.
billjamesdev 2010 년

정확히는 아니지만 단축 된 삼항 연산자입니다. 나는 그것에 작성자을했다 : colinharrington.net/blog/2008/10/groovy-elvis-operator 또한 :-)이 전체 표현 할 수
콜린 해링턴을

답변에 게시 된 코드는 키워드 "default"가 변수로 사용되기 때문에 컴파일되지 않습니다. 대신 "d"를 사용하여 코드를 컴파일하십시오.
Vorg van Geir 2011-08-15

2
OP가 제안한 규칙을 유지하면서 중요한 이유는 전혀 없습니다. 그 당시 나는 내 행동이 가져올 상쾌한 효과를 고려하지 않았습니다.
gotomanners

35

객체에 어떤 메소드가 있는지 알아내는 것은 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"]

1
이것은 처음에는 어리석은 것 같습니다. 그러나 그것은 매우 유용합니다. 파이썬에는 dir 내장 함수가 있습니다. dir ( "foo")는 문자열에 대한 모든 메소드를 제공합니다.
santiagobasulto

28

누락 된 정적 메서드를 가로 채려면 다음을 사용하십시오.

 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"

-


Groovy를 처음 접했으며 이것을 파싱하는 데 약간의 어려움이 있습니다.
ripper234

3
Object Foo에는 B라는 정적 메서드가 정의되어 있지 않습니다. 그러나 "$ static_methodMissing (String, Object)"라는 메서드를 추가하고 원하는 것을 구현하여 즉석에서 구현할 수 있습니다. 이 매직 메서드는 정적 메서드가 호출되고 개체에 해당 정적 메서드가 정의되어 있지 않을 때마다 호출됩니다.
Jen S.

24

구조화

Groovy에서는 다른 이름으로 불릴 수 있습니다. 클로저에서 구조화라고합니다. 얼마나 편리 할 수 ​​있는지 결코 믿지 못할 것입니다.

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

Groovy 에서는 다중 할당 이라고 합니다 . Wikipedia는 이것을 병렬 할당 이라고 부릅니다 .
Frank Kusters

Clojure의 Destructuring은 다중 할당보다 훨씬 강력합니다. clojure.org/…
Jason

21

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

( 빌더 지원이 작동하는 List대신 빈 목록의 기본값 인 POJO의 특성을 제공해야합니다 null.)


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

아, 여러 줄 문자열의 아름다움. 모든 언어는이를 채택해야합니다.
ripper234

2
""를 확장하여 단일 행 문자열뿐만 아니라 여러 행 문자열을 허용 할 수있을 때 여러 행 문자열에 구분 기호로 "" "이 필요한 이유를 알 수 없습니다.
Vorg van Geir 2011-08-15

2
"" "를 사용하는 @VorgvanGeir는" "를 이스케이프 할 필요가 없음을 의미합니다.
undefined

1
@Brian True이지만 "" "a \ bc"de "f \ g" ""는 \ 또는 \ g를 이스케이프해야하기 때문에 컴파일되지 않으며 \ b는 이스케이프하지 않는 한 백 스페이스처럼 작동합니다. ? 당신은 여전히 문자열 내부의 모든 다른 특별한 순서 탈출해야 할 때 "탈출 할 필요가 없습니다에 지점 무엇인가
Vorg 반 이르

우리 중 일부는 "foo \ tbar"를 쓸 수 있기를 원하기 때문입니다. 그러나 그루비도 있습니다에 println // ( "드"F \ g / BC / A \) - "드"F \ g BC>은 \
다크 스타 (Darkstar)

15

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"]

15

Java와 달리 Groovy에서는 기본 유형뿐만 아니라 모든 것이 switch 문에 사용될 수 있습니다 . 일반적인 eventPerformed 메서드에서

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

15

우주선 연산자 사용

모든 종류의 사용자 지정 정렬 시나리오에 유용한 우주선 연산자를 좋아합니다 . 여기에 몇 가지 사용 예가 있습니다 . 특히 도움이되는 한 가지 상황은 여러 필드를 사용하여 개체의 즉석에서 비교기를 만드는 것입니다. 예 :

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 ]

14

클로저는 리소스 관리의 모든 오래된 트라이-파이널 게임을 사라지게 할 수 있습니다. 파일 스트림은 블록 끝에서 자동으로 닫힙니다.

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

1
또한 클로저 내에서 Exception이 발생하는 경우 파일 핸들이 제대로 닫히므로 try-with-resources보다 더 좋습니다.
DarkStar

13

다음 groovy.transform과 같은 GDK 패키지 내부의 변환에서 제공하는 기능 :

  • @Immutable: @Immutable 주석은 정의 된 속성으로 불변 클래스를 만들 때 일반적으로 작성되는 필요한 getter, 생성자, equals, hashCode 및 기타 도우미 메서드를 추가하는 AST 변환을 실행하도록 컴파일러에 지시합니다.
  • @CompileStatic: 이렇게하면 Groovy 컴파일러가 Java 스타일의 컴파일 시간 검사를 사용한 다음 정적 컴파일을 수행하여 Groovy 메타 개체 프로토콜을 우회 할 수 있습니다.
  • @Canonical: @Canonical 어노테이션은 위치 생성자, 같음, hashCode 및 예쁜 인쇄 toString을 클래스에 추가하는 AST 변환을 실행하도록 컴파일러에 지시합니다.

기타 :

  • @Slf4j이 로컬 변환은 LogBack 로깅을 사용하여 프로그램에 로깅 기능을 추가합니다. log라는 이름의 바인딩되지 않은 변수에 대한 모든 메서드 호출은 로거 호출에 매핑됩니다.
  • Groovy의 XML Slurper : XML을 쉽게 파싱합니다. 킬러 기능!

12

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']

이것이 as Object []첫 번째 줄에 필요합니까?
Kamil

12

클로저 기반 인터페이스 구현

다음과 같이 입력 된 참조가있는 경우 :

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

8

null목록에서 값 제거

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

7

내가 조금 늦었다는 것을 알고 있지만 여기에 몇 가지 멋진 기능이 누락 된 것 같습니다.

컬렉션 플러스 / 마이너스 연산자

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']

유니 코드 변수 이름

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

7

@대리자

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

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

def bar = new Bar()

assert "footest" == bar.footest()

6

리터럴의 밑줄

긴 리터럴 숫자를 쓸 때, 예를 들어 수천 개의 단어 그룹과 같이 일부 숫자가 함께 그룹화되는 방식을 파악하기가 더 어렵습니다. 숫자 리터럴에 밑줄을 넣을 수있게함으로써 이러한 그룹을 쉽게 찾을 수 있습니다.

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

5

암시 적 인수를 사용한 인수 재정렬은 또 다른 좋은 방법입니다.

이 코드 :

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 msg"및 "int val"에서 "String"및 "int"를 생략 할 수 있습니다. 명확성을 위해 그대로 두었습니다.


이 경우라면 좋겠지 만 현재 Groovy (1.6)는 개체 생성자에 대해 명명 된 인수 만 지원합니다. 이 구문을 메서드 호출에 사용할 수 있지만 명명 된 인수를 Map으로 패키징 한 다음 foo (Map)을 찾습니다.
Cody Casterline

나는 당신이 내가 다른 것을 암시한다고 생각하는 것에 대해 혼란 스럽습니다.
Robert Fischer

4

매개 변수 및 매개 변수 기본값 값으로 폐쇄의 조합이라고 생각합니다.

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"


4

메서드 매개 변수에서 확산 연산자 사용

이것은 코드를 데이터로 변환 할 때 큰 도움이됩니다.

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('_'))

아니요, 코드를 데이터로 변환하여 일반적으로 정적 인 인수 목록과 동일한 데이터 인 배열을 만듭니다. 그러나 나는 당신의 관점에 달려 있습니다. 기존 정적 코드를 더 많은 dynami! c 코드로 리팩토링하는 관점에서 살펴보고 있습니다.
Luis Muñiz 2013

아마도 "데이터 기반 설계를 사용할 때"일까요?
DarkStar

3

메모 화

Memoization은 값 비싼 함수 호출의 결과를 저장하고 동일한 인수로 함수가 다시 호출 될 때마다 캐시 된 결과를 반환하는 최적화 기술입니다.

무제한 버전이 있는데, 그것은 그것이 볼 수있는 (입력 인수, 반환 값) 쌍을 캐시합니다. LRU 캐시를 사용하여 마지막으로 본 N 개의 입력 인수와 그 결과를 캐시하는 제한된 버전.

방법의 메모 :

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 사용에 대한 광범위한 정보가 있습니다. 나는 단지 하나의 간단한 실용적인 사용을 지적 할 것이다.

상수 초기화를 가능한 마지막 순간으로 연기

때로는 클래스 정의 또는 생성시 초기화 할 수없는 상수 값이 있습니다. 예를 들어 상수 표현식은 다른 상수 또는 다른 클래스의 메서드를 사용할 수 있으며, 클래스 초기화 후 다른 항목 (Spring 등)에 의해 연결됩니다.

이 경우 상수를 getter로 변환하고 @Memoized. 처음 액세스 할 때 한 번만 계산 된 다음 값이 캐시되고 재사용됩니다.

import groovy.transform.Memoized

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

2

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)
}
}

산출:

푸 바 10


2

동적 메서드 호출

이름이있는 문자열을 사용하여 메소드를 호출 할 수 있습니다.

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()'

2

Groovy에서 몇 줄에 JSON 트리를 만드는 방법은 무엇입니까?

1) 자체 참조 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"}}}


2

안전한 내비게이션 연산자

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

1

다중 변수 감속

1) 한 줄에 여러 변수 선언

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

2) 다른 유형 선언 사용.

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

0

강제 연산자

강제 연산자 (as)는 캐스팅의 변형입니다. Coercion은 할당에 호환되지 않고 객체를 한 유형에서 다른 유형으로 변환합니다. 예를 들어 보겠습니다.

Integer x = 123
String s = (String) x
Integer는 String에 할당 할 수 없으므로 런타임에 ClassCastException이 생성 됩니다. 대신 강제 변환을 사용하여 해결할 수 있습니다.

Integer x = 123 String s = x as String
Integer는 String에 할당 할 수 없지만 as를 사용하면 String으로 강제 변환됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.